|
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;
}