plot a graph real time

Hi,
I have a rotary encoder 1024 ppr hooked up to a arduino 2056 mega board which outputs to a lcd shield, serial monitor and micro sd card.
I would like to take the output and also plot it to a graph real time on a lcd screen.
Right now when I rotate the encoder CW and click the the left button it stores the value on the arduino. I then rotate the encoder CCW and click the right button, storing the value on the arduino. I then click on the down button and the increaseB+=2 value plus the left and right value is printed to the micro sd card and serial monitor. The difference of the left and right value is also printed to the micro sd card, serial monitor and some to the lcd. Is there a way to plot the above info into a realtime graph that would show the increaseB+=2 as the y value and the difference of left and right as the y value. Below is the code for the keypad buttons in use now.

       case btnDOWN:
      if (Flag == 0)
    {
       //Serial.println(increaseB);
result = leftBtn - rightBtn;
    
      lcd.setCursor(0, 1);
      lcd.print("Gap Dif:");
      lcd.setCursor(9, 1);
      lcd.print(result);
      
      if(increaseB < 100)
   {
       increaseB+=2;
   }
   else increaseB = 0;
     Serial.print(increaseB); Serial.print("\t"); Serial.print("Left Contact: "); Serial.print(leftBtn); Serial.print("\t"); Serial.print("Right Contact: "); Serial.print(rightBtn);Serial.print("\t");
     Serial.print("Contact Gap"); Serial.print("\t"); Serial.print(result); Serial.print("\n");
  
    dataString =  String (increaseB) + String("\t")+ String("Left contact..") + String (leftBtn) + String("\t") + String("Right contact..") + String(rightBtn) + String("\t") + String("Contact Gap \t") +  String(result);
        File dataFile = SD.open("d2.txt", FILE_WRITE);//open a file named d2.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening d2.txt");//in that case print an error message
        }

      
 Flag = 1;
    }
      break;
[\code]

This is simply a matter of drawing a pixel using time and variable value as coordinates. Any graphics LCD can do this. I use the Henning Karlsen library, but I believe they are all much the same for this purpose.

Thanks for the reply Nick. Good to know that this isn't too hard too accomplish. Are there examples available that i could at. and would it be possible to plot the graph to the serial monitor?
Bill

I think any graphic library will have an example you can utilise.

You have a number of other options, using the serial monitor is not one of them.

You can send the data direct to older versions of Excel, using the PLX-DAQ macro. This gives you all the graph-drawing facilities of Excel with realtime update.

You can use Live Graph

You can send the data to an Android device via bluetooth and use Bluetooth Graphics Terminal.

Etc., etc.........

Thanks for the info,
I looked into PLX-DAQ macro and don't think it would play well with my operating system (win10) and the stopped supporting it. ):
I also updated my arduino IDE to 1.6.7 which now has serial plotter. It looked interesting but I need to be able to insert the increment value to the x axis everytime I click the up or down key pad. When i press the up button each entry increments by and the x axis advances by 2.5 while clicking the down button would increment by 2. I want a graph that displays the "result" value on the y axis with the increment value on the x axis. I don't believe serial plotter can handle doing that at this moment. But, I do have matlab 2014 installed and have been reading up on some of the tutorials and know this to be possible. Does anyone have experience with graphing encoder output to matlab? and if so...could you help walk me through it with my sketch?

       case btnDOWN:
      if (Flag == 0)
    {
       //Serial.println(increaseB);
result = leftBtn - rightBtn;
    
      lcd.setCursor(0, 1);
      lcd.print("Gap Dif:");
      lcd.setCursor(9, 1);
      lcd.print(result);
      
      if(increaseB < 100)
   {
       increaseB+=2;
   }
   else increaseB = 0;
     Serial.print(increaseB); Serial.print("\t"); Serial.print("Left Contact: "); Serial.print(leftBtn); Serial.print("\t"); Serial.print("Right Contact: "); Serial.print(rightBtn);Serial.print("\t");
     Serial.print("Contact Gap"); Serial.print("\t"); Serial.print(result); Serial.print("\n");
  
    dataString =  String (increaseB) + String("\t")+ String("Left contact..") + String (leftBtn) + String("\t") + String("Right contact..") + String(rightBtn) + String("\t") + String("Contact Gap \t") +  String(result);
        File dataFile = SD.open("d2.txt", FILE_WRITE);//open a file named d2.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening d2.txt");//in that case print an error message
        }

      
 Flag = 1;
    }
      break;

I can't say I understand the requirement as stated in the Original Post - for example how often is a new piece of data produced that needs to go on the graph?

Maybe my EzScrn demo would be of interest.

...R

Hi,
Each time the down button is clicked, a new value is outputted which I want to plot on a graph. The rotary encoder In this project is attached to a safe dial. The left and right buttons represent the left and right position on the dial. When the dial is rotated to the left and stops at a certain position the left button is clicked. that value is then stored on the arduino. Then the dial is rotated right and stopped at a certain position and the right button is clicked, again storing the dial position on the arduino. The result button is then clicked. when this happens the following data is passed to the sd micro card and written to file.
the increment value which represents the number on the safe dial followed by the difference of left and right button subtracted. so the file would look like this.
2 Left contact..30.00 Right contact..9.04 Contact Gap 20.96
4 Left contact..24.10 Right contact..0.58 Contact Gap 23.52
6 Left contact..21.01 Right contact..5.78 Contact Gap 15.23
the increment goes up by 2 which represents the number on the safe dial I am testing.
left contact is the left button and right contact is the right button.
Contact gap is the difference of the two.
I want to graph the increment value on the y axis and the contact gap value on the x axis. I want the values to be entered on the graph each time i click the result so I can visually verify whats happening as I enter the information. in this case the variance of the contact gap.
Hope this helps, and sorry for sounding so confusing
Bill

On my last post I did not notice the link to the ezscrn demo Robin2. I will also look into that.
Thanks

hi,
Just to update, I tried the serial plotter that comes with Arduino IDE 1.6.7. would be awesome if you had control over the x-axis. I started working with "Meguno" which looks like it could do what I want. The problem I have is a compile error I am getting. no matching function for call to 'XYPlot::SendData(int&, float&)' In some sample code I have this function compiles fine so I know the library is okay

#include "MegunoLink.h" // Helpful functions for communicating with MegunoLink Pro. 
 
// Millis value when the data was last sent. 
long LastSent;
 
// Interval (milliseconds) between sending analog data
const unsigned SendInterval = 200; // [ms]
 
// The plot we are sending data to.
XYPlot MyPlot;
 
void setup()
{
  Serial.begin(9600);
 
  LastSent = millis();
 
  MyPlot.SetTitle("My Analog Measurement");
  MyPlot.SetXlabel("Channel 0");
  MyPlot.SetYlabel("Channel 1");
  MyPlot.SetSeriesProperties("ADCValue", Plot::Magenta, Plot::Solid, 2, Plot::Square);
}
 
void loop()
{
  if ((millis() - LastSent) > SendInterval)
  {
    LastSent = millis();
 
    int XDataValue = analogRead(0);
    int YDataValue = analogRead(1);
    MyPlot.SendData("ADCValue", XDataValue, YDataValue);
  }
}

How ever when I try to use the MyPlot.SendData() in my code I get the error. I believe it is because in the sample code the function is located in the void loop() while in my code it is inside the btnUp and btnDown function which is located inside the void loop(). What should I do so that the MyPlot.SendData(increaseB, result); is recognized inside the button function?

This is my code that I am using the MyPlot.SendData()

#include "MegunoLink.h" // Helpful functions for communicating with MegunoLink Pro. 
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;
float rightBtn = 0;
float leftBtn = 0;
float result = 0;
int increaseB = 0;      //add counter that will  increment by 1 or 2
byte Flag = 1;          //add flag to control multiple records for same button press

const int numRows = 2;   //Setup the dfrobot lcd panel
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnDOWN    2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()



{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnDOWN;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add 
}



XYPlot MyPlot;
void setup() {
  

  Serial.begin(9600);
  MyPlot.SetTitle("Manipulator");
  MyPlot.SetXlabel("Dial Number");
  MyPlot.SetYlabel("Contact Gap Difference");

  //Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    //Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  //Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);// encoder wire A
  pinMode(19, INPUT_PULLUP);// encoder wire B

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {

 
  // make a string for assembling the data to log:
  String dataString = "";


  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
       
        rightBtn = (mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
      
        
        Flag = 1;
      }
      break;
/**********************************************************************************/
    case btnLEFT:
      if (Flag == 0)
      {
        
        leftBtn = (mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        
        
        Flag = 1;
      }

      break;

/**********************************************************************************/


    case btnSELECT:
      if (Flag == 0)
      {
       
        lcd.clear();
      
        
        Flag = 1;
      }
      break;
/****************************************************************************************/
      case btnUP:
     if (Flag == 0)
    {
      
result = leftBtn - rightBtn;
    
      lcd.setCursor(0, 1);
      lcd.print("Gap Dif:");
      lcd.setCursor(9, 1);
      lcd.print(result);
      Serial.println(result);
      if(increaseB < 100)
   {
       increaseB+=1;
   }
   else increaseB = 0;
    MyPlot.SendData(increaseB, result);
    dataString =  String (increaseB) + String("\t")+ String("Left contact..") + String (leftBtn) + String("\t") + String("Right contact..") + String(rightBtn) + String("\t") + String("Contact Gap \t") +  String(result);
        File dataFile = SD.open("d2.txt", FILE_WRITE);//open a file named d2.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.
          
         
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening d2.txt");//in that case print an error message
        }

      
 Flag = 1;
   }
     break;


/*************************************************************************************************************/

       case btnDOWN:
      if (Flag == 0)
    {
      
      
result = leftBtn - rightBtn;
    
      lcd.setCursor(0, 1);
      lcd.print("Gap Dif:");
      lcd.setCursor(9, 1);
      lcd.print(result);
      Serial.println(result);
      if(increaseB < 100)
   {
       increaseB+=2;
   }
   else increaseB = 0;
     MyPlot.SendData(increaseB, result);  
  

    dataString =  String (increaseB) + String("\t")+ String("Left contact..") + String (leftBtn) + String("\t") + String("Right contact..") + String(rightBtn) + String("\t") + String("Contact Gap \t") +  String(result);
        File dataFile = SD.open("d2.txt", FILE_WRITE);//open a file named d2.txt.

 
        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening d2.txt");//in that case print an error message
        }

      
 Flag = 1;
    }
      break;
/**************************************************************************************************/
    case btnNONE:
      Flag = 0;
      break;
/*************************************************************************************************/
  }//closes switch

  lcd.setCursor(0, 0);
  lcd.print("Encoder:");
  lcd.setCursor(9, 0);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
  
    lcd.print("0");
  lcd.print(value);
 
}//closes loop

  void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}

Depending on what lcd you have, i have written some graphing functions and are available for download. Links in these YouTube Videos.

DIY oscilloscope but has graphing functions

Hope this helps.

I wonder should this line

#include "MegunoLink.h"

be

#include <MegunoLink.h>

Where have you stored the Meguno library?

...R

Robin2:
I wonder should this line

#include "MegunoLink.h"

be

#include <MegunoLink.h>

Where have you stored the Meguno library?

...R

Hi Robin, Tried your suggestion but no luck. The Meguno library was installed here

Using library MLP-master in folder: C:\Users\enduser\Documents\Arduino\libraries\MLP-master (legacy)

What I don't understand is how the first example I posted works fine, but in my code it doesn't. They both use the same library located above. I would have thought that if it was a library issue neither sketch would compile. I don't know. What is the difference between these two?

#include "MegunoLink.h"
#include <MegunoLink.h>

KrisKasprzak:
Depending on what lcd you have, i have written some graphing functions and are available for download. Links in these YouTube Videos.

https://www.youtube.com/watch?v=YejRbIKe6e0
https://www.youtube.com/watch?v=U5hOU-xxQgk

DIY oscilloscope but has graphing functions
https://www.youtube.com/watch?v=jYaWjMUfkMg

Hope this helps.

Hi Kris,
I had a look at your links. Wow good stuff. I am now shopping around for one of those LCD screens.

williamjcoates:
Hi Robin, Tried your suggestion but no luck. The Meguno library was installed here

Using library MLP-master in folder: C:\Users\enduser\Documents\Arduino\libraries\MLP-master (legacy)

What I don't understand is how the first example I posted works fine, but in my code it doesn't. They both use the same library located above. I would have thought that if it was a library issue neither sketch would compile. I don't know. What is the difference between these two?

#include "MegunoLink.h"
#include <MegunoLink.h>

The version with quotes looks for the .h file in the same directory as your .ino file.
The version with <> looks for the .h file in the libraries directory

I wonder if, in the example that works, there is also a local copy of the library?

It is also usually the case that the library should be in a directory with the same name as the .h file - for example ...\libraries\MegunoLink rather than ...\libraries\MLP-master (legacy) I wonder if there were instructions to rename the directory before saving it into the libraries directory.

...R

There is an option in the meguno program that installs the megunoLink library to
"Using library MegunoLinkPro in folder: C:\Program Files (x86)\Arduino\libraries\MegunoLinkPro (legacy)"
In the MegunoLink folder there is an examples folder that holds the arduino example .ino file for the xyPlot feature. There is also a utility folder that holds the MegunoLink.h file. But as you can see above it dosn't show a path to this file when compiling......I don't know what to think. I even saved my sketch in the xyPlot file located in the examples folder and tried compiling it and same problem. Its almost as if this function will not work unless it is configured and used in the void loop(), which doesn't help me at all as I need it to work in the button function...grrrrrr

The MyPlot.SendData() function need to pass three arguments.

Change this

   else increaseB = 0;
     MyPlot.SendData(increaseB, result);

To this and try it.

   else increaseB = 0;
     MyPlot.SendData("Contact Gap Difference", increaseB, result);

BillHo:
The MyPlot.SendData() function need to pass three arguments.

Change this

   else increaseB = 0;

MyPlot.SendData(increaseB, result);




To this and try it.



else increaseB = 0;
    MyPlot.SendData("Contact Gap Difference", increaseB, result);

Wow, that did it. Thanks alot. Drove me bonkers trying to figure that out. I noted that the first argument has to be a string "".