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.
Related
I am using attiny microcontroller and atmel studio. And I am using the millis function in my project.
Code related to the millis function:
And I am using this classic code:
starttimex = millis();
endtimex = starttimex;
while ((endtimex - starttimex)<=60000)
{
endtimex = millis();
// Action
}
I don't want the millis() function to reset after 50 days.
I have to use uint64_t instead of unsigned long.
My questions:
Does this cause any trouble? Does this situation have a disadvantage? One of the disadvantages is memory size. I know this. But, I don't know other disadvantage.
I don't understand variable of timer0_overflow_count in the image. Is there a need for this for millis?
Should I do uint64_t for all of the unsigned long variables in the image?
Thanks
If your interval (60000 in your sample code) does not exceed the range of unsigned long, you're fine.
The millis() function does not reset, it simply rolls over :)
(endtimex - starttimex) in unsigned arithmetics calculates fine, even during a rollover.
I don't understand variable of "timer0_overflow_count" in image. Is there a need for this for millis?
The overflow count is used to keep track of the number of millis even when the period of the timer is not an exact multiple of milliseconds. For example, imagine if the timer went off every 1.5ms, see how that would work?
Does this cause any trouble?Does this situation have a disadvantage?
You can use any type you want for the millis counter, but keep in mind that interrupts are off whenever that variable is updated or read, so going from 32 to 64 bits means that interrupts will be off for significantly longer, which could impact other interrupts running on the system.
With the following:
Serial.begin(9600);
I am printing two values:
Serial.print(Input);
Serial.println(Output);
delay(100);
I am measuring temperature and PWM signal.
What are the drawbacks of using delay?
Here are a couple of drawbacks of using delay :
Inaccuracy
Unable to multitask
There is one good way to go make a delay without using delay(), it's by using millis(). See here for great examples of why millis() is better than delay() and how to maximize its capability.
It is usually fine to use delay() in simple programs. However, imagine you have 4 tasks:
T1 which you want to execute every 2s
T2 which you want to execute every 3s
T3 which you want to execute every 3.5s
Serial read task, which should read serial input as soon as it arrives
How would you deal with that using delay()? It is much better to use approach based on millis() or micros() functions, like here, or use the elapsedMillis library, which under the hood does the same, but makes a code a bit more readable.
The main idea, is that you want to have a sort of timers, that store a time elapsed from last reset. You check the state of these timers in every iteration of the loop() function, and if they finish, you execute associated task:
void loop() {
if(isTimerDone(Tim1)) {
T1();
resetTimer(Tim1);
}
if(isTimerDone(Tim2)) {
T2();
resetTimer(Tim2);
}
if(isTimerDone(Tim3)) {
T3();
resetTimer(Tim3);
}
readSerialPort();
}
That way it is very easy to change timing for each task, as it is independent of other tasks. It is also easy to add more tasks to the program.
It is also true, that delay() (but also millis()) are innacurat,e in a sense that you are not guaranteed to have an exact timing. To be sure that a task is executed exactly after given time, you need to use interrupts, like in here (Arduino Playground on Timer1).
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.
The Arduino A/D converter takes about 0.1ms according to the manual. Actually, my tests show that on an Uno I can execute about 7700 per second in a loop.
Unfortunately analogRead waits while the reading is being performed, making it difficult to get anything done.
I wish to interleave computation with a series of A/D conversions. Is there any way of initiating the analogRead, then checking the timing and getting the completed value later? If this needs to be low-level and non-portable to other versions, I can deal with that.
Looking for a solution that would allow sampling all the channels on an Arduino on a regular basis, then sending data via SPI or I2C. I am willing to consider interrupts, but the sampling must remain extremely periodic.
Yes, you can start an ADC conversion without waiting for it to complete. Instead of using analogRead, check out Nick Gammon's example here, in the "Read Without Blocking" section.
To achieve a regular sample rate, you can either:
1) Let it operate in free-running mode, where it takes samples as fast as it can, or
2) Use a timer ISR to start the ADC, or
3) Use millis() to start a conversion periodically (a common "polling" solution). Be sure to step to the next conversion time by adding to the previously calculated conversion time, not by adding to the current time:
uint32_t last_conversion_time;
void setup()
{
...
last_conversion_time = millis();
}
void loop()
{
if (millis() - last_conversion_time >= ADC_INTERVAL) {
<start a new conversion here>
// Assume we got here as calculated, even if there
// were small delays
last_conversion_time += ADC_INTERVAL; // not millis()+ADC_INTERVAL!
// If there are other delays in your program > ADC_INTERVAL,
// you won't get back in time, and your samples will not
// be regularly-spaced.
Regardless of how you start the conversion periodically, you can either poll for completion or attach an ISR to be called when it is complete.
Be sure to use the volatile keyword for variables which are shared between the ISR and loop.
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