/* * file : dymoclock.c * project : Simple LED clock with thermometer * author : Bruno Gavand * compiler : mikroC V6.0.0.0 * date : september 15, 2006 * * description : * This is a 12 hours clock with 27 LEDs display, with a 2°C resolution thermometer * * target device : * PIC16F819 with 16 Mhz crystal * * configuration bits : * HS clock * no watchdog * no power up timer * RA5 as MCLR pin * brown out detect * LVP disabled * data EE protect disabled * ICD disabled * CCP1 pin on RB2 * * see more details and schematic on http://www.micro-examples.com/ * */
/* * display modes */ #define MODE_HOURMN 0 // display hours:minutes #define MODE_SS 1 // display seconds #define MODE_TEMP 2 // display temperature #define MAX_MODE 3 // number off display modes
/* * buttons */ #define BUTTON ((PORTA.F1 == 0) || (PORTA.F2 == 0)) // at least one #define BUTTON_MODE (PORTA.F1 == 0) // mode / advance #define BUTTON_TOGGLE (PORTA.F2 == 0) // toggle / valid #define BUTTON_SET ((PORTA.F1 == 0) && (PORTA.F2 == 0)) // both at the same time
#define TEMP_REF 115 // silicon junction offset : 600 mV #define MAX_TEMP 20 // number of temperature samples
/* * LED multiplexing tables * * LED index : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 * LED number : 1 2 3 4 9 10 5 6 11 12 25 30 7 8 5 10 35 40 45 50 2 1 15 20 3 4 55 * LED hours : 1 2 3 4 5 6 7 8 9 10 11 12 * LED min/deg : 5 10 15 20 25 30 35 40 45 50 55 * LED 1234 : 1 2 3 4 */
/* * upper row : hours from 1 to 12 */ const unsigned char hhTable[] = { 0, 1, 2, 3, 4, 7, 8, 13, 14, 5, 6, 9, 10 } ;
/* * middle row : minutes/seconds/°C from 5 to 55 step 5 */ const unsigned char mnTableH[] = { 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27 } ;
/* * lower row : increment of minutes/seconds/°C from 1 to 4 */ const unsigned char mnTableL[] = { 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26, 0, 22, 21, 25, 26 } ;
/* * RAM variables */ unsigned char mode ; // display mode unsigned char toggleMode ; // toggle mode flag unsigned int scaler = 0 ; // timer overflow divider unsigned char hh = 1 ; // hours unsigned char mn = 1 ; // minutes unsigned char ss = 0 ; // seconds int temp ; // temperature in °C unsigned char tdeg[MAX_TEMP] ; // array of temperatures samples unsigned char tidx = 0 ; // index of the temperature sample
/* * interrupt routine service * called Fosc / 4 / 256 times per second */ void interrupt(void) { if(INTCON.TMR0IF) // timer overflow ? { scaler++ ; // increment scaler if(scaler == 15625) // one second has expired ? { scaler = 0 ; // reset scaler
ss++ ; // next second if(ss == 60) // one minute has expired ? { ss = 0 ; // reset seconds mn++ ; // next minute if(mn == 60) // one hour has expired ? { mn = 0 ; // reset minutes hh++ ; // next hour if(hh == 13) // 12 hours mode { hh = 1 ; // back to first hour } } } }
INTCON.TMR0IF = 0 ; // clear interrupt flag } }
/* * light the LED number n during d milliseconds */ void dymoLight(const unsigned char n, unsigned char d) { switch(n) { case 0 : TRISB = 0b11111111 ; PORTB = 0b00000000 ; break ; case 1 : TRISB = 0b11111100 ; PORTB = 0b00000001 ; break ; case 2 : TRISB = 0b11111100 ; PORTB = 0b00000010 ; break ; case 3 : TRISB = 0b11111010 ; PORTB = 0b00000001 ; break ; case 4 : TRISB = 0b11111010 ; PORTB = 0b00000100 ; break ; case 5 : TRISB = 0b11111001 ; PORTB = 0b00000010 ; break ; case 6 : TRISB = 0b11111001 ; PORTB = 0b00000100 ; break ; case 7 : TRISB = 0b11110110 ; PORTB = 0b00000001 ; break ; case 8 : TRISB = 0b11110110 ; PORTB = 0b00001000 ; break ; case 9 : TRISB = 0b11110101 ; PORTB = 0b00000010 ; break ; case 10 : TRISB = 0b11110101 ; PORTB = 0b00001000 ; break ; case 11 : TRISB = 0b11110011 ; PORTB = 0b00000100 ; break ; case 12 : TRISB = 0b11110011 ; PORTB = 0b00001000 ; break ; case 13 : TRISB = 0b11101110 ; PORTB = 0b00000001 ; break ; case 14 : TRISB = 0b11101110 ; PORTB = 0b00010000 ; break ; case 15 : TRISB = 0b11101101 ; PORTB = 0b00000010 ; break ; case 16 : TRISB = 0b11101101 ; PORTB = 0b00010000 ; break ; case 17 : TRISB = 0b11101011 ; PORTB = 0b00000100 ; break ; case 18 : TRISB = 0b11101011 ; PORTB = 0b00010000 ; break ; case 19 : TRISB = 0b11100111 ; PORTB = 0b00001000 ; break ; case 20 : TRISB = 0b11100111 ; PORTB = 0b00010000 ; break ; case 21 : TRISB = 0b11011110 ; PORTB = 0b00000001 ; break ; case 22 : TRISB = 0b11011110 ; PORTB = 0b00100000 ; break ; case 23 : TRISB = 0b11011101 ; PORTB = 0b00000010 ; break ; case 24 : TRISB = 0b11011101 ; PORTB = 0b00100000 ; break ; case 25 : TRISB = 0b11011011 ; PORTB = 0b00000100 ; break ; case 26 : TRISB = 0b11011011 ; PORTB = 0b00100000 ; break ; case 27 : TRISB = 0b11010111 ; PORTB = 0b00001000 ; break ; case 28 : TRISB = 0b11010111 ; PORTB = 0b00100000 ; break ; case 29 : TRISB = 0b11001111 ; PORTB = 0b00010000 ; break ; case 30 : TRISB = 0b11001111 ; PORTB = 0b00100000 ; break ; } VDelay_ms(d) ; }
/* * set clock time */ void setTime() { INTCON.GIE = 0 ; // stop time counting hh = 1 ; // set hours for(;;) { dymoLight(hhTable[hh], 20) ; // light hour
if(BUTTON_MODE) // advance hour ? { VDelay_ms(15) ; // debounce button while(BUTTON_MODE) ; VDelay_ms(15) ;
hh++ ; // next hour if(hh > 12) // overflow ? { hh = 1 ; // back to first hour } }
if(BUTTON_TOGGLE) // valid ? { VDelay_ms(15) ; while(BUTTON_TOGGLE) ; // debounce button VDelay_ms(15) ; break ; // exit loop } }
mn = 1 ; // set minutes for(;;) { dymoLight(mnTableH[mn], 10) ; // light minutes, upper row dymoLight(mnTableL[mn], 10) ; // light minutes, lower row
if(BUTTON_MODE) // advance minute ? { VDelay_ms(15) ; // debounce button while(BUTTON_MODE) ; VDelay_ms(15) ;
mn++ ; // next minute if(mn > 59) // overflow ? { mn = 0 ; // back to first minute } }
if(BUTTON_TOGGLE) // valid ? { VDelay_ms(15) ; // debounce button while(BUTTON_TOGGLE) ; VDelay_ms(15) ; break ; // exit loop } }
ss = 0 ; // reset seconds INTCON.GIE = 1 ; // start clock toggleMode = 0 ; // no toggle mode = MODE_HOURMN ; // display hours:minutes }
/* * main entry */ void main() { unsigned int loopCtr = 0 ; // counter for temperature sampling delay unsigned int toggleCtr = 0 ; // counter for toggle delay // OSCCON |= 0b01110000 ; // untag if you use internal RC clock, 8Mhz
ADCON1 = 0b00001110 ; // RA0 as analog input, other input as digital I/O TRISA = 0b11111111 ; // all PORTA as inputs PORTA = 0 ; // clear PORTA
TRISB = 0xff ; // switch off display
INTCON.TMR0IF = 0 ; // clear timer 0 overflow interrupt flag INTCON.TMR0IE = 1 ; // allow timer 0 overflow interrupt OPTION_REG.T0CS = 0 ; // timer 0 clock source is internal instruction cycle clock
OPTION_REG.PS2 = 0 ; // no prescaler OPTION_REG.PS1 = 0 ; OPTION_REG.PS0 = 0 ; OPTION_REG.PSA = 1 ; setTime() ; // set time
for(;;) { loopCtr++ ; // increment loop counters toggleCtr++ ;
if(BUTTON) // if at least one button is pressed { unsigned char b = 0 ; VDelay_ms(15) ; // debounce while(BUTTON) // while one button is pressed { if(BUTTON_SET) // are they both pressed ? { dymoLight(hhTable[0], 1) ; // clear display dymoLight(mnTableH[0], 1) ; dymoLight(mnTableL[0], 1) ;
VDelay_ms(1000) ; // 1 second delay
setTime() ; // enter time setting break ; } else if(BUTTON_MODE) // change mode ? { b = 1 ; } else if(BUTTON_TOGGLE) // toggle the toggle mode ? { b = 2 ; }
VDelay_ms(15) ; } if(b == 1) // change mode { VDelay_ms(15) ; // debounce button while(BUTTON_MODE) ; VDelay_ms(15) ;
mode++ ; // next mode toggleMode = 0 ; // clear toggle mode if(mode == MAX_MODE) // last mode ? { mode = 0 ; // back to first one } } else if(b == 2) // toggle mode { VDelay_ms(15) ; // debounce button while(BUTTON_TOGGLE) ; VDelay_ms(15) ;
toggleMode = !toggleMode ; // toggle display mode } } if(mode == MODE_HOURMN) // display mode is hours:minutes { dymoLight(hhTable[hh], 5) ; // light hours
dymoLight(mnTableH[mn], 5) ; // light minutes, upper row dymoLight(mnTableL[mn], 5) ; // light minutes, lower row if(toggleMode && (toggleCtr > 400)) // if toggle mode and delay expired { toggleCtr = 0 ; // reset counter mode = MODE_TEMP ; // switch to temperature } } else if(mode == MODE_SS) // display mode is seconds { dymoLight(mnTableH[ss], 5) ; // light seconds, upper row dymoLight(mnTableL[ss], 5) ; // light seconds, lower row } else if(mode == MODE_TEMP) // display mode is temperature { unsigned char i ;
if(loopCtr > 20) // if delay expired { loopCtr = 0 ; // reset counter temp = TEMP_REF - Adc_Read(0) ; // get sample
temp *= 221 ; // temperature coefficient of the silicon junction temp /= 102 ; temp = 25 + temp ; // get the result in celcius
tdeg[tidx] = temp ; // store temperature sample into array tidx++ ; // advance index if(tidx == MAX_TEMP) // index overflow ? { tidx = 0 ; // back to first slot }
temp = 0 ; // compute average temperature for(i = 0 ; i < MAX_TEMP ; i++) // for all samples { temp += tdeg[i] ; // add them } temp /= MAX_TEMP ; // divide by sample number }
if((temp > 0) && (temp < 60)) // if temperature wihtin 0...59 { dymoLight(mnTableL[temp], 5) ; // display temperature, upper row dymoLight(mnTableH[temp], 5) ; // display temperature, lower row }
if(toggleMode && (toggleCtr > 200)) // if toggle mode and delay expired { toggleCtr = 0 ; // reset counter mode = MODE_HOURMN ; // switch to hours:minutes } } } }
|