/* * ATmega16_BUTTON_13519_2358.c * Runs with 1MHz internal RC-oscillator * No delay-loops! * gcc-Compiler Optimization is most -O3 * Need 414Bytes FLASH, 4Bytes RAM * Need ca. 61 clock cycles (ca. 60us/MHz) * Need minimal 0.5 to 6.5ms@1MHz for return a valid BUTTON state after DEBOUNCING * * The routine getValidButton() returns 4Bit about BUTTON behaviour in a valid state * * Bit1 and Bit0 describes how is the actual state of the BUTTON: * * Bit0 == 0 BUTTON is valid stable * Bit0 == 1 BUTTON has valid changed * * Bit1 == 0 BUTTON is valid OFF * Bit1 == 1 BUTTON is valid ON * * Bit3 and Bit2 describes how long is the BUTTON valid stable ON or OFF: * * buttonTimeTH[] = {3000, 11000, 60000} describes the limits for different behaviour (0.2s , 1s , 6s) * 00 time <= buttonTimeTH[0] * 01 buttonTimeTH[0] < time <= buttonTimeTH[1] * 10 buttonTimeTH[1] < time <= buttonTimeTH[2] * 11 buttonTimeTH[2] < time * * Created: 01.05.2013 12:49:36 * Author: 25mmHg */ #define BUTTONPIN (1<<7) #define LEDPIN (1<<6) #define BIT0 (1<<0) #define BIT1 (1<<1) #define BIT2 (1<<2) #define BIT3 (1<<3) #include const uint8_t countMAX = 15; // DEBOUNCE MAX must be below uint8_t overflow (try 8 to 255) const uint8_t countTH = 8; // DEBOUNCE Threshold for valid BUTTON (try 4 to 128) const uint16_t buttonTimeTH[] = {3000, 11000, 60000}; // ca. 0,2s, 1s, 6s threshold uint8_t getRealButton(){ return !(PIND & BUTTONPIN); // if BUTTON short the PORT-Pin to LOW returns 1 } uint8_t getValidButton(){ static uint8_t validButton; // validButton at startup static uint8_t count; // count for DEBOUNCING static uint16_t stableButtonTime; // how long the Button is stable? // Copy last stableButtonTime to validButton Bit3 and Bit2 uint8_t i = 0; do{ validButton |= (i<<2); // set Bit3 or Bit2 validButton &= (~(BIT3 | BIT2) | (i<<2)); // clear Bit3 or Bit2 i++; } while((buttonTimeTH[i-1] < stableButtonTime) && (i <= 3)); // DEBOUNCING: Test realButton and LowPass if(getRealButton()){ if (count < countMAX){ count++; // Button pressed? increment to MAX } } else if(count > 0){ count--; // Button released? decrement to 0 } // DEBOUNCING: update stableButtonTime, comparator with hysteresis copy to validButton Bit1 and Bit0 if((count > countTH) && !(validButton & BIT1)){ // validButton has changed: rising @ countTH after last state wars OFF count = countMAX; // make hysteresis stableButtonTime = 0; validButton |= BIT0; // validButton has changed -> set Bit0 validButton |= BIT1; // validButton has changed and is now ON -> set Bit1 } else if((count < countTH) && (validButton & BIT1)){ // validButton has changed: falling @ countTH after last state wars ON count = 0; // make hysteresis stableButtonTime = 0; validButton |= BIT0; // validButton has changed -> set Bit0 validButton &= ~BIT1; // validButton has changed and is now OFF -> clear Bit1 } else if(count == 0 || count == countMAX){ validButton &= ~BIT0; // validButton is valid stable -> clear Bit0 if(stableButtonTime < ~0){ // to prevent overflow stableButtonTime++; } } // If You need an DEBUG-OUTPUT: set StatusLEDs for Bit0, Bit1, Bit2, Bit3 on PORTA connected to Vcc PORTA = ~validButton; // OUTPUT: Mask Bits4,5,6,7 (spare for another Button next) and return the BUTTON behaviour return (validButton & (BIT3 | BIT2 | BIT1 | BIT0)); } int main(void){ DDRD &= ~BUTTONPIN; // PORTD BUTTONPIN = INPUT DDRD |= LEDPIN; // PORTD LEDPIN = OUTPUT PORTD |= BUTTONPIN; // PORTD PULL-UP DDRA |= BIT3 | BIT2 | BIT1 | BIT0; // If You need an DEBUG-OUTPUT: PORTA StatusBitLEDs = OUTPUT while(1){ //Examples, try more variants //uint8_t temp = getValidButton(); if ((temp < 12) && (temp & ~(BIT2 | BIT3)) == 1){ // validButton ON -> OFF for short and long pressed BUTTON with timeout 6s //if (getValidButton() == 3){ // validButton fast double-click like PC-mouse (<0,2s) //if ((getValidButton() & ~(BIT2 | BIT3)) == 3){ // validButton OFF -> ON simple variant ignore time //if ((getValidButton() & ~(BIT2 | BIT3)) == 1){ // validButton ON -> OFF simple variant ignore time if (getValidButton() == (BIT3 | BIT0)){ // validButton ON -> OFF for long pressed BUTTON (> 1s)with timeout 6s PORTD ^= LEDPIN; // Put your switched Code here! (writing on PINB toggles the pin also on some AVRs) } // Put non switched code here! } }