/******************************************************************************
*
* AtomSoft Clock Using PIC18F248, DS1306, 74LS164, 3v Buzzer
*
******************************************************************************
* FileName: main.c
* Author: Jason Lopez
* Processor: PIC18F248(0)
* Compiler: C18
* Company: AtomSoftTech
* Version: 2.0.0
******************************************************************************/
#include <p18F248.h>
#include <stdio.h>
#include <delays.h>
#include <spi.h>
#pragma config WDT = OFF, LVP = OFF, OSC = HS
/************************************
Prototypes
*************************************/
void main(void);
void initSPI(void);
void e_togg(void);
void lcd_line(char line);
void lcd_cmd(unsigned char letter);
void lcd_char(unsigned char letter);
void lcd_string(char *senpoint);
void lcd_init(void);
void delay_ms(int mS);
void delay_us(int uS);
void delay_s(int S);
void lcdByte(unsigned char dNyb,unsigned char rs);
char RTCRegRead(char adx);
void RTCRegWrite(char adx, char data);
static unsigned char uint2bcd(unsigned char ival);
char readBtn(void);
unsigned char bcd2dec(unsigned char aBCD, char type);
void putDate(char type, char data);
void UpdateTime(void) ;
void ShowMenu(void);
void SetTime(char type);
void low_isr(void);
void high_isr(void);
void SetDate(void);
/************************************
Definitions
************************************/
#define CS LATCbits.LATC2
#define CS_T TRISCbits.TRISC2
#define SCL_T TRISCbits.TRISC3
#define SDA_T TRISCbits.TRISC4
#define SDO_T TRISCbits.TRISC5
#define LCD_DAT_T TRISCbits.TRISC0
#define LCD_CLK_T TRISCbits.TRISC1
#define LCD_DAT LATCbits.LATC0
#define LCD_CLK LATCbits.LATC1
#define LCD_E_T TRISCbits.TRISC6
#define LCD_E LATCbits.LATC6
#define PL LATBbits.LATB0
#define CP2 LATBbits.LATB1
#define SDL PORTBbits.RB2
#define PL_T TRISBbits.TRISB0
#define CP2_T TRISBbits.TRISB1
#define SDL_T TRISBbits.TRISB2
#define Button (PORTA >> 1) & 0x0F;
#define Button_T TRISA
#define setupBtn 0x01
#define downBtn 0x02
#define upBtn 0x04
#define selectBtn 0x08
#define alarmOut LATBbits.LATB3
#define alarmOutT TRISBbits.TRISB3
#define alarmIn_T TRISBbits.TRISB1
#define OneHz_T TRISBbits.TRISB0
/************************************
Variables
************************************/
char string[] = " ";
char string2[] = " ";
char company[] = " AtomSoftTech ";
char SetStr[] = " Settings ";
char SetTA[] = " Adjust: ";
char TimeStr[] = "1. Set Time ";
char DateStr[] = "2. Set Date ";
char AlarmStr[] = "3. Set Alarm ";
unsigned char lDate[16];
unsigned char myTmp;
//////////////////////////
/* NEW VARs */
//////////////////////////
unsigned char decHour;
unsigned char decMin;
unsigned char decAPM;
unsigned char BcdHour;
unsigned char BcdMin;
unsigned char BcdAPM;
unsigned char BcdSec;
unsigned char decDate;
unsigned char decMonth;
unsigned char decYear;
unsigned char BcdDate;
unsigned char BcdMonth;
unsigned char BcdYear;
unsigned char time[16];
unsigned char comDate[16];
unsigned char view;
/************************************
Main
************************************/
void main(void) {
ADCON1 = 0x0E;
initSPI();
lcd_init();
SDL_T = 1;
Button_T = 0xFF; //TRISA (all input)
RTCRegWrite(0x8F,0x05);
alarmIn_T = 1;
OneHz_T = 1;
alarmOutT = 0;
alarmOut = 0;
/* Interrupt Items */
RCON = 0x80;
INTCON = 0xC0;
INTCON2 = 0x80;
INTCON3 = 0x98;
UpdateTime();
view = 0;
RTCRegRead(0x07);
while(1) {
myTmp = Button;
if(myTmp == selectBtn){
if(view == 1){
lcd_string(company);
view = 0;
} else {
lcd_string(comDate);
view = 1;
}
UpdateTime();
while(myTmp == selectBtn){myTmp = Button};
}
if(myTmp == setupBtn){
INTCON = 0x00;
ShowMenu();
UpdateTime();
delay_s(1);
INTCON = 0xC0;
}
if(myTmp == upBtn){
alarmOut = 0;
}
}
}
/***********************************
RTC Tools
************************************
Convert Char(byte) to BCD
************************************/
unsigned char uint2bcd(unsigned char ival)
{
return ((ival / 10) << 4) | (ival % 10);
}
/************************************
Convert BCD to Char(byte)
************************************/
unsigned char bcd2dec(unsigned char aBCD, char type)
{
char lowNyb = aBCD & 0x0F;
char highNyb = aBCD >> 4;
char MyDec = lowNyb;
char x;
switch(type){
case 0:
highNyb &= 0x0F;
break;
case 1:
highNyb &= 0x01;
break;
case 2:
highNyb &= 0x03;
break;
case 3:
highNyb &= 0x07;
break;
case 4:
highNyb &= 0x00;
break;
}
for(x=0;x<highNyb;x++){
MyDec += 10;
}
return MyDec;
}
/************************************
Read a Register off the DS1306
************************************/
char RTCRegRead(char adx){
char tmp;
CS = 1;
WriteSPI(adx); //sec
tmp = ReadSPI();
CS = 0;
return tmp;
}
/************************************
Write to a Register on the DS1306
************************************/
void RTCRegWrite(char adx, char data){
CS = 1;
WriteSPI((adx | 0x80 ));
WriteSPI(data);
CS = 0;
}
/************************************
Initialize SPI
************************************/
void initSPI(void){
CS_T = 0; //CS is output
SCL_T = 0; //SCL is output
SDA_T = 1; //SDA is input
SDO_T = 0; //SDO is output
OpenSPI(SPI_FOSC_4,MODE_10,SMPEND);
CS = 1;
WriteSPI(0x8F);
WriteSPI(0x00);
CS = 0;
}
/***********************************
LCD Functions
************************************
Send String to LCD
************************************/
void lcd_string(char *senpoint){
delay_ms(1);
while(*senpoint != '\0'){
lcd_char(*senpoint);
senpoint++;
}
}
/************************************
Send Data(Nybble) to LCD
************************************/
void lcdByte(unsigned char dNyb,unsigned char rs){
int i;
LCD_DAT=0; //Clear 74LS164 set initial bit to 0
for(i=0;i<8;i++){ //repeat for 8 bits
LCD_CLK=1;LCD_CLK=0; //write 0's to the 164
}
for(i=0;i<4;i++){ //output the nybble
if((dNyb & 0x08) != 0)
LCD_DAT=1;
else
LCD_DAT=0;
LCD_CLK=1;LCD_CLK=0;
dNyb=dNyb<<1;
}
LCD_DAT = rs; //output the RS bit value
LCD_CLK=1;LCD_CLK=0;
LCD_DAT = 0;
LCD_CLK=1;LCD_CLK=0;
LCD_CLK=1;LCD_CLK=0;
LCD_CLK=1;LCD_CLK=0;
e_togg();
}
/************************************
Toggle E Line
************************************/
void e_togg(void){
LCD_E=1;LCD_E=0;
}
/************************************
Set LCD Line
************************************/
void lcd_line(char line){
if(line == 0x01)
lcd_cmd(0x80);
else
lcd_cmd(0xc0);
}
/************************************
LCD Send Command
************************************/
void lcd_cmd(unsigned char letter){
unsigned char temp;
temp=letter;
temp=temp>>4;
lcdByte(temp,0);
temp=letter;
temp=temp&0x0f;
lcdByte(temp,0);
}
/************************************
LCD Send Character
************************************/
void lcd_char(unsigned char letter){
unsigned char temp;
temp=letter;
temp=temp>>4;
lcdByte(temp,1);
temp=letter;
temp=temp&0x0f;
lcdByte(temp,1);
}
/************************************
LCD Initialization
************************************/
void lcd_init(void){
LCD_E_T = 0;
LCD_CLK_T = 0;
LCD_DAT_T = 0;
lcdByte(0x03,0);
delay_ms(5);
e_togg();
delay_us(160);
e_togg();
delay_us(160);
lcdByte(0x02,0);
delay_us(160);
lcd_cmd(0x28); //set 4-bit mode and 2 lines
delay_us(160);
lcd_cmd(0x10); //cursor move & shift left
delay_us(160);
lcd_cmd(0x06); //entry mode = increment
delay_us(160);
lcd_cmd(0x0d); //display on - cursor blink on
delay_us(160);
lcd_cmd(0x01); //clear display
delay_ms(500);
}
/************************************
Delays (S,mS,uS) for 20Mhz
************************************/
/*********************
Delay Second(s)
**********************/
void delay_s(int S){
int y;
char x;
for(y=0;y<S;y++)
for(x=0;x<4;x++)
delay_ms(250);
}
/************************
Delay MilliSecond(s)
*************************/
void delay_ms(int mS){
int y;
for(y=0;y<mS;y++)
Delay1KTCYx(5);
}
/************************
Delay MicroSeconds
*************************
Lowercase 'u' is common
symbol for Micro
*************************/
void delay_us(int uS){
int y;
char x;
for(y=0;y<uS;y++)
for(x=0;x<5;x++)
Nop();
}
/**********************************
readBtn
***********************************/
char readBtn(void){
char tmpA;
tmpA = myTmp = Button;
while(myTmp == tmpA){myTmp = Button};
return tmpA;
}
/**********************************
LCD / RTC stuff
***********************************/
void UpdateTime(void) {
unsigned char tmp,tmp2;
char i;
// Fill In the LCD String
time[0] = 'T';
time[1] = 'i';
time[2] = 'm';
time[3] = 'e';
time[4] = ':';
time[5] = ' ';
time[8] = ':';
time[11] = ' ';
time[13] = 'M';
time[14] = ' ';
time[15] = ' ';
// Get Date
comDate[0] = 'D';
comDate[1] = 'a';
comDate[2] = 't';
comDate[3] = 'e';
comDate[4] = ':';
comDate[5] = ' ';
comDate[8] = '/';
comDate[11] = '/';
comDate[14] = ' ';
comDate[15] = ' ';
// Get Minutes
tmp = RTCRegRead(0x01);
time[10] = (tmp & 0x0F) + 0x30;
time[9] = (tmp >> 4) + 0x30;
// Get Hours
tmp = RTCRegRead(0x02);
time[7] = (tmp & 0x0F) + 0x30;
time[6] = ((tmp >> 4) & 0x01 ) + 0x30;
// GET AM or PM (already read register 0x02)
time[12] = ((tmp >> 4) & 0x01 ) + 0x30;
if(time[12] == 0){
time[12]='A';
} else {
time[12]='P';
}
//Get Month
tmp = RTCRegRead(0x05);
comDate[6] = (tmp >> 4) + 0x30 ;
comDate[7] = (tmp & 0x0F) + 0x30 ;
//Get Date(day)
tmp = RTCRegRead(0x04);
comDate[9] = (tmp >> 4) + 0x30 ;
comDate[10] = (tmp & 0x0F) + 0x30 ;
//Get Year
tmp = RTCRegRead(0x06);
comDate[12] = (tmp >> 4) + 0x30 ;
comDate[13] = (tmp & 0x0F) + 0x30 ;
lcd_line(2);
lcd_string(time);
lcd_line(1);
if(view == 0){
lcd_string(company);
} else {
lcd_string(comDate);
}
decMonth = bcd2dec(RTCRegRead(0x05), 2);
decDate = bcd2dec(RTCRegRead(0x04), 0);
decYear = bcd2dec(RTCRegRead(0x06), 0);
decHour = bcd2dec(RTCRegRead(0x02),1);
decMin = bcd2dec(RTCRegRead(0x01),3);
decAPM = bcd2dec(RTCRegRead(0x05),0);
decAPM = (decAPM >> 4) & 0x01;
}
/**********************************
Show Menu
***********************************/
void ShowMenu(void){
char MyButton = 0;
char views = 1;
myTmp = setupBtn;
while(myTmp == setupBtn){myTmp = Button};
while(1){
MyButton = Button;
lcd_line(1);
lcd_string(SetStr);
lcd_line(2);
switch(views){
case 1:
lcd_string(TimeStr);
break;
case 2:
lcd_string(DateStr);
break;
case 3:
lcd_string(AlarmStr);
break;
}
switch(MyButton){
case upBtn:
if(views>3)
views = 1;
else
views++;
break;
case downBtn:
if(views<1)
views = 3;
else
views--;
break;
case setupBtn:
return;
break;
case selectBtn:
switch(views){
case 1:
SetTime('t');
break;
case 2:
SetDate();
break;
case 3:
SetTime('a');
break;
}
break;
}
delay_ms(200);
}
}
/**********************************
Set the Time
***********************************/
void SetTime(char type){
char MyButton = 0;
char views;
myTmp = selectBtn;
while(myTmp == selectBtn){myTmp = Button};
views = 1;
if(type == 't'){
string2[0] = 'T';
string2[1] = 'i';
string2[2] = 'm';
string2[3] = 'e';
string2[4] = ':';
string2[5] = ' ';
} else {
string2[0] = 'A';
string2[1] = 'l';
string2[2] = 'a';
string2[3] = 'r';
string2[4] = 'm';
string2[5] = ':';
}
string2[6] = ' ';
string2[9] = ':';
string2[12] = ' ';
string2[14] = 'M';
string2[15] = ' ';
while(1){
MyButton = Button;
switch(MyButton){
case upBtn:
switch(views){
case 1:
decHour++;
break;
case 2:
decMin++;
break;
case 3:
decAPM++;
break;
}
break;
case downBtn:
switch(views){
case 1:
decHour--;
break;
case 2:
decMin--;
break;
case 3:
decAPM--;
break;
}
break;
case setupBtn:
return;
break;
case selectBtn:
views++;
break;
}
if(decHour > 12) decHour = 1;
if(decHour <= 0) decHour = 12;
if(decMin > 59) decMin = 0;
if(decMin < 0) decMin = 59;
if(decAPM > 2) decAPM = 0;
if(decAPM < 0) decAPM = 1;
//Minutes
myTmp = uint2bcd(decMin);
string2[10] = (myTmp >> 4) + 0x30;
string2[11] = (myTmp & 0x0F) + 0x30;
//Hours
myTmp = uint2bcd(decHour);
string2[7] = ((myTmp >> 4) & 0x01) + 0x30;
string2[8] = (myTmp & 0x0F) + 0x30;
//AM-PM
if(decAPM == 0)
string2[13] = 'A';
else
string2[13] = 'P';
switch(views){
case 1:
SetTA[9] = 'H';SetTA[10] = 'o';SetTA[11] = 'u';SetTA[12] = 'r';SetTA[13] = ' ';
break;
case 2:
SetTA[9] = 'M';SetTA[10] = 'i';SetTA[11] = 'n';SetTA[12] = ' ';SetTA[13] = ' ';
break;
case 3:
SetTA[9] = 'A';SetTA[10] = 'M';SetTA[11] = '/';SetTA[12] = 'P';SetTA[13] = 'M';
break;
}
lcd_line(1);
lcd_string(SetTA);
lcd_line(2);
lcd_string(string2);
delay_ms(200);
if(views >= 4) break;
}
if(decAPM == 0)
BcdHour = uint2bcd(decHour) | 0b01000000;
else
BcdHour = uint2bcd(decHour) | 0b01100000;
BcdMin = uint2bcd(decMin) & 0b01111111;
BcdSec = 0x00;
if(type == 't'){
RTCRegWrite(0x80,BcdSec);
RTCRegWrite(0x81,BcdMin);
RTCRegWrite(0x82,BcdHour);
} else {
RTCRegWrite(0x87,BcdSec);
RTCRegWrite(0x88,BcdMin);
RTCRegWrite(0x89,BcdHour);
RTCRegWrite(0x8A,0x80);
}
}
/**********************************
Set the Date
***********************************/
void SetDate(void){
char MyButton = 0;
char views;
myTmp = selectBtn;
while(myTmp == selectBtn){myTmp = Button};
views = 1;
string2[0] = 'D';
string2[1] = 'a';
string2[2] = 't';
string2[3] = 'e';
string2[4] = ':';
string2[5] = ' ';
while(1){
MyButton = Button;
switch(MyButton){
case upBtn:
switch(views){
case 1:
decMonth++;
break;
case 2:
decDate++;
break;
case 3:
decYear++;
break;
}
break;
case downBtn:
switch(views){
case 1:
decMonth--;
break;
case 2:
decDate--;
break;
case 3:
decYear--;
break;
}
break;
case setupBtn:
return;
break;
case selectBtn:
views++;
break;
}
if(decYear > 99) decYear = 1;
if(decYear <= 0) decYear = 99;
if(decDate > 31) decDate = 1;
if(decDate <= 0) decDate = 31;
if(decMonth > 12) decMonth = 1;
if(decMonth <= 0) decMonth = 12;
//Month
myTmp = uint2bcd(decMonth);
string2[6] = (myTmp >> 4) + 0x30;
string2[7] = (myTmp & 0x0F) + 0x30;
string2[8] = '/';
//Date
myTmp = uint2bcd(decDate);
string2[9] = (myTmp >> 4) + 0x30;
string2[10] = (myTmp & 0x0F) + 0x30;
string2[11] = '/';
//Year
myTmp = uint2bcd(decYear);
string2[12] = (myTmp >> 4) + 0x30;
string2[13] = (myTmp & 0x0F) + 0x30;
switch(views){
case 1:
SetTA[9] = 'M';SetTA[10] = 'o';SetTA[11] = 'n';SetTA[12] = 't';SetTA[13] = 'h';
break;
case 2:
SetTA[9] = 'D';SetTA[10] = 'a';SetTA[11] = 't';SetTA[12] = 'e';SetTA[13] = ' ';
break;
case 3:
SetTA[9] = 'Y';SetTA[10] = 'e';SetTA[11] = 'a';SetTA[12] = 'r';SetTA[13] = ' ';
break;
}
lcd_line(1);
lcd_string(SetTA);
lcd_line(2);
lcd_string(string2);
delay_ms(200);
if(views >= 4) break;
}
BcdMonth = uint2bcd(decMonth);
BcdDate = uint2bcd(decDate);
BcdYear = uint2bcd(decYear);
RTCRegWrite(0x85,BcdMonth);
RTCRegWrite(0x84,BcdDate);
RTCRegWrite(0x86,BcdYear);
}
/**********************************
Interrupt Code
***********************************/
#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm GOTO low_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interruptlow low_isr
void low_isr (void)
{
myTmp = PORTB;
UpdateTime();
INTCON3 = 0x98;
}
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr (void)
{
myTmp = PORTB;
alarmOut = 1;
UpdateTime();
RTCRegRead(0x07);
INTCON3 = 0x98;
}