Arduino interupt a delay function - loops

in my next project i use 4 Leds with delay(10000). I need a function for cancel this loop and start again with a new delay value e.g. 100.
I have enabled interrupts and when i pressed a button, delay changed to 100 AFTER a round. I have to wait 10 seconds.. It is possible to restart the loop function with the new values?

Wow that was rude ignacio
At least be helpful.
You can do this but not as you have implemented.
Delay is not good to be used in this circumstance. A much better way of implementing is to use a while loop like this:
int delayLED = 10000;
int beginMillis = millis();
while( millis() - beginMillis < delayLED)
{
// insert the code for your "interrupt" here
// kinda like this
if(button pressed)
{
delayLED = 100;
break;
}
}
This is just a template not a complete answer.
Let me know if you have further questions.
Happy coding!

Related

What should I do for stop the loop at the background when I am not pressing the button?

I am new here ,sooo sorry for the mistakes :P.
So whatever. I am trying to do a simple counter circuit with Arduino UNO, a catot 7-segment display and a button. I just want to when I press the button system circle start and takes one footstep. For example 7-segment shows "0" from earlier push, when ı push the button it needs to be "1". But ıdk why its keep counting from background and I couldn't stop it. Then I make some adjustments in my code( btw ı am coding in micro-c for AVR and using AVRDUDES for load my code in Arduino.) and then its stuck at "F" (System should count like 1,2,3,4,5,6,7,8,9,A,b,c,d,E,F). I don't understand why and how can I solve it. Additionally 7 segment led connected with my D port. I want to do B0 pin is input. Then I want to control the B0 pin's value. When B0 pin is HİGH, then i want to program continue.
unsigned char dizi[] = {0x40,0xF9,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x27,0x21,0x06,0x0E};
unsigned int i ;
void main()
{
DDRD = 0xFF ;
DDB0_bit = 0 ;
while(PINB.B0);
{
for(i = 0;i<=15;i++)
{
PORTD = dizi[i] ;
Delay_ms(700);
}
}
}
I just write the code and just ıdk ı hope it work. But it didn't. Idk why and my mind is so blurry ı can't see the error. I hope u can help :D.
What are you using to program your Arduino?
The loop never stops after you press the button because you don't have a stop condition aside from i reaching 15. I'm rusty on Arduino but you could add
if(!(PINB.B0)){ break; }
in the for loop, after the delay to exit the loop when you're not pressing the button.
Your program needs to work like this:
for(;;) { /* program here */ } Microcontroller programs never leave main().
You need to read the button and then debounce it. This should be mentioned in any embedded systems beginner tutorial. Debouncing is mandatory whenever you have a button, or the program will just behave randomly, sometimes missing keyboard presses, other times taking several at once etc.
(The most proper way to do this is to read the button repeatedly from a timer callback, but then you need to write the code for the timer/RTC hardware peripheral driver first.)
Once you have a debounced signal pressed/not pressed, then implement a simple state machine like in this pseudo code:ish C below:
typedef enum
{
NOT_PRESSED,
PRESSED_UPDATE_DISPLAY,
PRESSED_STILL_DISPLAYED,
} simple_state_machine_t;
simple_state_machine_t state = NOT_PRESSED;
...
int index_7seg = 0;
for(;;)
{
/* debounce button */
bool is_pressed = debounced_value;
switch(state)
{
case NOT_PRESSED:
state = is_pressed ? PRESSED_UPDATE_DISPLAY : NOT_PRESSED;
break;
case PRESSED_UPDATE_DISPLAY:
index_7seg++;
if(index_7seg == max_7seg)
{
index = 0;
}
state = is_pressed ? PRESSED_DISPLAYED : NOT_PRESSED;
break;
case PRESSED_DISPLAYED:
state = is_pressed ? PRESSED_DISPLAYED : NOT_PRESSED;
break;
}
PORTD = the7seg_table[index_7seg];
} /* for(;;) */
The PRESSED_UPDATE_DISPLAY state will only get entered when you go from not pressed to pressed, essentially giving you a rising edge trigger through software. That's the only time you should increase the table index.

How to force interrupt to restart main loop instead of resuming? (timing issue!)

For the last two days i wrote a program that in basic terms generates a fairly accurate user adjustable pulse signal (both frequency and duty cycle adjustable). It basically uses the micros() function to keep track of time in order to pull low or high the 4 digital output channels.
These 4 channels need to have a phase difference of 90 degrees (think a 4cyl engine) always. In order for the user to change settings an ISR is implemented which returns a flag to the main loop to re-initialise the program. This flag is defined as a boolean 'set4'. When it is false a 'while' statement in the main loop will run the outputs. When it is true an 'if' statement will perform the necessary recalculations and reset the flag so that the 'while' statement will resume.
The program works perfectly with the initial values. Phase is perfect. However when the ISR is called and comes back to the main loop, from how i understand it resumes the program in the 'while' statement from where was originally interrupted, until it finishes and re-checks the flag 'set4' to see it is now true and it should stop.
Then, even though the 'if' statement afterwards resets and re-calculates all the necessary variables the phase between these 4 output channels is lost. Tested manually i see depending on which time the ISR is called it will give different results, usually having all 4 output channels synchronised together!
This happens even though i might don't change any values (thus the 'if' routine resets the variables to exactly the same ones when you first power up the arduino!). However, if i comment out this routine and just leave the line which resets the flag 'set4' the program will continue normally like nothing never happened!
I'm pretty sure that this is somehow caused because of the micros() timer because the loop will be resumed from where the ISR was called. I've tried to do it differently by checking and disabling for interrupts using cli() and sei() but i couldn't get it to work because it will just freeze when the arguments for cli() are true. The only solution that i can think of (i've tried everything, spend the whole day searching and trying out stuff) is to force the ISR to resume from the start of the loop so that the program may initialize properly. Another solution that comes to mind is to maybe reset the micros() timer somehow..but this would mess up the ISR i believe.
To help you visualise what is going on here's a snip of my code (please don't mind the 'Millis" name in the micros variables and any missing curly brackets since it is not pure copy-paste :p):
void loop()
{
while(!set4)
{
currentMillis = micros();
currentMillis2 = micros();
currentMillis3 = micros();
currentMillis4 = micros();
if(currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
{
interval = ONTIME;
ledState = HIGH;
}
else
{
interval = OFFTIME;
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
.
.
//similar code for the other 3 output channels
.
.
}
if (set4){
//recalculation routine - exactly the same as when declaring the variables initially
currentMillis = 0;
currentMillis2 = 0;
currentMillis3 = 0;
currentMillis4 = 0;
//Output states of the output channels, forced low seperately when the ISR is called (without messing with the 'ledState' variables)
ledState = LOW;
ledState2 = LOW;
ledState3 = LOW;
ledState4 = LOW;
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
//ONTIME is the HIGH time interval of the pulse wave (i.e. dwell time), OFFTIME is the LOW time interval
//Note the calculated phase/timing offset at each channel
interval = ONTIME+OFFTIME;
interval2 = interval+interval/4;
interval3 = interval+interval/2;
interval4 = interval+interval*3/4;
set4=false;
}
}
Any idea what is going wrong?
Kind regards,
Ken
The problem is here:
previousMillis = 0;
previousMillis2 = 0;
previousMillis3 = 0;
previousMillis4 = 0;
All if statement will be true on the next loop.
Try with:
previousMillis = micros();
previousMillis2 = micros();
previousMillis3 = micros();
previousMillis4 = micros();

Do something, but check if button is clicked all the time

I have a arduino i want to blink some led light if the button is not clicked. Here is the code.
void startup(){
for (int x=0; x<=1;){
BUTTON5_state = digitalRead(START_BUTTON);
if (BUTTON5_state == HIGH ){
x++;
}
else{
blinkAll(1, 2000);
continue;
}
The problem is that its not checking the button often enough. The blink all 500 is waiting 2 seconds between each time it blinks. So you need to hold the button down for to seconds.
I want the light to blink every 2 second, but check the button "all the time". Is this possible?
Have you checked the "Blink Without Delay" tutorial in the Arduino IDE? Well, that's what you want to implement. Instead of using a delay (which is blocking) you poll the button as fast as possible and then, if millis() says that enough time has passed, you can blink.
delay is used when you want to wait; if you want to do something use other techniques.
An alternative is to use interrupts, but i suggest you to go with the first method...
2 possible solutions: create a thread, which checks the button and the original thread let the led blink. or you do the for loop faster and toggle the led only each 1000th iteration or so.
for example something like this:
for (int x=0; x<=100000;x++){
//wait to make the 1024 iteration blinking visible
BUTTON5_state = digitalRead(START_BUTTON);
if (BUTTON5_state == HIGH ){
break;
}
else if (x & (1 << 10)){ //each 1024th iteration
toggleLed();
}
}

Making a delay in C with 20MHz crystal(beginner level)

I've recently started with C and Im trying to figure out how to make a 10ms delay for
PIC16F884. From the formulas in the datasheet I've managed to create the following:
fosc = 20MHz and Toscx4 = 200ns
If I put a preset to 100 => t=100x200ns=20us and to get a 10 ms delay
10ms/20us = 500
Will the following code in C give me what Im looking for (10ms delay)? Assume I have all the initiating code and variables.
void interrupt ISR(void){
if(TMR0IF){
TMR0IF=0;
counter++;
}
if(counter==100){
delay++;
counter=0;
}
}
int main(void){
TMR0=155;
if(delay>4){
//any code
delay=0;
}
}
Might be a bad example but hopefully you understand
No, since the code in main() never actually waits, it won't implement a delay.
Assuming the interrupt and timer logic is properly set up, you're still going to need to loop:
delay = 0;
TMR0 = 155; /* Start timer. */
while(delay < 4)
; /* Do nothing */
/* More code here, delay has expired */
Also, remember to make delay a volatile variable since you're accessing it from multiple parallel threads of execution.
If you're a really beginner and want a tool that can help you calculate timer settings I advise you to look at this link :
http://www.mikroe.com/timer-calculator/
It generate the ccode for settiing properly a lot of different microcontroller

Delay using timer on raspberry pi

I need to create a accurate delay (around 100us) inside a thread function. I tried using the nanosleep function but it was no accurate enough. I read some post about how to read the hardware 1MHz timer, so on my function in order to create a 100us delay y tried something like this:
prev = *timer;
do {
t = *timer;
} while ((t - prev) < 100);
However, the program seems to stay inside the loop. But if I insert a small nano sleep inside the loop it works (but loosing precision):
sleeper.tv_sec = 0;
sleeper.tv_nsec = (long)(1);
prev = *timer;
do {
nanosleep (&sleeper, &dummy);
t = *timer;
} while ((t - prev) < 500);
I tried the first version in a stand along program and it works, but in my main program, where this is inside a thread it does not.
Does anyone know what the first version (without a small nanosleep) does not work?
I'm sorry to say but Raspberry Pi's OS is not a "real-time OS". In another words, you won't get consistent 100us precision in a user space program due to inherent OS scheduling limitations. If you need that kind of precision, you should use an embedded controller like an Arduino.

Resources