Code:
#include <p18F248.h>
#include <stdio.h>
#include <delays.h>
#include <spi.h>
#pragma config WDT = OFF, LVP = OFF, OSC = HS
/************************************
Prototypes
*************************************/
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);
void showMenu(void);
void setDate(void);
void setTime(char type);
static unsigned char uint2bcd(unsigned char ival);
char readBtn(void);
unsigned char bcd2dec(unsigned char aBCD, char type);
/************************************
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 setupBtn 0x08
#define downBtn 0x02
#define upBtn 0x01
#define selectBtn 0x10
/************************************
Variables
************************************/
char string[] = " ";
char string2[] = " ";
unsigned char time[17];
unsigned char theDay;
unsigned char theDate[2];
unsigned char theMonth[2];
unsigned char theYear[2];
unsigned char theHour[2];
unsigned char theMin[2];
unsigned char theSec[2];
unsigned char decHour;
unsigned char decMin;
unsigned char decSec;
unsigned char decAMPM;
/************************************
Main
************************************/
void main(void){
unsigned char tmp,tmp2;
unsigned char buff[40];
char i;
time[16] = 0;
ADCON1 = 0x0E;
initSPI();
lcd_init();
PL_T = 0;
CP2_T = 0;
SDL_T = 1;
lcd_line(1);
sprintf(string," AtomSoftTech",0);
lcd_string(string);
lcd_line(2);
sprintf(string," 2-Wire 74LS164",0);
lcd_string(string);
delay_s(1);
lcd_line(2);
sprintf(string," DS1306 TEST. ",0);
lcd_string(string);
delay_s(1);
while(1){
lcd_line(1);
sprintf(string," AtomSoftTech",0);
lcd_string(string);
tmp = RTCRegRead(0x02);
time[15] = (tmp >> 4) & 0x02;
if(time[15] == 0)
time[15] = 'A' ;
else
time[15] = 'P';
time[14] = 0x20;
tmp = RTCRegRead(0x00);
decSec = tmp;
theSec[1] = time[13] = (tmp & 0x0F) + 0x30;
theSec[0] = time[12] = ((tmp >> 4) & 0x0F ) + 0x30;
time[11] = ':';
tmp = RTCRegRead(0x01);
decMin = tmp;
theMin[1] = time[10] = (tmp & 0x0F) + 0x30;
theMin[0] = time[9] = ((tmp >> 4) & 0x0F ) + 0x30;
time[8] = ':';
tmp = RTCRegRead(0x02);
decHour = tmp;
theHour[1] = time[7] = (tmp & 0x0F) + 0x30;
theHour[0] = time[6] = ((tmp >> 4) & 0x01 ) + 0x30;
time[5] = 0x20;
time[4] = ':';
time[3] = 'e';
time[2] = 'm';
time[1] = 'i';
time[0] = 'T';
lcd_line(2);
lcd_string(time);
tmp = readBtn();
if(tmp == setupBtn)
showMenu();;
delay_ms(10);
}
}
/***********************************
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;
}
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){
adx |= 0x80;
CS = 1;
WriteSPI(adx);
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();
}
/***********************************
SN74LS165 Functions
************************************
Toggle Clock Pin
************************************/
void clk_togg(void){
LCD_CLK=1;LCD_CLK=0;
}
/************************************
readBtn
************************************/
char readBtn(void){
char x;
char buff;
delay_ms(100);
PL=0; PL=1;
for(x=0;x<8;x++){
buff <<= 1; // shift composed byte by 1
buff &= 0xFE; // clear bit 0
if (SDL) // is data line high
buff |= 0x01; // set bit 0 to logic 1
CP2 = 0; CP2 = 1;
}
delay_ms(100);
return buff & 0x1F;
}
/***********************************
LCD / RTC stuff
************************************
Show Menu
************************************/
void showMenu(void){
char item, isEnter;
isEnter = 0;
item = 1; //Default to first menu item
while(1){
/******************************
Which item are we viewing
*******************************/
switch(item){
case 0:
item=3; //user went do down too far start from 3
break;
case 1:
sprintf(string2,"1.Set Time ",0);
break;
case 2:
sprintf(string2,"2.Set Date ",0);
break;
case 3:
sprintf(string2,"3.Set Alarm ",0);
break;
case 4:
item=1; //user went too up far start them from 1
break;
}
/*****************************
Determine Button Pressed
******************************/
switch(readBtn()){
case upBtn:
item++;
break;
case downBtn:
item--;
break;
case selectBtn:
isEnter = 1;
break;
}
/*****************************
Enter is pressed
******************************/
if(isEnter == 1){
if(item==1)
setTime('t');
if(item==2){
setDate();
}
if(item==3){
//Set Alarm
}
item=9; //a overkill number incase i want to add more functions.
}
/*************************
Show Menu to the user
**************************/
lcd_line(1);
sprintf(string," Settings ",0);
lcd_string(&string);
lcd_line(2);
lcd_string(&string2);
/**************************
Check if user is done.
***************************/
if(item==9)
break; //leave while(1) loop
}//end of while loop
}
/*****************
Set the Date
******************/
void setDate(void){
}
/****************
Set the Time
****************/
void setTime(char type){
char bcdMin,bcdHour;
char x = 0;
decMin = bcd2dec(decMin,3);
decHour = bcd2dec(decHour,1);
decAMPM = (RTCRegRead(0x01) >> 5) & 0x01 ;
/********************
Main while loop
*********************/
while(1){
/**********************************
Determine which title to show
***********************************/
switch(x){
case 0:
sprintf(string,"Set Time: Hour ",0);
break;
case 1:
sprintf(string,"Set Time: Min ",0);
break;
case 2:
sprintf(string,"Set Time: AM/PM ",0);
break;
}
/*****************************************
Button pressed functions
******************************************/
switch(readBtn()){
case upBtn:
switch(x){
case 0:
decHour++;
break;
case 1:
decMin++;
break;
case 2:
decAMPM++;
break;
}
break;
case downBtn:
switch(x){
case 0:
decHour--;
break;
case 1:
if(decMin == 0)
decMin = 59;
else
decMin--;
break;
case 2:
decAMPM--;
break;
}
break;
case selectBtn:
x++;
break;
case setupBtn:
return; //User Pressed Setup aka Cancel
}
/**********************************************
Error Fix's:
***********************************************
ex: If hour is greater than 12 then set to 1
if its a 0 set it to 12 since this is 12 hr
there is no 00:00 hour only 1-12 AM/PM
***********************************************/
if(decHour >= 13)
decHour = 1;
if(decHour == 0)
decHour = 12;
if(decMin >= 60)
decMin = 0;
if(decAMPM >= 2)
decAMPM = 0;
if(decAMPM < 0)
decAMPM = 0;
if(x >= 3)
break;
if(x == 'c')
break;
/*****************************************
Convert to BCD for the RTC(DS1306)
******************************************/
bcdHour = uint2bcd(decHour);
if(decAMPM >= 1)
bcdHour = bcdHour | 0x20; //0b00100000
bcdMin = uint2bcd(decMin);
/*********************************************
Convert to seperate numbers or split BCD
and add 0x30 so it can be displayed on
LCD.
**********************************************/
time[6] = ((bcdHour >> 4) & 0x01) + 0x30;
time[7] = (bcdHour & 0x0F) + 0x30;
time[9] = (bcdMin >> 4) + 0x30;
time[10] = (bcdMin & 0x0F) + 0x30;
time[12] = time[13] = 0x30;
if(decAMPM == 1)
time[15] = 'P';
else
time[15] = 'A';
/*****************************************
Update the LCD with new info.
******************************************/
lcd_line(1);
lcd_string(string);
lcd_line(2);
lcd_string(&time);
}
/*****************************************
Done! Now write to RTC the new Data
******************************************/
RTCRegWrite(0x80,0x00); //Seconds = 00
RTCRegWrite(0x81,bcdMin); //Minutes
RTCRegWrite(0x82,bcdHour); //Hours
}