Serial print slowing down execution of code. Arduino Due - arduino

We are using an Arduino Due to send serial data via usb to a piece of software produced in visual studio.
The problem we are having lies with the Due. We have a section of code that is time critical
PumpCycleTime = millis();
// Loop this until the pumpHIGH duration has expired
do
{
digitalWrite(Pump, HIGH);
SendSerialData();
}
while (millis() - PumpCycleTime < PumpHIGH);
// Record the pump cycle LOW start time
PumpCycleTime = millis();
// Loop this until the pumpLOW duration has expired
do
{
digitalWrite(Pump, LOW);
SendSerialData();
}
while (millis() - PumpCycleTime < 1);
Initially we were controlling the frequency of the pump using delays. Which gave us reliable frequencies when measure on an oscilloscope. However this of course compromised the plotting of the graphs as there was gaps in the data.
With millis() we are unable to produce the same frequency. Obviously we could compensate to achieve a single frequency however we need to be able to use a range frequencies reliably.
It seems the SendSerialData(), which is a function with around 15 serial.print's, is effecting the timings as without it the frequency is as expected.
Does anyone know of any solutions? Data logging and plotting to a graph in real time is essential and cannot be compromised.
Thanks in advance

If the time is so critical DON'T use delay(), use Finite State Machine.
More then this, what is your baud rate? if it's 9600 there is a big chance that is your slowing down because the println();, try to use a bigger baud (like 115200).
Hope it's help.
Yoav

Related

How do I read serial between interrupts on Arduino?

I have steppers stepping during an interrupt timer at 50 and have all my code working between the interrupts until I tried reading serial commands more than one character long.
I'm getting dropped bytes so my strings are missing a letter every 4-5 chars. I researched all day to try and figure out a solution but have come up with nothing. If I don't use an interrupt my stepper stops for 2 seconds reading a one char serial input as a string.
My goal is to have a remote control app sending speed commands. I need help working this problem out.
https://sourceforge.net/p/open-slider/code/ci/master/tree/OpenSliderFirmware/
String incomingString = "";
if (Serial.available() > 0) {
incomingString = Serial.readString();
Serial.println(incomingString);
}
Using Accelstepper library
interrupt:
//Interrupt Timer1
void ISR_stepperManager() {
Slide.runSpeed();
Xaxis.runSpeed();
Yaxis.runSpeed();
}
Quick answer: you don't if the interrupt timer is cutting in too often.
I resolved the problem by using a variable interrupt timer and a step multiplier. Basically the steps are called every time the timer interrupts instead of checking millis inside the interrupt function. This solved many issues. The speed of the stepper is now controlled by the interrupt timer. This gave me more free cycles to fully read the incoming serial without corruption and improved efficiency. Calling more steps per cycle when doing over 4k steps/s also improved efficiency requiring less cycles for a high rate of steps.
The serial is processed one char per cycle to prevent blocking.
Overall, if you are using serial and an interrupt timer, any interrupt happening < 100us you should be cautious how much code you are running during the interrupt. It will cause issues with incoming serial and user inputs. A few lines of code in a 25us timer interrupt, incoming serial will not function.
i'm not sure if it will help to your problem, but i saw along the time that the String type is not safe to use when other things need to happened.
i prefer to use char array and read one char at a time.
while(Serial.available())
{
data[x] = Serial.read();
x++;
}
i'm finding it much more reliable.
hope it's help!

How do I measure how long operations take on an Arduino Mega?

I'm writing code that requires me to have certain code run at exact times (Like a loop taking 8ms long) on an Arduino Mega. I'm trying to figure out how to calculate this by finding out how long it takes for a Mega to make one calculation and multiplying it by the # of calculations in a certain block of code. Is this the correct way of approaching this problem? How do I even count how many calculations are going on?
One of the simplest ways to implement a timer is by using millis() in your loop() function and comparing it against the last time your code ran, something like this:
long loopTime = 0;
loop()
{
if (millis() - loopTime >= 8)
{
// Do the stuff here that you want to happen every 8ms
// ...
//
// Keep track of the last time this code ran, so we'll run it
// again 8 ms from now
loopTime = millis()
}
// Do other stuff here
}
Note that this will not be precise, because the millis() function doesn't guarantee an exact figure. If you require absolute precision you'd need to use some sort of external hardware timer to generate an interrupt every 8 ms. Interrupt programming gets a bit more complex, but the timing loop technique shown above should work for most things that don't require absolute precision.

Arduino Servo Motor Control with SD Card Data

I've been working on a project where I need to control servo motors based on data saved on an SD card. So far it is going well, however I'm having issues with controlling the timing and speed of the servo motors movements. I'll explain what I'm trying to accomplish and some example code.
I'm using an Arduino Mega with an SD module attached to it. On the SD card I have four different .txt files. Each file contains 30 integer values, each line contains a single integer and is terminated with a (,). This is merely test data so I can sweep through a range of angles to check I'm reading and converting the values just fine. But when I try to slow down the servos using timers, delays etc. it speeds through the code as if they were there. In my case the code looks like this:
string dataRead =""; // String object to read bytes from
unsigned long int motorTime = 250; // Refresh time of the motor (250 ms)
unsigned long int lastMotor = (long) micros();
while (entry.available()) { // While there are bytes in the file to be read
dataRead = entry.readStringUntil(',');
while((long) micros() - lastMotor <= (motorTime * 1000)); // Do nothing until refresh time has elapsed
myServo.write(dataRead.toInt());
lastMotor = (long) micros();
}
The data is read fine and the motor moves according to the data, however the timing code just appears to be negated for some reason. I suspect it is because all sorts of hardware features are being enabled and disabled underneath all the layers of abstraction in the Arduino IDE and the delay is being negated for some reason.
Has anyone had experience of this? Any tips for driving a servo at a set speed? My alternative solution is to load the data into an array; but I don't want to run the risk of burning through all of the RAM and cause other problems.
Thanks in advance!
I fixed it in the end. I disabled interrupts for when I was reading the data and that messed with the timer functions such as micros() and millis(); they rely on interrupts to keep track of the elapsed time.
It probably makes more sense to detach the interrupt service routines rather than disabling them by default.

Arduino Uno - Light Switch

The function of the program I am writing is to stream incoming analog data from a sensor to a program on my computer across the USB port. For a little fun, I've decided to add a button to the program that will turn on/off a lamp. The lamp will be connected to a relay, which is connected to the arduino. I know how to go about programming it, but I want to know if this will interrupt the sensor data transfer?
I will get the current state of the light (HIGH(1) or LOW(0)) from the arduino when the button is pressed, then write to the arduino (HIGH(1) or LOW(0)) depending on the current state. I have a 5 second delay between each loop of the arduino program, for reasons related to the sensor output; however, I think I'm going to have to change this so that when the button is pressed, it is not missed by the arduino loop, or is that not possible?
I thought I read somewhere that you can't transmit/receive streaming data on the same serial line...in which case, I will need the Mega.
You have to remember and think of the Arduino as a single threaded device. While it is doing anything it is not able to do anything else. Period! In regard to the serial port however, the buffer will still accept incoming data on RX, however if an overflow situation occurs whilst blocked, management is impossible.
See the following taken directly from the Arduino reference
Certain things do go on while the delay() function is controlling the Atmega chip however, because the delay function does not disable interrupts. Serial communication that appears at the RX pin is recorded, PWM (analogWrite) values and pin states are maintained, and interrupts will work as they should. Reference
Now in saying that when you are setting the delay to 5 seconds between loops ( delay(5000) ) you are essentially blocking it from doing anything else almost full stop.
The Arduino framework exposes a a counter ( millis() ) that basically runs from the moment of boot for roughly 50 days in increments of one (1) millisecond. See Arduino - millis()
In your application you would define (remember) what loop you were due to run & when the said loop had finished so to not allow the other loop to run until the millis() counter was a defined amount more than your count. (Remember to define the count as a long)
Then what you do is move your loops out into separate functions that will only execute if the if statement return true...
for example...
long interval = 5000; // Define interval outside of the main loop
long previousCount = 0; // Used to store milli count when finished
int loopPosition = 1;
void loop()
{
if ((long)millis() - previousCount >= 5000 )
// This if statement will only return true every 5 seconds (5000ms)
{
if (loopPosition == 1)
{
function_One();
previousCount = millis(); // Redefine previousCount to now
loopPosition++; // Increment loop position
}
else if (loopPosition == 2)
{
function_Two();
previousCount = millis();
loopPosition--; // Decrement loop position
}
}
// Do Anything Here You Want
// - While ever the if statement above returns false
// the loop will move to this without hesitation so
// you can do things like monitor a pin low / high scenario.
}
void function_One()
{
// Do Your First Loop
}
void function_Two()
{
// Do Your Second Loop
}
The above will stop any delay you are using from blocking awesomeness, and to more of a point, almost make delay obsolete if implemented correctly under the right scenarios.
In regard to your serial data comment, like i said at the top of this article, the Arduino can only do one thing at a time. Transmitting and receiving at exactly the same time is impossible even with the Mega. In saying that a board like the 'Uno' for example is only capable of one serial interface, where as the 'Mega' is capable of four.
Best of luck....
NB- For a beginner reading this, the following tutorial / example covers what i have above in fairly simple terms and is a great building block for further awesomeness! Arduino - Blink Without Delay

necessity to give delay to adc

I was trying to send analog signals from arduino to the computer by the serial port.For getting the maximum samples of my input analog signals,I put my baudrate to the maximum limit.The code is as given
void setup()
{
Serial.begin(115200);
}
void loop()
{
int a=analogRead(A0);
Serial.println(a);
delay(1);
}
This program works well for my signals with very low frequency.but at higher frequency signals,there is still arising a problem of aliasing.I tried decreasing the delay.i got more samples When i did this but some of my digital values that I got could not be used,that is,some of the wrong digital values were like 353?12 and so on.Is it manda to give minimum delay of 1 ms to the ADC??Or is there any way that i can Increase my samplestory
You are running into an issue with the default prescaler setting in arduino. The default setup will only get less than 10 samples per millisecond.
You can certainly get faster reads from your ADC if you want to play with some of the underlying settings:
www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/
has a good write up on the subject. They got it running at 50 samples per millisecond with some tweaking.
The other option is to get an ADC chip which will run faster for you. Search sparkfun for "mcp3002". No tweaking of your arduino required since it uses spi input.

Resources