It's my first time posting on this forum and I hope anyone can help me out.
I am currently working on EMG project to send muscle signal data via Bluetooth and save the data on Excel using PLX-DAQ. The problem is that I want my code to run faster and avoid using any 'delay'.
I read on this Arduino's forum thread that the usage of analogRead slowed the code and he suggested the code below which removed the 'delay' and also serial.print:
#define SENSORPIN 2 // can't be changed :)
void setup()
{
Serial.begin(115200);
}
void loop()
{
int sensorValue = analogRead(sensorPin);
Serial.write((uint8_t) (sensorValue >> 8)); // some bit masking to get the highbyte
Serial.write((uint8_t) (sensorValue & 0xFF)); // and the low byte
// delay(5); should not be needed
}
I tried to implement but when I read the data, serial monitor just shows some gibberish things instead of values. It's not because of the baud rate. Can anyone help me implement the idea into my code or any suggestion to make my code run faster?
Below is my code to read the EMG signal using two channels:
void setup() {
// open serial connection
Serial.begin(9600);
// define 3 columns named "Time", "EMG1", and "EMG2"
Serial.println("LABEL,Time ,EMG 1, EMG 2");
}
void loop() {
// convert analog output 0-1023 to 0-5V
float emgValue1 = analogRead (A1) * (5.0 / 1024.0);
float emgValue2 = analogRead (A2) * (5.0 / 1024.0);
delay(5);
//print time and both emg values
Serial.print((String) "DATA," + millis());
Serial.print(",");
Serial.print(emgValue1);
Serial.print(",");
Serial.println(emgValue2);
delay(5);
}
"run faster" is not a specification. What sample rate do you require?
If all you are doing is analogRead() and discarding the output, then you can get up to 10,000 samples per second. You can never achieve that, but it gives you some idea of what's possible. With some work it's even possible to go faster than that, but that's rarely required.
The "gibberish" is the binary data output. You must store that on the PC and then convert it back to human-readable characters. Binary is better because a number like 35546 can be sent in only 2 bytes instead of the 5 bytes I used to show it in readable characters.
I see you chose 9600 baud. Is there any reason for choosing that speed? The fastest speed available in the regular list of speeds is 115200, or 12 times faster. With a tiny bit of effort, it's possible to go to 500000 on an Arduino.
"run faster" is not a specification. What sample rate do you require?
My desired sampling frequency is 2kHz.
I see you chose 9600 baud. Is there any reason for choosing that speed? The fastest speed available in the regular list of speeds is 115200, or 12 times faster
There is no specific reason to choose 9600. I can always change the baud rate but I don't really see any significant difference in that. So I just think maybe modify the code is another way to increase the sampling frequency.
Wawa:
// convert analog output 0-1023 to 0-5V
That, and the lines after that suggests a voltmeter.
What human readable output do you expect.
0-100% could be an option.
You don't have to convert it to anything.
Leaving it as rawData (0-1023) is also ok.
Leo..
I want it to be readable in voltage. The reason is the sensor is supplied with 5v. Raw EMG values usually range from 0 to 10mV. After a gain of 1000, usually, it is around 1v and above. Since the sensor is supplied with 5v, I assumed the max voltage it can go is only up to 5v. Is my assumption wrong?
The A/D returns a value between 0 and 1023.
It's up to you what to do with that.
If you want to display muscle strength in volts, so it is.
Bit silly though if you ask a weightlifter how many volts he can lift.
Leo..
amsyar:
Its for graph analysis on how much voltage generated when muscle contracts
The Arduino might be powered by 5volt (or 4.6volt if it's a Nano), but the A/D doesn't generate any voltage.
It generates digital values (0-1023).
Leo..
Hi,
Can you try this edited version of your code please, make sure the monitor is set to 9600.
int Emg1Pin = A1;
int Emg2Pin = A2;
float emgValue1;
float emgValue2;
void setup() {
Serial.begin(9600); // open serial connection
Serial.println();
Serial.println("Starting");
Serial.println("LABEL \tTime \tEMG \tEMG 2"); // define 3 columns named "Time", "EMG1", and "EMG2"
delay(2000);
}
void loop() {
emgValue1 = analogRead (Emg1Pin) * (5.0 / 1024.0); // input and convert analog output 0-1023 to 0-5V
emgValue1 = analogRead (Emg1Pin) * (5.0 / 1024.0); // repeat the analogread to ensure input of ADC is stabilised on input voltage
emgValue2 = analogRead (Emg2Pin) * (5.0 / 1024.0);
emgValue2 = analogRead (Emg2Pin) * (5.0 / 1024.0);
delay(5);
Serial.print( "DATA \t"); //print time and both emg values
Serial.print(millis());
Serial.print("\t");
Serial.print(emgValue1);
Serial.print("\t");
Serial.println(emgValue2);
delay(5);
}
You should get this in your monitor.
Starting
LABEL Time EMG EMG 2
DATA 2004 2.84 2.70
DATA 2017 2.16 2.22
DATA 2028 2.34 2.28
DATA 2039 2.28 2.30
DATA 2051 2.18 2.18
DATA 2067 2.33 2.25
DATA 2092 2.11 2.11
DATA 2115 2.04 2.04
DATA 2140 2.10 2.12
DATA 2163 2.51 2.44
DATA 2187 2.23 2.20
DATA 2211 1.95 1.98
DATA 2235 1.90 1.90
DATA 2258 1.88 1.92
DATA 2283 2.35 2.29
DATA 2307 2.18 2.13
DATA 2330 1.83 1.86
DATA 2355 1.77 1.78
DATA 2378 1.70 1.72
DATA 2402 2.21 2.14
DATA 2426 2.13 2.08
DATA 2450 1.71 1.75
DATA 2475 1.66 1.67
DATA 2498 1.59 1.59
DATA 2522 2.03 1.98
DATA 2546 2.08 2.01
DATA 2570 1.61 1.65
DATA 2593 1.56 1.57
DATA 2618 1.49 1.49
DATA 2641 1.86 1.82
DATA 2665 2.03 1.96
DATA 2690 1.51 1.56
DATA 2713 1.46 1.47
DATA 2738 1.41 1.41
DATA 2761 1.68 1.67
DATA 2785 1.94 1.88
DATA 2809 1.45 1.48
DATA 2833 1.39 1.39
DATA 2856 1.33 1.33
DATA 2881 1.52 1.52
DATA 2905 1.86 1.79
DATA 2928 1.47 1.46
This is with open circuit floating analog inputs.
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
amsyar:
I want it to be readable in voltage. The reason is the sensor is supplied with 5v. Raw EMG values usually range from 0 to 10mV. After a gain of 1000, usually, it is around 1v and above. Since the sensor is supplied with 5v, I assumed the max voltage it can go is only up to 5v. Is my assumption wrong?
Can be very wrong as the maximum output of a sensor is not necessarily the supply voltage. It depends on the sensor (and you didn't give any info on what specific sensor you're using). As I understand you have a sensor that reads a certain voltage (this EMG), then converts it into a much higher voltage (a gain of 1,000 would give a 10V output for a 10 mV input - so that's a zero too many in the gain), and feeds that to your Arduino.
If you expect an input of around 10 mV with peaks of say 20 mV, then a good target gain would be 200, giving you a typical input voltage of around 2V and a peak of 4V, comfortably within range of the Arduino. Setting a gain at 250 would give you a slightly better resolution but also risking peaks to go off the scale (normally sensors won't output higher voltages than the supply voltage).
amsyar:
There is no specific reason to choose 9600. I can always change the baud rate but I don't really see any significant difference in that. So I just think maybe modify the code is another way to increase the sampling frequency.
It is absolutely significant. The sample rate of your sketch is limited by the baud rate of getting the data out. The analogRead() is just a ten-thousandth of that.
It's simple to work out:
Baud rate is bits per second, but there's some additional start and stop bits you don't see. To send one 8-bit byte takes 10 bits, so you can only send 960 bytes in a second.
If one sample only took 1 byte, then you're already worse than half your stated objective, and we haven't included any of the redundant "DATA" words on each line.
One way to go faster is to use one of the Arduinos that has a "native USB". You can get 2 Megabytes per second without too much difficulty.