Very nice video. Also not just rerecording and only showing the correct code, but also talking about why the old code is wrong is a perfect solution. Guys can learn much more by such a code review. Maybe as a task for every viewer: rethink why the old problems do not appear anymore. Think exactly about the 2 situations that lead to the old bugs. The first one is easy to explain. The second one is more difficult to explain.
@@playduino Well, rethinking about bug 1 and 2 again in fact the first code was even faster buggy than I thought. Since if the if statement is executed in less than 1ms, this means that the storeTimeStamp is (at the end) always set to millis() (because of bug 2). So it will be set to the max value also and that mean bug 1 will occur 100%. Luckily you fixed it now.
Your new code will work just fine! However, if you don't fancy waiting almost 50 days for a rollover, do this In setup to adjust the millis counter. extern unsigned long timer0_millis; unsigned long untilOverflow = 1500; noInterrupts(); timer0_millis = 0xffffffff - untilOverflow; Interrupts(); Now wait 1500 milliseconds and the millis count will overflow. Cheers, Norm. (Author of Arduino Software Internals and Arduino Interrupts)
Nice! I'm going to check your book out. I'm in the interesting position of being what I would consider an intermediate programmer writing code for Arduino that will go into production in toys, so I'm doing as hard a crash course in C, C++, and Arduino/AVR programming as I can manage. Your book looks great!
@@victormikecharlie1596 There is! But it depends on how the test was written. The result of millis() doesn't go negative, obviously, but it does overflow from 0xffffffff to zero. That's the problem for some calculations. As described in the video. Cheers, Norm.
@@victormikecharlie1596 this is why overflow is a problem Arduino millis function, plus rollover. Don't do this: if (millis() - lastTime > 1000) doSomething(); Because roll over leaves millis() less than lastTime. Do this: if (millis() < (lastTime + 1000)) doSomething(); That always works. Cheers, Norm.
Its very good to know how the nuts and bolts of this stuff works so you know how to properly use it and know it's advantages. Now I'll shamelessly plug the NoDelay library that helps you use millis for timing without having to write that many lines of code yourself. Great for multiple timing loops
Thanks. Now the LED starts off and it's take 1 sek to light up. If I want the LED to start at once and then starts to blink. I tried to move the !-sign first but it's not accepted. Can you suggest something?
Hi, I have 2 blocking coded that both have delay I have a servo code that goes from 30 to 60 and from 60 to 30 with a delay of (15) speed back an forth. And also a DF-Mini player that has delays.. I'm not to familiar with Arduino so am needing some assistance
Hi the thing is, I do not know exactly what you are trying to do. However I think in your case the simplest solution is actually to use a library called TimerOne. You can keep your working blocking DF-Mini code in the loop. And then have a timer isr function called every 15ms. Inside you change the angle of the servo. You will need two static volatile global variables, one for current angle (int) and one for the direction(bool). Inside or the isr you increment the angle if direction true and decrement the angle is the direction is false. If you hit the maximum angle you need to change direction to false. If you hit the minimum angle you need to change direction to true. Put all this logic into ISR, but don’t put a delay into the ISR. You do not need it, because the ISR is called every 15ms. I’ll upload a video about TimerOne soon. But if you look at example code I’m sure you can do it
I would not deploy this to my nuclear power plant yet, but I am pretty confident that this will work because subtracting the big number will lead to a overflow that results in a small Number. Let's for a moment assume that we only have 8 bits. If storedTimeStamp = 255 and currentMillis is already very small, lets say 10. Now we calculate 10 - 255. it will overflow to the result 11. I just tried it by running the code: Serial.begin(9600); byte x = 10 - 255; Serial.print(x,DEC);
@@playduino Ah. I wasn't sure how Arduino handled types in conditional expressions, but it does look like it remains unsigned and overflows correctly. This is not always the case. Evaluating the difference of 2 unsigned types within a conditional can return a signed negative value on other platforms. Looks like you are safe to deploy after all. ;)
interesting. I assume as soon as one of the numbers in signed, the result will also be signed. Yeah all good, lets get this power plant up and running :D
@@Enigma758 ah, I see. @longdarkrideatnight it would be awesome if you could share the example you mentioned in the message that I currently cant see for some reason
// Blink an LED on PA2 on an ATTiny1614 MCU // Pin definitions // Important - always use the full pin definition i.e. PXn where X is the port letter and n the pin number const int ledPinRed = PIN_PA2;// Pin 2 Port A const int ledPinBlue = PIN_PB1;// Pin 1 Port B // Variable definitions unsigned int A = 888; //dividend unsigned int B = 444; //divisor unsigned int C = 666; //dividend unsigned int D = 222; //divisor void setDefaultPinStates() { pinMode(ledPinRed, OUTPUT); //set as output pinMode(ledPinBlue, OUTPUT); //set as output digitalWrite(ledPinRed,HIGH); //start with LED off digitalWrite(ledPinBlue,HIGH); //start with LED off } void setup() { setDefaultPinStates(); delay (1000); } void loop() { /* Flash the LEDs on PA2 & PB1 with a single line of code. The remainder of millis divided by A is compared to B and when greater the result is 1 and when less is 0, this binary result is written to the appropriate ledPin */ digitalWrite(ledPinRed, millis() % A > B); digitalWrite(ledPinBlue, millis() % C > D); }
you can find the code on git:
github.com/playduino/arduino-uno-programming
Very nice video. Also not just rerecording and only showing the correct code, but also talking about why the old code is wrong is a perfect solution. Guys can learn much more by such a code review. Maybe as a task for every viewer: rethink why the old problems do not appear anymore. Think exactly about the 2 situations that lead to the old bugs. The first one is easy to explain. The second one is more difficult to explain.
Thank you :) I agree, I really tried but it is very hard to explain and I had a hard time understanding the issue in the first place.
@@playduino Well, rethinking about bug 1 and 2 again in fact the first code was even faster buggy than I thought. Since if the if statement is executed in less than 1ms, this means that the storeTimeStamp is (at the end) always set to millis() (because of bug 2). So it will be set to the max value also and that mean bug 1 will occur 100%. Luckily you fixed it now.
OMG true, so the code would stop after 50days for sure
This is one of the best videos on youtube! Congrats!
Thank you!
Your new code will work just fine! However, if you don't fancy waiting almost 50 days for a rollover, do this In setup to adjust the millis counter.
extern unsigned long timer0_millis;
unsigned long untilOverflow = 1500;
noInterrupts();
timer0_millis = 0xffffffff - untilOverflow;
Interrupts();
Now wait 1500 milliseconds and the millis count will overflow.
Cheers,
Norm.
(Author of Arduino Software Internals and Arduino Interrupts)
Awesome, this is very useful, I will give it a try! Thank you very much!
Nice! I'm going to check your book out. I'm in the interesting position of being what I would consider an intermediate programmer writing code for Arduino that will go into production in toys, so I'm doing as hard a crash course in C, C++, and Arduino/AVR programming as I can manage. Your book looks great!
There aren't any need for checking overflow when you use milis
@@victormikecharlie1596 There is! But it depends on how the test was written. The result of millis() doesn't go negative, obviously, but it does overflow from 0xffffffff to zero. That's the problem for some calculations. As described in the video.
Cheers,
Norm.
@@victormikecharlie1596 this is why overflow is a problem
Arduino millis function, plus rollover.
Don't do this:
if (millis() - lastTime > 1000)
doSomething();
Because roll over leaves millis() less than lastTime. Do this:
if (millis() < (lastTime + 1000))
doSomething();
That always works.
Cheers,
Norm.
Its very good to know how the nuts and bolts of this stuff works so you know how to properly use it and know it's advantages. Now I'll shamelessly plug the NoDelay library that helps you use millis for timing without having to write that many lines of code yourself. Great for multiple timing loops
Thanks bro! Enjoying your videos👍
thank you! I'm glad
This would be better if you did direct but manipulation to remove all the overhead of the digitalWrite function.
But, I like that you are willing to acknowledge shortcomings, address them, and educate those you've previously guided as to the better methods!
Great video
Thank you
You are a great teacher 😊
Thank you 😊
im the 1000 subscriber :)
well done =D
Awesome teacher
Thanks. Now the LED starts off and it's take 1 sek to light up. If I want the LED to start at once and then starts to blink. I tried to move the !-sign first but it's not accepted. Can you suggest something?
hmm one solution is to turn on the LED in the setup, directly after pinMode.
Will the code cause both LEDs to change, out of time, on the ~50day overflow ?
I think it should not 🤔
Hi, I have 2 blocking coded that both have delay
I have a servo code that goes from 30 to 60 and from 60 to 30 with a delay of (15) speed back an forth. And also a DF-Mini player that has delays..
I'm not to familiar with Arduino so am needing some assistance
Hi, instead of delay(15) you could use the code shown in this video and then handle the servos instead of blinking the led (what I did)
@@playduino would you still have the code ?
Hi the thing is, I do not know exactly what you are trying to do. However I think in your case the simplest solution is actually to use a library called TimerOne. You can keep your working blocking DF-Mini code in the loop. And then have a timer isr function called every 15ms. Inside you change the angle of the servo. You will need two static volatile global variables, one for current angle (int) and one for the direction(bool). Inside or the isr you increment the angle if direction true and decrement the angle is the direction is false.
If you hit the maximum angle you need to change direction to false.
If you hit the minimum angle you need to change direction to true.
Put all this logic into ISR, but don’t put a delay into the ISR. You do not need it, because the ISR is called every 15ms.
I’ll upload a video about TimerOne soon. But if you look at example code I’m sure you can do it
@playduino HI well what I am trying to put together is a sketch for a wig-wag (sweep servo) using a IR sensor and a DF-Mini player.
Before you deploy this to your nuclear power plant, what happens when currentMillis overflows and is less than the storedTimeStamp?
I would not deploy this to my nuclear power plant yet, but I am pretty confident that this will work because subtracting the big number will lead to a overflow that results in a small Number. Let's for a moment assume that we only have 8 bits. If storedTimeStamp = 255 and currentMillis is already very small, lets say 10.
Now we calculate 10 - 255. it will overflow to the result 11.
I just tried it by running the code:
Serial.begin(9600);
byte x = 10 - 255;
Serial.print(x,DEC);
@@playduino Ah. I wasn't sure how Arduino handled types in conditional expressions, but it does look like it remains unsigned and overflows correctly. This is not always the case. Evaluating the difference of 2 unsigned types within a conditional can return a signed negative value on other platforms. Looks like you are safe to deploy after all. ;)
interesting. I assume as soon as one of the numbers in signed, the result will also be signed. Yeah all good, lets get this power plant up and running :D
You need to create a class so you can make timers without writing more code that is the same for each now timer.
Do you mean functions? I will talk about functions in 2 weeks. They are a great way to reduce code duplication
I have a classy example for you who would you like to send it to you, I can put it on drop box for you to pick up @@playduino
@@playduino I think he means class, such as a "task" class.
@@Enigma758 ah, I see. @longdarkrideatnight it would be awesome if you could share the example you mentioned in the message that I currently cant see for some reason
// Blink an LED on PA2 on an ATTiny1614 MCU
// Pin definitions
// Important - always use the full pin definition i.e. PXn where X is the port letter and n the pin number
const int ledPinRed = PIN_PA2;// Pin 2 Port A
const int ledPinBlue = PIN_PB1;// Pin 1 Port B
// Variable definitions
unsigned int A = 888; //dividend
unsigned int B = 444; //divisor
unsigned int C = 666; //dividend
unsigned int D = 222; //divisor
void setDefaultPinStates() {
pinMode(ledPinRed, OUTPUT); //set as output
pinMode(ledPinBlue, OUTPUT); //set as output
digitalWrite(ledPinRed,HIGH); //start with LED off
digitalWrite(ledPinBlue,HIGH); //start with LED off
}
void setup() {
setDefaultPinStates();
delay (1000);
}
void loop() {
/*
Flash the LEDs on PA2 & PB1 with a single line of code.
The remainder of millis divided by A is compared to B
and when greater the result is 1 and when less is 0, this binary result
is written to the appropriate ledPin
*/
digitalWrite(ledPinRed, millis() % A > B);
digitalWrite(ledPinBlue, millis() % C > D);
}
digitalWrite(ledPinRed, millis() % A > B)
looks like a very interesting way to get blinking patterns, thanks for sharing
Not my idea I discovered to concept from ruclips.net/video/foiqs-rNHig/видео.html@@playduino