Helo, I’m new here, but I’m with a very urgent problem.
I’m trying to acquire a sinus signal from a function generator which is about 20 Hz with 1V with arduino.
I’m conecting the ground of the function generator to the arduino ground and the output to the A0 pin. Then I have the following program on arduino:
double t = 0;
double s = 0;
int analogPin0 = 0;
int val=0;
void setup() {
// start serial port at 9600 bps:
Serial.begin(9600);
s=millis();
}
void loop() {
val=analogRead(analogPin0);
Serial.println(val);
t=millis()-s;
Serial.println(t);
//delay(4000);
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.println(‘A’); // send a capital A
delay(300);
}
}
And this is connected to the MatLab by the program:
clc;
clear all;
numSec=10;
t=;
v=;
s1 = serial(‘COM3’);
s1.BaudRate=9600;
set(s1, ‘terminator’, ‘LF’);
fopen(s1);
try
w=fscanf(s1,‘%s’);
if (w==‘A’)
display([‘Collecting data’]);
fprintf(s1,‘%s\n’,‘A’);
end
i=0;
t0=tic;
while (toc(t0)<=numSec)
i=i+1;
v(i)=fscanf(s1,‘%d’);
t(i)=fscanf(s1,‘%d’);
plot(v(i),t(i),‘*r’)
drawnow;
hold on
end
t2(1);
hold off
fclose(s1);
catch exception
fclose(s1);
throw (exception);
end
My problem is that suposedly, in graph that appears in the MatLab I should be able to see my signal, but it seems that the Arduino is giving random points to Matlab.
If too slow then the ADC output would look random.
Since the AC wave is 20Hz you need to sample at better than 40Hz (Nyquist rate) and to nicely reproduce the sine wave its better to sample at 10x (200Hz) or faster.
One way to measure the ADC sampling rate is to toggle an output pin at the end of every ADC sample. Then measure the pin output period on an O’scope.
Does your code work correctly if you inject a DC level into the ADC? If not then the code is not working properly.
If DC is working then try a much lower frequency from the sig Gen.
The ADC can’t sample any faster than it takes the main loop to print out the time and the value, which at 9600 baud is less than 1000 characters per second. Depending on how many characters are actually output for t and val, this could be quite slow. You could increase the baud rate, or:
Don’t use double for t and s. They are unsigned long integers.
Make t and val to be arrays, for example int t[100],val[100]. The program could then sample 100 values quite rapidly and later, print the 100 values.
If you’re trying to get real-time output then you need to be careful of your sampling loops timing. As said above sending characters out over a slow serial connection will introduce a serious penalty. My recommendations are:
increase the serial port speed (115.2k)
send the minimum of data needed to display the signal
Re: the latter I wouldn’t bother sending the sample times over the serial link but rather make the samples happen at set increments of time, just like an oscilloscope does. Perhaps even send the 10 bits of A/D as binary data, packed into 2 bytes rather than as an ASCII representation of the 10 bit value. Unpack and scale with MatLab at the PC end.
I also wonder about how you’ve got the signal connected into the Arduino. Is the signal strictly AC, that is going above ground (0.5V) and below ground (-0.5V) ? If so then the Arduino A/D won’t sample the negative portion of the signal properly. You need to add a DC bias into the signal so it remains >0 V at all times. I don’t know how you’re generating the signal but most function generators will allow you to add a DC bias to their AC output. If not you can “ac couple” the signal to the Arduino and add a bias there (at the Arduino). AC coupling means putting a big capacitor in series with the signal output and before the Arduino circuitry. Again most function generators will allow you to do this with a switch setting. Then use two 10K resistors to make a voltage divider at the analog pin. One resistor between 5V and said analog pin, the other between ground and said pin. The big cap then connects to that same pin. You’ll now have a 1V signal added to a 2.5V DC offset at the Arduino.
As for making the samples happen at set intervals … you have 2 choices. You can setup an internal interrupt to trigger the sampling and “printing” routine every X msec or, given the sample rate for your signal need not be too fast (200 Hz), use a loop and test for time passage since last sample. Be sure to sure to use the micros(), not millis(), function. At 200 Hz that’s 5 msec between samples and that should allow a reasonable amount of instructions to be run and data to be sent out. My guess is you could leave the sample ASCII encoded and the 4 bytes to send … say a sample value of 1023 … would take < 400 usec. Add another 120 usec for the A/D conversion and even a 1000 usec for the rest of the loop and you’d still be able to do a 200 Hz rate, faster even.
I wrote a short sketch to figure out what sample rates could be accommodated w/o having to go to interrupts. Using the code below and varying the baud rate and sample periods I found that the sampling loop in the code took :
@ 9600 baud : 5.2 msec
@ 19.2k baud : 2.6 msec
@ 38.4k baud : 1.3 msec
Oddly anytime I tried to increase the baud rate to 57k my Java runtime engine quit. Anyway you can see how having to send characters out over the serial line affects the rate at which the loop runs. I would say it’s the dominant factor. Consider that my random samples were always 3 characters long (generally 300 -399 counts). Add in a CR and at best the actual sending of the 4 characters takes ~1 msec. Now I think the Arduino UART has a 1 byte buffer so the code can put 2 chars into the pipeline and then has to wait for the 1’st one to empty out before putting any more into the pipeline. Given I was also storing a time away you should have no problems getting a good sampling rate (>= 200 Hz) for your 20 Hz signal using a faster than 9600 baud rate and slimming down what data is sent.
// declare constants
const unsigned long s_period = 5000; // this is the sample period in usec
int analogPin = 0;
// declare variables
unsigned long t_now = 0; // the latest time from micros call
unsigned long t_prior = 0; // the last time a sample was taken
unsigned long t[50]; // save space for 50 times
int val = 0; // A2D reading
int count = 0; // loop counter
void setup(){
Serial.begin(38400); // vary the baud rate
t_prior = micros(); // init time of last sample
}
void loop(){
// take 50 samples and then report their timing
while(count < 50){
t_now = micros(); // poll the time at the top of the loop
// get a sample when a sample period has passed since last sample
if(t_now - t_prior >= s_period){
t_prior = t_now; // remember time
t[count] = t_now; // save time when sample taken
val = analogRead(analogPin); // sample
Serial.println(val); // output data
count++;
}
}
// send saved times to serial monitor
for(int i=0; i<50; i++){
Serial.println(t[i]);
}
count = 0; // reset count for next 50
}
ps - note how the code above appears and saves the indentations from the editor. Use the code button/tags to do this.
Yes, please tell us since we only take guesses on the available info. Letting us know the real solution adds to our knoweledge as well as have the complete solution if someone else has this problem.