How to plot a graph on a screen shield ?

Hi,

I received my screen shield from adafruit and I would like to draw a graph on it. And well, despite the research I've done on internet/forum I can't find some "easy and accessible" resources (ok, I admit, I'm a newbie here). Everybody seem to be interested in logging data and then plotting them on the computer with excel or labview or matlab ...

what I would like is to plot my sensor data (light, humidity, resistance, atmospheric pressure, etc ...) on my screen shield.

add. infos : I have arduino Uno, Adafruit 2,8" TFT Touch Shield and some random sensors (one at a time considering this shield is taking so many pins :( )

In advance : thanks a lot for your guidance.

Chris.

The site from adafruit has many tutorials. Is it this screen - http://www.ladyada.net/products/tfttouchshield/ -? You were not clear about that.

Hi ! Sorry for not being clear on that. Yes this is the screen I have. Cheers.

Modification: ... And yes there is a library and a good tutorial but nothing for plotting a graph. There is all you need for text, rectangle, circle, line, clear screen. But I haven't found for plotting values.

There is all you need for text, rectangle, circle, line, clear screen. But I haven't found for plotting values.

What kind of plot do you want? Generally a "plot" consists of lines and text...

Looking at the library you could create graphs using the drawLine(x1,y1,x2,y2,color)-routine.

I don’t know whether it works since I don’t have an 320x240 screen, you may have to
correct the code to get it working, but hopefully this will give you an idea how to create a graph.
All routines to be able to work with the screen should of course be loaded and initialised as well.

void graph(void){
 int y1,y2, z1,z2;
 int color = 0x001F; // 1 blue line
 int color1 = 0xF800; // 1 red line

  for (int x=1;x<319;x++){
     y2 = map(analogread(1), 0, 1023,0,240); // map max analog read (1023) to max screensize (240)
     z2 = map(analogread(2), 0, 1023,0,240); // map max analog read (1023) to max screensize (240)

     drawLine(x,y1,x+1,y2,color); // draw line between previous reading and current
     drawLine(x,z1,x+1,z2,color1); // draw line between previous reading and current

     y1 = y2; // Make current reading previous
     z1 = z2;
  }

}

In this example 319 readings of two analogpins should be shown in a line-graph in two different
colours. It should also be possible to use rectangles in a similar way. Haven’t looked at the
circle()-routine yet, if it’s possible to draw parts of circles it may also be possible to create pie-charts.

For circles there is allways the bresenham algorithm (fast integer only)

Hey All !! Thanks for your answers.

Reading your answers (particulary Simpson_Jr's), I think a good way to do this graph would be to draw the values pixel by pixel in a loop (pretty much like you did Simpson_Jr).

I can't check it now, but it looks like your code will draw from left to right. And when it arrives on the right (at 319), it will stop. Unfortunately, they don't like me to bring my arduino board at work.

Maybe I can give you more details now on what I imagine : a sliding graph. I don't know if that's the right word so let me explain : every [time] millisecond (as in delay([time])), the graph would move one pixel to the left and the last pixel on the right would take the new value of the sensor.

So I imagine I will need a vector of values per sensor, sensor(i) with i=0:239. Once every second for example : sensor(i) = sensor(i+1) drawpixel(i, sensor(i),...) sensor 239=map(AnalogRead(1), 0, 1023,0,240)

Am I on the right track ?

PS: regarding the rectangle and circles, that's not my direct interest now, but very interresting thought. imagine having some tweet-a-watt in a room and seeing on a screen what is the repartition of electrical comsumption, realtime :)))

A sliding graph (don't know whether it's the right term as well :-) would probably also be possible. I guess the way you describe it should work.

It will use a lot more RAM & processing power available though. Storing 2 signals x 320 pixels in byte-arrays would already cost ~1/3 of the 2KB RAM-memory available on an 328-based duino. Updating/plotting the complete graph every time new values are measured will also take a lot more time. If it takes less time as the interval needed it should work though.

as in delay([time])

That's something I'd try to avoid... to program a time based interval in which you also perform other tasks. During a delay()-function arduino does nothing else as waiting for an amount of time. To get an correct interval using a delay() you'll also need to know exactly how long all other tasks take as well. Should one of the other tasks take different amounts of time during different readings, setting delay() or delayMicroseconds() correctly will be quite hard.

A better possibility is setting an interval using millis() or micros() and continuously checking whether it's time yet. If not... other tasks like updating/plotting the graph, reading switches etc could be done until it's time. If those other tasks are performable within the interval set, the next measurement should always be right on time. The blink without delay example basically shows how.

Hello !

Thanks Simpson_Jr for the repply. For the memory consumption, is there an issue except not being able to make many other calculation or storing a large program (that would have other functionnalities) For the delay(). well noted. for other potential readers here is what I've seen on other pages : http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay ... the blink without delay example http://arduino.cc/forum/index.php?topic=66062.0 ... another way to multithread processes.

more questions :

  • if the task of updating the sliding graph takes more that the "delay" I want to put, then the new value added at the right end of the graph will skip a value. Right ? for example. the graph updates to the initial value, then the board goes in the loop for updating the graph but before the end of this loop (before updating the pixels on the right side), it will have enough time to update the sensor reading twice. Am I right ? ... or am I completely wrong and the time between 2 analog readings will be the max between [graph updating time] and [delay time]

  • since the time taken by different tasks is an issue, what is the usual way/method to keep an eye on each task ? should I put a time marker (in milli-seconds) and display it at different steps, or maybe output a substraction of time marker to know the duration ... how to I monitor the "load" on my board ? (... maybe I should search the forum before asking ?)

  • In the example you mention "Blink without delay" (http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay) since the moment you blink your led is in milli-seconds and stored in a long-typed variable. What will happen when your reach the maximum value of 2147483,647 seconds ? I guess it will flip around, then the substraction done to have the delay will return very large positive value ... so it will stop ? ( ... maybe I should try before asking ?)

NB: sorry I don't have my board with me, I can't check in realtime. they don't like too much me coming at work with my arduino and my netbook ... héhé. Hopefully tonight I can have a look and try all this. NB2: edit from the "tonight I'll check stuff" ... well it's already late. no time to check tonight since it will involve putting together a protoshield + programming :( argh, I so wanted to try this :/

(moving graph) you should use a circular buffer in which the calculated values are stored 0..240 => byte will do

byte array[320]; 
int idx;   // keep it % 320

new values are added (%320) and overwrite old ones. But before painting the pixels you must clear/remove the old one. so a repaint of 640 pixels (at least)