#include #include static const code unsigned char digits[10] = { 0x5F, /* 0 */ 0x06, 0x3B, 0x2F, /* 3 */ 0x66, 0x6D, 0x7D, 0x07, /* 7 */ 0x7F, 0x6F, }; static const code unsigned char wave[] = { 1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1 }; #define TOUT 0x10 // watchdog timeout bit in STATUS #define XTAL 4000000 // crystal freq #define PRE 4 // prescaler value #define INTVL 1000u // 1000uS (1mS) per loop #define DIVIDE (XTAL/PRE/INTVL/4) // division ratio - must be < 256 #define SECS(x) ((x)*1000000/INTVL/21) // convert secs to outer loop count #define DEBOUNCE 10 // debounce 10mS #define COUNT 40 // this many debounce intervals to do something #define CYCLES sizeof(wave) // this many cycles per "tick" #define PWRDOWN 30 // power down time persistent static unsigned char rate; // current rate static bit btn_1, btn_2; // push buttons static bit spkr; // speaker bit static bit counting; // we are counting up or down static bit fast; // we are counting fast! static bit display; // display on main() { unsigned char digcnt, // digit counter segcnt, // segment counter debounce, // debounce timer button, // button press timer cntcnt, // counter timer for speed up beep_cnt, // beep timer curval; // current value unsigned int tick_cnt, // delay timer powerdown, // powerdown timer tock_cnt; // tick-tock reload value OPTION = 1; PORTA = 0x0F; // set all bits high TRISA = ~0x0F; // bits 0-3 are output PORTB = 0x80; // set bits low TRISB = ~0x7F; // bits 0-6 are output PORTA &= ~3; // enable both buttons btn_1 = 0; btn_2 = 0; if((STATUS & TOUT)) { // power on-reset? rate = 60; // initialize rate beep_cnt = CYCLES; display = 1; powerdown = SECS(PWRDOWN); } else { // watchdog reset if(PORTB & 0x80) { // no buttons pressed - back to sleep TRISA = 0xFF; // hi-Z all pins TRISB = 0xFF; OPTION = 0xB; // WDT prescaled by 8 - about 150 ms asm(" sleep"); } display = 1; powerdown = SECS(PWRDOWN); } spkr = 0; debounce = 0; button = 0; counting = 0; tock_cnt = (unsigned)(60*1000000/INTVL)/rate; tick_cnt = tock_cnt; for(;;) { if(powerdown) if(--powerdown == 0) { display = 0; if(!spkr) { TRISA = 0xFF; // hi-Z all pins TRISB = 0xFF; OPTION = 0xB; // WDT prescaled by 8 - about 150 ms asm(" sleep"); } } curval = rate; digcnt = 0; do { segcnt = 1; // least sig. segment do { asm(" clrwdt"); while((RTCC & 0x80) == 0) // sync with RTCC continue; if(beep_cnt && wave[--beep_cnt]) PORTA ^= 0x8; // toggle speaker bit while(RTCC & 0x80) continue; RTCC = -DIVIDE; // reprogram RTCC if(--tick_cnt == 0) { tick_cnt = tock_cnt; if(spkr) beep_cnt = CYCLES; } if(beep_cnt && wave[--beep_cnt]) PORTA ^= 0x8; // toggle speaker bit PORTA |= 0x7; // all digits off PORTA &= ~(1 << digcnt); // enable one digit PORTB = 0x80; // all segments off if(display) PORTB |= segcnt & digits[curval % 10]; // convert digit to seg pattern segcnt <<= 1; if(digcnt == 0 && !btn_2) { // scan button 1 if((PORTB & 0x80) == 0) { if(!btn_1) { debounce = 0; button = 0; cntcnt = 0; fast = 0; } btn_1 = 1; if(++debounce == DEBOUNCE) { debounce = 0; button++; } display = 1; powerdown = SECS(PWRDOWN); } else { if(!counting && btn_1 && button > 1 && button < COUNT/3) spkr = 0; btn_1 = 0; button = 0; } } else if(digcnt == 1 && !btn_1) { // scan button 2 if((PORTB & 0x80) == 0) { if(!btn_2) { debounce = 0; button = 0; cntcnt = 0; fast = 0; } btn_2 = 1; if(++debounce == DEBOUNCE) { debounce = 0; button++; } display = 1; powerdown = SECS(PWRDOWN); } else { if(!counting && btn_2 && button > 1 && button < COUNT/3) spkr = 1; btn_2 = 0; button = 0; } } if(button >= COUNT/3) { if(fast) { if(btn_1) rate -= 10; else rate += 10; } else { if(btn_1) rate--; else rate++; if(++cntcnt == 5) fast = 1; } if(rate < 10) rate = 10; if(rate > 200) rate = 200; counting = 1; button = 0; } } while(!(segcnt & 0x80)); if(counting && !btn_1 && !btn_2) { tock_cnt = (unsigned)(60*1000000/INTVL)/rate; counting = 0; } curval /= 10; } while(++digcnt != 3); } }