### You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Problem having button push polling switch modes properly

 December 07, 2012 by adosch I'm having a slight logical dilemma with some code I am working with to try and make an LED lamp that switches lighting modes (low, bright, fade) with a momentary push button. Right now I'm using infinite loop polling just to rough out the logic, but I can't see past my error. For whatever reason, I'm fighting with the logic that happens on button push to change the mode. I've tried making my 3-bit shifting logic (2^1 was mode-1, 2^2 was mode-2 and 2^3 was mode 3) or by setting 3 directives and just switching between. I'm using an attiny2313; PB2 and PB3 have the two LEDs, and PD6 is where the push-button. Posted below is my simplified logic; I was fooling around to handle the button debounce better, but I've it out for simplicity sake: ``````#define F_CPU 1000000UL #include #include #define MODE1 1 #define MODE2 2 #define MODE3 3 // Initialize micocontroller settings void init_avr(void) { DDRB |= (1 << PB2); DDRB |= (1 << PB3); DDRD &= ~(1 << PD6); // Turn on the internal resistors for the pins for PB1, PB2 and PB3 PORTD |= (1<= 0) { OCR0A=pwm--; OCR1A=pwm--; _delay_ms(25); // Delay 2 millisecond } _delay_ms(150); // Delay 100 millisecond } void run_mode(uint8_t mode) { if (mode == MODE1) { do_mode1(); } else if (mode == MODE2) { do_mode2(); } else if (mode == MODE3) { do_mode3(); } else { do_mode1(); } } int main(void) { uint8_t mode = MODE1; init_avr(); while(1) { if (bit_is_clear(PIND, 6)) { mode = switch_mode(mode); run_mode(mode); } } } `````` ... (continued)I should have noted what issues I am experiencing (my apologies). After I write my flash my image to the AVR, mode-1 doesn't show at the brightness at it should that I have set in do_mode1(). Then when I push the button to rotate through the modes, I go straight to mode-3 and it's infinitely suck there, I get no more functionality out of the push-button. There are 2 problems that are stopping your program from working how you want it to. 1 - In the function "switch_mode" there is no wrap around back to mode1. (Note the last if statement you are using there...) 2 - you are looking for the "button being pressed", but that is only 1/2 of the event that you are looking for. Since you are NOT looking for the button to be released it just continuously processes a "button being pressed event". What you really want to be doing is to "process a button pressed event" and then you want to "wait for the button release event" before you process the next "button pressed event"... Those are the 2 initial problems that need to be remedied. I don't use the built-in PWM stuff for anything I do, but what you are doing there doesn't look quite right to me... I am also NOT a fan of using the "delay_ms()" function quite so rampantly. Using that function with large values creates "program stutters" and also limits how you should be viewing programs. (Programs should be viewed as a series of conditions, events, and actions...) If you go to the library and look for "Safety double tap routine with pushbutton" that should provide some additional insight. If you want to look at the whole discussion then look at this link: double tap discussion (The whole discussion would explain alot to you I think...) JimFrederickson, Thanks for the reply. That code block from 33-43 (e.g. switch_mode() ) was a typo; I was initially testing just MODE1 and MODE2 and forgot to change that back when adding my source code out here. So yes, I did have a wrap back to MODE1. As for the PWM portions, it looks pretty good to me from the datasheet point of view on how to setup and use. Raising and lowering values from OCR[10]A to adjust the forward voltage over the LED to adjust the 'brightness' level works well. I did find my problem, which is exactly what you described as 'stuttering' --- when I isolated my modes to static ORC[01]A values only (not using that loop business in do_mode3() ) in all three modes, I saw it. Only when I decided to take that PWM loop-over I was doing did I finally figure out what was happening; it was very unstable and jerky when trying to find that button switch while polling. After reading through that 'double tap discussion', I drew a personal conclusion that polling is quite the hack for button press-down/up; I spent that latter half of the afternoon trying to work polling logic and I found it much easier to set an external interrupt request on INT0 (PD2) and look for the rising/falling edge from that pin change (as opposed to using PCINT and not having that functionality). The actual switching between my LED 'brightness' modes isn't as 'smooth' as I want to, but it's MUCH improved now using an interrupt. It seems I have to have the button pressed in for ~0.5-1sec to get it to be smooth change from mode to mode. I'll work on that. Below is a snip from my new code I have now: ``````SIGNAL (SIG_INT0) { mode = switch_mode(mode); run_mode(mode); } // Initialize micocontroller settings void init_avr(void) { DDRB |= (1 << PB2); DDRB |= (1 << PB3); DDRD &= ~(1 << PD2); PORTD |= (1<