Analog Sample Rate

I just got a new Duemilanove and a touch shield. I wrote code for it to sample 2 analog channels and then send the data to the touch shield for display. I have a potentiomenter connected to the analog channel of the board. What I have found is that the data sent to the touch shield is not updated as fast as I can change the potentiometer. For example, I have changed my analog values which range from 0 - 1023 into degrees (0-359) of a circle. Then I draw a single pixel of the circle for each degree I read in. If I turn the potentiometer very slowly, I can draw the whole circle and not miss and pixels. However, if I turn the potentiomenter decently fast, I miss lots of pixels, sometimes 20 or so in a row.

The serial interface between the arduino and touch shield is 9600 baud so that should keep up sending only 2 ADC values. The sample rate on the arduino is fast enough. Why am I not getting all my analog values. There must be a bottleneck somewhere.

Here is the basic code on the arduino:

#include <SoftwareSerial.h>
#include <AFSoftSerial.h>

#define rxPin 3
#define txPin 2

AFSoftSerial mySerial = AFSoftSerial(rxPin, txPin);

void setup()
{
// define pin modes for tx, rx:
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
mySerial.begin(9600);
Serial.begin(9600);
}

unsigned int adc1, adc2;

void loop()
{
adc1 = analogRead(0);
delay(10);
// adc2 = analogRead(1);

//convert to degrees of rotation
adc1 = adc1-102;
adc1 = adc1/2.272;

//should never be greater than 359 degrees
if(adc1 >= 360)
adc1 = 0;

//should never read more than 1023 on a 10 bit ADC
//if(adc2 >= 1023)
// adc2 = 0;

mySerial.print((unsigned char)((adc1) >> 8));
delay(7);
mySerial.print((unsigned char)adc1);
delay(7);
mySerial.print((unsigned char)(adc1 >> 8));
delay(7);
mySerial.print((unsigned char)adc1);
delay(30);

}

If anyone spots an error in my math, let me know.

With all the delay() calls in your loop(), you're taking at least 61 milliseconds between samples, and more depending on how long it takes to send the serial characters. That's at least 1/16th of one second. If it took you 2 seconds to roll the potentiometer from max to min, then you'd only get about 32 readings, not all 1024 possible readings, from max to min.

Those were the least amount of delay I could put in the code in order to communicate with my touch sheild. For example, I tried putting less delay between sampling analog 1 and 2 and the values end up coming out wrong and not updating on the touch shield screen. I tried putting less delay between sending to the serial interface to the touch shield and again, the shield flashes and does not update. What is a good way to get less delay in the code, but still be able to sample and send data to the touch shield?

I guess I should ask how do you determine how much delay is needed between consecutive analog reads and how much delay is needed between each serial print. The values I have in my code are the least amount of delay i could use without seeing other issues.

If I need my board to process data quickly there needs to be a better way to do it without adding all these delay statements.

You don't need any delay between ADC samples. The analogRead function will wait for the conversion to complete and return as soon as the data is ready.

It sounds like the delay is needed for the touch shield, have you checked to see if you can speed up communication with that?

I haven't found any documentation on the touch shield. I'll keep looking though to see if there is a limitation which is holding me back. I also could not get the touch shield to work on any other baud rate but 9600.

If you can't increase the baud rate, you could double the performance by sending one byte per sample instead of two bytes. You can use the Arduino map function to scale from 0-1023 to 0-180, that way each unit of value represents two degrees.

adc1 = analogRead(0);,
val = map(adc1, 0,1023,0,128);

Since you are only using one serial line, have you tried using the hardware serial?

How do I use the hardware serial to connect to the LCD? How do you define which pins the hardware serial will use?

How do you define which pins the hardware serial will use?

You don't, Hardware serial is fixed at pins 0 and 1

Kind of a silly question, but it makes me wonder nonetheless - if you draw a circle showing where the pot position was, and now is...

Why do you care if you miss samples? If you're moving clockwise, for example, and your last reading was at 100, and you're now at 120 - you can safely assume you passed through 110 to get there. (And if someone rotated it all the way around CCW in a mS, you're screwed either way =)

Why not just "fill in the blanks" and not have to worry so much about "real-time awareness"?

!c

Edit: it's kind of like those bar graph visualizers on a stereo EQ - they're not "actually" in real-time, they just appear to be that way.

I think the issue is that if you want to fill in the blanks, you still have to send those serial commands to the LCD, which is really slow.

But good point though, if you don't care if the LCD is slow, you can simply make another variable called LCDangle or something, which gets increased or decrease by say 1 every loop depending on if LCDangle > PotAngle or not.

In my application I am measuring a couple things. I want to measure the angle as it relates to a circle as well as a pressure associated with that angle. I am basically measuring the pressure of something as it rotates. I would like to store and send to the lcd the pressure at every angle interval possible. I should also mention that this can rotate in any direction and switch dirctions whenever. Yet I am not getting the granularity I need. My program is now baiscally sampling as much as it can, and then every rotation it updates the lcd with the data for an entire rotation. While it updates the lcd it is missing samples that are happening during the serial send. Also, the more features I add to my program, such as sending data to storage (EEPROM) the less resolution I get on my samples/angle. I guess this is just a limitation of the speed serial interfaces and processor.

How fast is it rotating and how many samples per rotation do you need?

Or better yet, what specifically are you trying to accomplish?

My goal is to be able to achive a rotation rate of 120 rpm and sample with an accuracy of 5 degrees (at least 1 sample every 5 degrees). This seems possible if the program is doing nothing else, but when I had communications and other features, things begin to slow down.

Ok, you are looking for 144 samples per second (hz) (or .007 period). Arduino analogRead can do about 10,000 per second so no problem there.

The trick to not losing samples is to use interrupts. You copy the data to send at the top of the loop (quickly, or use a double buffer approach) and send the copy in the main loop over the uart. Need to figure out how to generate an interrupt every 5 degrees. if 5 degrees and rpm isn't critical then use a timer interrupt (figure out how much time = 5 degrees of rotation). Otherwise it gets complicated.

The main loop will be treated as though it were a "lower priority" thread, where execution will be suspended and the readings taken (again quickly) and then resumed.