back to www.audiodesignguide.com |
To get more information contact me at: webmaster@audiodesignguide.com |
This project is not complete because I have found
some limit in the Microcontroller used because the flash memory is not enough to
contain all my firmware.
This Programmable Thermostat include an automatic charge for Ni-Mh battery and a
very good clock using 2 quartz.
I would like that someone continue to develop the firmware, I can give you one
pcb for free.
SCHEMATIC
PCB
PHOTO
Follows the rear side photo with the 2 correction to the pcb,
RA4 pin need pull-up and you must cut the wrong line as show.
FIRMWARE
To program the 16F876A Microchip microcontroller I have used the PICKIT 2 USB Development Programmer/Debugger (cod. PG164120 or DV164121) with a cost about 40-50$. |
I love the C language because it is very simple if compared to assembler.
The my C source has been compiled with
HI-TECH PICC-Lite™ Compiler. HI-TECH Software has provided a freeware HI-TECH PICC-Lite compiler as a tool for hobbyists and students, but the licence allows its use for commercial purposes as well. It is ideal as a teaching tool for an introduction into the 'C' language and embedded programing on a Microchip device. |
Follows the source file to compile with this command:
picl -16F877A ProgrammableThermostat.c
#include <pic.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define PIC_CLK 20000000 #include "delay_alternative_enhanced_precision.h" //__CONFIG(WDTDIS & XT & UNPROTECT & LVPDIS); // freq. clock 4MHz //__CONFIG(WDTDIS & HS & UNPROTECT & LVPDIS); // freq. clock 20MHz __CONFIG(WDTDIS & PWRTEN & HS & UNPROTECT & DEBUGDIS & BORDIS & LVPDIS); //__CONFIG(WDTDIS & XT & UNPROTECT & LVPDIS); #define PORTBIT(adr, bit) ((unsigned)(&adr)*8+(bit)) static bit BAT_CH @ PORTBIT(PORTC, 2); static bit BAT_DI @ PORTBIT(PORTC, 3); static bit BUT_UP @ PORTBIT(PORTB, 0); static bit BUT_LF @ PORTBIT(PORTB, 1); static bit BUT_EN @ PORTBIT(PORTB, 2); static bit BUT_RG @ PORTBIT(PORTB, 4); static bit BUT_DW @ PORTBIT(PORTB, 5); static bit OUT_ON @ PORTBIT(PORTA, 5); static bit BUT_ON @ PORTBIT(PORTA, 4); static bit LCD_RS @ PORTBIT(PORTC, 7); static bit LCD_RW @ PORTBIT(PORTC, 6); static bit LCD_EN @ PORTBIT(PORTC, 5); static bit LCD_BK @ PORTBIT(PORTC, 4); static bit LCD_O1 @ PORTBIT(TRISC, 6); static bit LCD_O2 @ PORTBIT(TRISC, 5); static bit LCD_O3 @ PORTBIT(TRISC, 4); #define LCD_DATA PORTB #define LCD_TRIS TRISB #define ACT_UP (1) #define ACT_DW (2) #define ACT_EN (3) #define ACT_LF (4) #define ACT_RG (5) //****************************************************************************** //* function declarationis & global variables //****************************************************************************** void DelayMs(int); void write_SPI(unsigned int, unsigned int); void LCD_init(void); void LCD_write_str(int, int, char *); void LCD_write_data(unsigned char); void LCD_write_cmd(unsigned char); void LCD_wait_busy(void); void LCD_clear_screen(); void LCD_cursor_on(); //int byteToInt(unsigned char, unsigned char) ; //int intToByte(int, unsigned char *, unsigned char *); void uitoa(unsigned int, char*, unsigned char); void DelayBigUs(unsigned int cnt); void DelayBigMs(unsigned int cnt) ; unsigned long GetTemp(); unsigned long GetBattery(); unsigned long GetPowerSupply(); unsigned char GetButton(); void ManageBacklight(unsigned char event); void DebugEvent(unsigned char event); void DisplayTime(); void DisplayPower(); void menu2(); void menu3(); void menu4(); void menu5(); void menu6(); unsigned long valoreBat, valorePS, valoreTemp; unsigned char byte1, byte2, byte3, byte4; unsigned char tmp[17]; #define DOTS ":" #ifdef OLD #define HELLO "HELLO" #define CHOICE "Scegli > up/down" #define ROW "1234567890123456" #define GOON "Accendi subito " #define GOOFF "Spegni subito" #define PROGC "Cambia programma" #define PROGV "Visual programma" #define PROGH "Cambia orario" #define PROGSV "Visualizza stat" #define PROGSR "Resetta stat" #define PROG1I "Prog1 Ora inizio" #define PROG1F "Prog1 Ora fine" #define PROG1S "Prog1 giorno set" #endif int ore = 0; int min = 0; int sec = 0; unsigned char state = 0; #define XTAL 20000000 // crystal frequency - 4MHz //########################1234567890123456######### char hello[] = "Ciao "; char arrow[] = ">"; char space[] = " "; bank1 char choice[] = "Scegli su o giu"; bank1 char switchon[] = "Accendi"; bank1 char switchoff[] = "Spegni"; bank1 char now[] = "subito"; bank1 char change[] = "Cambio"; bank1 char prog[] = "progr."; bank1 char time[] = "orario"; bank1 char enter[] = "Invio conferma "; //########################1234567890123456######### void interrupt prv_int(void) { if (TMR1IF) { TMR1H = 0x80; sec++; if (sec == 60) { sec = 0; min++; if (min == 60) { min = 0; sec = 0; ore++; if (ore == 24) { min = 0; sec = 0; ore = 0; } } } TMR1IF = 0; } } main() { unsigned char event; TRISA = 0b00001111; // All RA0-RA4 port A are input TRISC = 0b00000011; // only RC0 e RC1 are input for oscill CMCON = 0b00000111; // All comparator disabled //***************************************************** //* start tmr1 and secondary oscillator //***************************************************** T1OSCEN = 1; TMR1CS = 1; T1CKPS0 = 0; T1CKPS1 = 0; TMR1IF = 0; TMR1L = 0x80; TMR1H = 0x80; TMR1IE = 1; PEIE = 1; GIE = 1; TMR1ON = 1; //***************************************************** //* start adc //***************************************************** ADCON1 = 0b10000100; DelayMs(50); //################################################## //# display startup //################################################## LCD_init(); LCD_write_str( 1, 1, hello); LCD_BK = 1; DelayMs(2000); LCD_BK = 2; //################################################## //# load menu //################################################## //################################################## //# main loop //################################################## while(1) { if (state == 0 || state == 1) { DisplayTime(); valoreTemp = GetTemp(); } //valoreBat = GetBattery(); //valorePS = GetPowerSupply(); //DisplayPower(valoreBat, valorePS); event = GetButton(); ManageBacklight(event); if (event > 0) { switch (state) { case 0: LCD_write_str( 2, 1, choice); state = 1; break; case 1: menu2(); state = 2; break; case 2: if (event == ACT_EN) { OUT_ON=1; } else if (event == ACT_DW) { menu3(); state=3; } break; case 3: if (event == ACT_EN) { OUT_ON=0; } else if (event == ACT_UP) { menu2(); state=2; } else if (event == ACT_DW) { menu4(); state=4; } break; case 4: if (event == ACT_UP) { menu3(); state=3; } else if (event == ACT_DW) { menu5(); state=5; } break; case 5: if (event == ACT_EN) { menu6(); state=6; } else if (event == ACT_UP) { menu4(); state=4; } } } if (state == 6) { menu6(); } //DebugEvent(event); DelayMs(500); } } void switchon_now() { // >Accendi subito // 1234567890123456 LCD_write_str( 1, 2, switchon); LCD_write_str( 1, 9, space); LCD_write_str( 1, 10, now); LCD_write_str( 1, 16, space); } void switchoff_now() { // Spegni subito // 1234567890123456 LCD_write_str( 2, 2, switchoff); LCD_write_str( 2, 8, space); LCD_write_str( 2, 9, now); LCD_write_str( 2, 15, space); LCD_write_str( 2, 16, space); } void change_prog() { // >Cambio progr. // 1234567890123456 LCD_write_str( 1, 2, change); LCD_write_str( 1, 8, space); LCD_write_str( 1, 9, prog); LCD_write_str( 1, 15, space); LCD_write_str( 1, 16, space); } void change_time() { // Cambio orario // 1234567890123456 LCD_write_str( 2, 2, change); LCD_write_str( 2, 8, space); LCD_write_str( 2, 9, time); LCD_write_str( 2, 15, space); LCD_write_str( 2, 16, space); } void menu2() { LCD_write_str( 1, 1, arrow); switchon_now(); LCD_write_str( 2, 1, space); switchoff_now(); } void menu3() { LCD_write_str( 1, 1, space); switchon_now(); LCD_write_str( 2, 1, arrow); switchoff_now(); } void menu4() { LCD_write_str( 1, 1, arrow); change_prog(); LCD_write_str( 2, 1, space); change_time(); } void menu5() { LCD_write_str( 1, 1, space); change_prog(); LCD_write_str( 2, 1, arrow); change_time(); } void menu6() { LCD_write_cmd(0x01); // clear screen LCD_write_cmd(0x02); // cursor home position LCD_write_cmd(0xE); // cursor on DisplayTime(); //LCD_write_str( 2, 1, enter); } void DisplayTime() { uitoa(ore, tmp, 2); LCD_write_str( 1, 1, tmp); strcpy(tmp, DOTS); LCD_write_str( 1, 3, tmp); uitoa(min, tmp, 2); LCD_write_str( 1, 4, tmp); strcpy(tmp, DOTS); LCD_write_str( 1, 6, tmp); uitoa(sec, tmp, 2); LCD_write_str( 1, 7, tmp); strcpy(tmp, " "); LCD_write_str( 1, 9, tmp); return; } void ManageBacklight(unsigned char event) { static unsigned long backTime = 0; if (event > 0) { LCD_BK = 1; backTime = 0; } else if (backTime > 20) { LCD_BK = 0; state = 0; } else { backTime++; } } unsigned char GetButton() { TRISB = 0b11111111; // All port A are input DelayMs(10); BUT_ON = 1; DelayMs(10); if (BUT_UP == 0) { BUT_ON = 0; return ACT_UP; } else if (BUT_DW == 0) { BUT_ON = 0; return ACT_DW; } else if (BUT_LF == 0) { BUT_ON = 0; return ACT_LF; } else if (BUT_RG == 0) { BUT_ON = 0; return ACT_RG; } else if (BUT_EN == 0) { BUT_ON = 0; return ACT_EN; } BUT_ON = 0; return 0; } void adc_enable(unsigned char channel) { DelayMs(5); ADCON0 = (channel << 3) + 0x81; // ADC on, Fosc/32 DelayMs(5); } void adc_read() { ADGO = 1; // start A/D-conversion while(ADGO) // wait continue; } void DisplayPower() { strcpy(tmp, "PS "); LCD_write_str( 2, 1, tmp); uitoa(valorePS/10, tmp, 2); LCD_write_str( 2, 4, tmp); strcpy(tmp, ","); LCD_write_str( 2, 6, tmp); uitoa(valorePS%10, tmp, 1); LCD_write_str( 2, 7, tmp); strcpy(tmp, "BAT "); LCD_write_str( 2, 9, tmp); uitoa(valoreBat/10, tmp, 2); LCD_write_str( 2, 13, tmp); strcpy(tmp, ","); LCD_write_str( 2, 15, tmp); uitoa(valoreBat%10, tmp, 1); LCD_write_str( 2, 16, tmp); return; } unsigned long GetPowerSupply() { unsigned long valore; adc_enable(3); adc_read(); valore = ADRESL+(ADRESH<<8); //valore = (valore * (5000 / 1023)) / 7 ; valore = (valore * (5000 / 1023)) / 9 ; return valore; } unsigned long GetBattery() { unsigned long valore; adc_enable(1); adc_read(); valore = ADRESL+(ADRESH<<8); //valore = valore * (5000 / 1023) / 7 ; valore = (valore * (5000 / 1023)) / 9 ; return valore; } unsigned long GetTemp() { unsigned long valore; adc_enable(0); adc_read(); valore = ADRESL+(ADRESH<<8); valore = valore * (5000 / 1023) / 6; uitoa(valore/10, tmp, 2); LCD_write_str( 1, 12, tmp); strcpy(tmp, ","); LCD_write_str( 1, 14, tmp); uitoa(valore%10, tmp, 1); LCD_write_str( 1, 15, tmp); tmp[0] = 0b11011111; LCD_write_str( 1, 16, tmp); return valore; } //********************************************************************* //* LCD read and write //********************************************************************* void LCD_init() { char * ptr; char LCDstr[] = { 0x3c, // 111100: 8bits, 2lines, 5x10dots 0x01, // clear display 0x0c, // 1100: display on, cursor off 0x06, // 110: auto-increment 0x00 }; LCD_O1 = 0; LCD_O2 = 0; LCD_O3 = 0; LCD_TRIS = 0; LCD_DATA = 0; ptr = LCDstr; while(*ptr) { LCD_write_cmd(*ptr); ptr++; } } void LCD_wait_busy() { unsigned char busy; int retry = 1000; LCD_TRIS = 0xff; LCD_RS = 0; LCD_RW = 1; // read asm("nop"); do { LCD_EN = 1; asm("nop"); busy = LCD_DATA & 0x80; LCD_EN = 0; } while (busy && retry-- > 0); LCD_TRIS = 0x00; } void LCD_write_cmd(unsigned char c) { LCD_wait_busy(); LCD_RW = 0; LCD_RS = 0; LCD_DATA = c; LCD_EN = 1; LCD_EN = 0; } void LCD_write_data(unsigned char c) { LCD_wait_busy(); LCD_RW = 0; LCD_RS = 1; LCD_DATA = c; LCD_EN = 1; LCD_EN = 0; } void LCD_write_str(int line, int pos, unsigned char * str) { unsigned char curr; unsigned char i; //************************************************* // set the posistion and line //************************************************* if (line == 1) curr = 0b10000000 + (pos - 1); else curr = 0b11000000 + (pos - 1); LCD_write_cmd(curr); //************************************************* // send the string //************************************************* for(i = 0; str[i] != '\0'; i++) { LCD_write_data(str[i]); } } void DelayMs(int cnt) { unsigned char i; do { i = 4; do { DelayUs(250); } while(--i); } while(--cnt); } #ifdef OLD int intToByte(int integer, unsigned char * byte1, unsigned char * byte2) { *byte1 = (char)(integer >> 8); *byte2 = (char)(integer); return 0; } int byteToInt(unsigned char byte1, unsigned char byte2) { int integer; integer = byte1; integer <<= 8; integer |= byte2; return integer; } #endif
void uitoa(unsigned int value, char* string, unsigned char len) { unsigned char index = len; string[0] = '0'; do { string[--index] = '0' + (value % 10); value /= 10; } while (value != 0); string[len] = 0; }