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

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();
}
}

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.

Using CCS Toggle LED With Button

I didn't understand what is wrong with my code. Here what I am trying to do is toggle a led when I press button. And I count my button hits with int count;.
If the count number is even LED is high and else LED is low. But when I upload this program, LED stays on. And off only while I hold the button.
while(1){
int buttonState=input_state(pin_a0);
if(buttonState != lastButtonState){
count++;
lastButtonState=buttonState;
if(count%2==0){
output_high(pin_b0);
}
else
output_low(pin_b0);
}
delay_ms(50);
}
There is a problem in your logic. You have two changes while pressing the button. The first change is from 0 to 1 (pressing) and the second change is from 1 to 0 (releasing the button).
Try something like:
if(lastButtonState == 0 && buttonState == 1)
Is your button active-high or active-low ? Is your LED powered active-high or active-low? You need to give that information.
I'll give an explanation assuming LED is powered when output is low. Then what follows is, assuming button is active-low, when your button is not pressed,
buttonState = 1;
So, since
lastButtonState = 0;
(at the start of the program, I'm assuming)
You will enter the if clause:
if(buttonState != lastButtonState){
...
}
This will increase your counter by one and make lastButtonState = buttonState;
Since count%2 will be 1, your pin will be output_low(pin_b0);... So, at the start of your program, your LED will be ON.
If you then press the button,
buttonState=0;
will happen and you will enter the if() clause, again. This will increase your counter by one. And then:
count%2 = 0;
Will happen. So, you will have
output_high(pin_b0);
As you can see, when you press the button, your LED will go off. And on when you release the button, your LED will go on Try this:
while(1){
int buttonState=input_state(pin_a0);
if(buttonState != lastButtonState){
lastButtonState=buttonState;
if(buttonState == 1){
output_high(pin_b0); // LED is off
}
else
output_low(pin_b0); // LED is on
}
delay_ms(50);
}
You don't need the counter.
EDIT:
I see you have made this addition to your code:
if(buttonState==1)
count++;
This works. Yet is harder to understand. Try writing something easier to read.

how to stop looping and wait until different value received from serial

hi i planning to made a multiple servo controlling with serial as control trigger signal on AVR with C and codevision
but when the trigger is true, the servo running in crazy loop, it back to original position (0 degree) instead of stay on desired position, my tutor give me hint to use "wait ... until" statement with the old data comparison but i'm not found the way to utilize it yet on google
because utilizing break; at the end of the if left the chip freeze until it reset
and the old code(it runs the servo forth and back continously)
while (1)
{
while(UCSRA & (1<<RXC))
{
// Place your code here
//data=UDR;
PORTC=UDR;
data=UDR;
//PORTB=data;
} ;
if (data== 0x0A || data== 0x0B)
{
if (data== 0x0A)
{
old_data=data;
PORTA=0x00;
PORTA.1=1;
movservo0(90,7);
movservo1(15,3);
}
if (data== 0x0B)
{
old_data=data;
PORTA=0x00;
PORTA.1=1;
movservo0(15,3);
movservo1(90,7);
}
}
}
as for movservo0 (another movservo() almost had same code)
void set_servo1(unchar derajat)
{ unchar n;
servo2=1;
delay_us(750);
for(n=0; n<derajat; n++)
{
delay_us(12);
};
servo2=0;
delay_ms(10);
}
void movservo0(unsigned char sudut, unsigned char speed)
{
unchar i;
set_servo1(sudut);
for (i=1;i<=sudut;i+=speed){
set_servo1(i);
delay_ms(100/speed);
}
}
This new code is a bit better.
The top of the while(UCSRA & (1<<RXC)) loop is fine this way. The loop body will only be entered if there is a character to be read. (Although, I'm not sure why you are expecting to read '\n' or vertical tab.)
A minor problem is the way the UDR is read. The act of reading UDR erases the contents. So you should be using
data=UDR;
PORTC=data;
The jumping of the servos appears to be in the moveservo() function. This function always sets the angle to 1 and then gradually increases the angle of the servo until it reaches the desired angle.
setservo() appears to be an attempt to perform PWM to drive a servo, but it doesn't work correctly. To keep the servo at a desired angle, you have to keep switching the pin from 0 to 1 at the correct times, not just once like this function does. Have you looked at the PWM functions of the timers? You just set these up and they run in the background. An alternative is to use a timer to set an interrupt to wake up and toggle the pins as you need.
If you want to do the switching of the pins without interrupts, then you should be using delays in the while(1) loop itself. Just use the setservo() functions to change some variables.
while(1)
{
// read the UART if ready and set the target values
// this part only runs occasionally
while(UCSRA & (1<<RXC))
{
// etc
}
// The rest of the loop body runs every time
// adjust the servo values toward the target values
// use a counter to determine if to adjust during this loop iteration
// e.g., a slow speed counts to a higher number before adjusting
delay(750);
for(int i = 0; i < NUM_INTERVALS; ++i)
{
// decide whether to set pins to 1 or 0 based on the servo values
delay(INTERVAL);
}
}
I don't know about your particular servos, but they typically have a period where most of the time the pin is 0, and then a short time in the period where the pin is 1. You will need to adjust NUM_INTERVALS and INTERVAL and 750 to add up to the correct length of time.
There is so much wrong with this snippet, it is hard to start. It is difficult to say why the servo is moving, as it is only ever "moved" to the same value every time. (Unless, you have omitted some code that sets it to some other value.)
Typically, when receiving UART, the processor should wait until the character is received. This is accomplished by this
while(UCSRA & (1<<RXC) == 0);
Note the ; creating an empty body of the while loop. This is probably what your tutor meant. When the flag is set, then the loop exits and the data is ready to be read.
while(UCSRA & (1<<RXC) == 0);
data = UDR;
Next, you have a block which looks like you meant to be part of a while loop, but it isn't. The body of the loop is the single statement abbove it. The block gets executed every time.
{
if(data=0x0a)
{
olddata=data;
movservo0(90,7); //move servo to certain degree
}
}
Another error is the condition in the if statement. It looks like you are trying to test if data is 0x0A, but that is not what is happening. Instead, you set data to be 0x0A, and then execute the inner part every time. The condition you probably want is if(data == 0x0A). Note the == instead of =.
So your code is equivalent to
while(1)
{
while(ucsra & (1<<RXC)) data=udr; // maybe read UDR into data
data=0x0a; // set data anyway
olddata=data;
movservo0(90,7); //move servo to certain degree
}
Again, for the jumping servo, I suspect some code that is omitted here that is also runs every time. Or else, the moveservo() function has a problem itself.

Arduino interupt a delay function

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!

Does this sound like a stack overflow?

I think I might be having a stack overflow problem or something similar in my embedded firmware code. I am a new programmer and have never dealt with a SO so I'm not sure if that is what's happening or not.
The firmware controls a device with a wheel that has magnets evenly spaced around it and the board has a hall effect sensor that senses when magnet is over it. My firmware operates the stepper and also count steps while monitoring the magnet sensor in order to detect if the wheel has stalled.
I am using a timer interrupt on my chip (8 bit, 8057 acrh.) to set output ports to control the motor and for the stall detection. The stall detection code looks like this...
// Enter ISR
// Change the ports to the appropriate value for the next step
// ...
StallDetector++; // Increment the stall detector
if(PosSensor != LastPosMagState)
{
StallDetector = 0;
LastPosMagState = PosSensor;
}
else
{
if (PosSensor == ON)
{
if (StallDetector > (MagnetSize + 10))
{
HandleStallEvent();
}
}
else if (PosSensor == OFF)
{
if (StallDetector > (GapSize + 10))
{
HandleStallEvent();
}
}
}
this code is called every time the ISR is triggered. PosSensor is the magnet sensor. MagnetSize is the number of stepper steps that it takes to get through the magnet field. GapSize is the number of steps between two magnets. So I want to detect if the wheel gets stuck either with the sensor over a magnet or not over a magnet.
This works great for a long time but then after a while the first stall event will occur because 'StallDetector > (MagnetSize + 10)' but when I look at the value of StallDetector it is always around 220! This doesn't make sense because MagnetSize is always around 35. So the stall event should have been triggered at like 46 but somehow it got all the way up to 220? And I don't set the value of stall detector anywhere else in my code.
Do you have any advice on how I can track down the root of this problem?
The ISR looks like this
void Timer3_ISR(void) interrupt 14
{
OperateStepper(); // This is the function shown above
TMR3CN &= ~0x80; // Clear Timer3 interrupt flag
}
HandleStallEvent just sets a few variable back to their default values so that it can attempt another move...
#pragma save
#pragma nooverlay
void HandleStallEvent()
{
///*
PulseMotor = 0; //Stop the wheel from moving
SetMotorPower(0); //Set motor power low
MotorSpeed = LOW_SPEED;
SetSpeedHz();
ERROR_STATE = 2;
DEVICE_IS_HOMED = FALSE;
DEVICE_IS_HOMING = FALSE;
DEVICE_IS_MOVING = FALSE;
HOMING_STATE = 0;
MOVING_STATE = 0;
CURRENT_POSITION = 0;
StallDetector = 0;
return;
//*/
}
#pragma restore
Is PosSensor volatile? That is, do you update PosSensor somewhere, or is it directly reading a GPIO?
I assume GapSize is rather large (> 220?) It sounds to me like you might have a race condition.
// PosSensor == OFF, LastPosMagState == OFF
if(PosSensor != LastPosMagState)
{
StallDetector = 0;
LastPosMagState = PosSensor;
}
else
{
// Race Condition: PosSensor turns ON here
// while LastPosMagState still == OFF
if (PosSensor == ON)
{
if (StallDetector > (MagnetSize + 10))
{
HandleStallEvent();
}
}
else if (PosSensor == OFF)
{
if (StallDetector > (GapSize + 10))
{
HandleStallEvent();
}
}
}
You should cache the value of PosSensor once, right after doing StallDetector++, so that in the event PosSensor changes during your code, you don't start testing the new value.
This is definitely not stack overflow. If you blew the stack (overflowed it) your application would simply crash. This sounds more like something we used to call memory stomping in my C++ days. You may not be accessing the memory location that the StallDetector value occupies via StallDetector variable alone. There may be another part of your code "stomping" this particular memory location erroneously.
Unfortunately, this kind of issue is very hard to track down. About the only thing you could do is systematically isolate (remove from execution) chunks of your code until you narrow down and find the bug.
Do you have nest ISRs on your system? Could be something along the lines of start your ISR and increment your count, then interrupt it and do it again. Do this enough times and your interrupt stack can overflow. It could also explain such a high counter variable as well.
Does HandleStallEvent() "look at" StallDetector within the ISR or does it trigger something on the main loop? If it's on the main loop, are you clearing the interrupt bit?
Or are you looking at StallDetector from a debugger outside the ISR? Then a retriggered interrupt would use the correct value each time, but execute too many times, and you would only see the final, inflated value.
On second thought, more likely you don't have to clear an interrupt-generating register, but rather the interrupt pin is remaining asserted by the sensor. You need to ignore the interrupt after it's first handled until the line deasserts, such as by having the original ISR disable itself and and reinstall it in a second ISR which handles the 1->0 transition.
You might then also need to add debouncing hardware or adjust it if you have it.
Check your parameter types. If you defined the parameters in a way different than the caller expects then calling your method could overwrite the space that variable is stored in. (For instance if you wrote the function expecting an int but it is pushing a long onto the stack.)
You could see what additional options your debugger supports. In Visual Studio, for example, it is possible to set a "data breakpoint", where you break when a memory location changes (or is set to a certain value, or above a threshold, ...).
If something like this is possible in your case, you could see where the data is changed and if there is someone else writing to the memory erroneously.

Resources