程序:
main函數(shù):
/*
程序功能:DS1302實(shí)時(shí)時(shí)鐘顯示
作者:朱波
時(shí)間:2012年2月3日
通信方式:3線串行通信
使用說(shuō)明:本程序模仿家用萬(wàn)年歷,能夠進(jìn)行時(shí)間的設(shè)定
時(shí)間設(shè)定方法:1.按下設(shè)置鍵進(jìn)入設(shè)置模式
2.按選擇鍵對(duì)要設(shè)置的項(xiàng)進(jìn)行選擇
3.按加一鍵對(duì)選擇項(xiàng)加一
4.完成全部選擇后出現(xiàn)"please check OK!"
此時(shí)按下確定鍵就回到時(shí)間模式
備注:可以通過(guò)主函數(shù)中的宏定義進(jìn)行時(shí)間設(shè)置
*/
#include <iom16v.h>
#include <macros.h>
#include "delay.h"
#include "display.h"
#include "ds1302.h"
#include "key.h"
#define uchar unsigned char
#define uint unsigned int
//用于校準(zhǔn)時(shí)間
#define year 12//年份
#define week 4//星期
#define month 12//月
#define daytime 23//日
#define hour 12//小時(shí)
#define minute 59//分鐘
#define seconds 55//秒
uint time_data[7]={year,week,month,daytime,hour,minute,seconds};//年星期月日時(shí)分秒(設(shè)置初始時(shí)間)
void main()
{
int_init();//中斷初始化
SEI();//開啟總中斷
LCD_init();//1602液晶初始化
SCK_OUT;//對(duì)時(shí)鐘進(jìn)行操作將SCK設(shè)置成輸出
RST_OUT;//對(duì)時(shí)鐘進(jìn)行操作將RST設(shè)置成輸出
set_rtc();//設(shè)置時(shí)間
hour_mode(24);//時(shí)間顯示模式設(shè)定,12小時(shí)顯示沒(méi)有做好處理
//只是注意此函數(shù)的寫法
while(1)
{
read_rtc();//讀取時(shí)間
time_pro();//時(shí)間處理
display();//顯示時(shí)間
}
}
delay.c:
#include"delay.h"
void delay(unsigned int ms)
{
unsigned int i,j;
for(i=0;i<ms;i++)
{
for(j=0;j<1141;j++);
}
}
delay.h:
#ifndef delay_h
#define delay_h
extern void delay(unsigned int ms);
#endif
ds1302.c:
#include <iom16v.h>
#include <macros.h>
#include "key.h"
#include "display.h"
#define uchar unsigned char
#define uint unsigned int
#define SCK_CLR PORTA&=~BIT(6)
#define SCK_SET PORTA|=BIT(6)
#define SCK_OUT DDRA|=BIT(6)
#define RST_CLR PORTC&=~BIT(7)
#define RST_SET PORTC|=BIT(7)
#define RST_OUT DDRC|=BIT(7)
#define IO_CLR PORTA&=~BIT(7)//IO引腳輸出低電平
#define IO_SET PORTA|=BIT(7)//IO引腳輸出高電平
#define IO_OUT DDRA|=BIT(7)//IO引腳設(shè)置為輸出
#define IO_IN DDRA&=~BIT(7)//IO引腳設(shè)置為輸入
#define IO_R PINA&BIT(7)//IO引腳進(jìn)行讀取操作
extern int time_data[7];
uchar write_add[7]={0X8C,0X8A,0X88,0X86,0X84,0X82,0X80};//寫地址(最低位為0)
uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};//讀地址(最低位為1)
uchar table[];//用于計(jì)算
void write_ds1302_byte(uchar dat)//在ds1302中寫指令字節(jié)
{
uint i;
IO_OUT;
for(i=0;i<8;i++)//一位一位往里寫,共寫8位
{
SCK_CLR;//開始時(shí)時(shí)序?yàn)?
//先準(zhǔn)備好數(shù)據(jù),在給上升沿
if(dat&0x01)//如果數(shù)據(jù)位為1
{
IO_SET;//IO為1
}
else//如果數(shù)據(jù)位為0
{
IO_CLR;//IO為0
}
SCK_SET;//SCLK拉高開始傳輸數(shù)據(jù)
dat=dat>>1;//移位進(jìn)行下一個(gè)字節(jié)的傳輸(寫的時(shí)候放到后面)
}
}
uchar read_ds1302(uchar add)//單字節(jié)讀
{
uchar i,value;//定義變量
RST_CLR;
SCK_CLR;//開始RET和SCLK時(shí)序?yàn)榈? RST_SET;
//根據(jù)時(shí)序要傳輸命令
write_ds1302_byte(add);//執(zhí)行完此句后,SCLK時(shí)序到下降沿處開始讀數(shù)據(jù)
IO_IN;//IO設(shè)置成輸入
for(i=0;i<8;i++)//一個(gè)字節(jié)為8位,一位一位的讀
{
SCK_CLR;//時(shí)鐘拉低開始傳輸
value=value>>1;//讀的時(shí)候放到前面
if(IO_R)//讀的結(jié)果如果為1
{
value=value|0X80;//從低位開始讀取
}
SCK_SET;//時(shí)鐘拉高結(jié)束傳輸
}//循環(huán)結(jié)束后SCLK時(shí)序到了最后,將RST拉低
RST_CLR;
return value;//將數(shù)據(jù)返回
}
void write_ds1302(uchar add,uchar dat)//單字節(jié)寫(傳遞兩個(gè)參數(shù)一個(gè)是地址一個(gè)是數(shù)據(jù))
{
RST_CLR;
NOP();
SCK_CLR;//開始RET和SCLK時(shí)序?yàn)榈? RST_SET;//根據(jù)時(shí)序開始寫入東西時(shí)將RST拉高
write_ds1302_byte(add);//寫入地址
write_ds1302_byte(dat);//寫入數(shù)據(jù)
RST_CLR;//根據(jù)時(shí)序,當(dāng)寫完?yáng)|西時(shí)RST拉低
}
void set_rtc(void)//設(shè)置時(shí)間(初始化時(shí)間)
{
uchar i,k;
for(i=0;i<7;i++)//將十進(jìn)制轉(zhuǎn)換為16進(jìn)制
{
k=time_data[i]/10;//得到十位
time_data[i]=time_data[i]%10;//得到個(gè)位
time_data[i]=time_data[i]+k*16;//變成BCD碼
}
write_ds1302(0x8e,0x00);//去除寫保護(hù)(control寄存器)
for(i=0;i<7;i++)//對(duì)時(shí)
{
write_ds1302(write_add[i],time_data[i]);
}
write_ds1302(0x8e,0x80);//(wp位置1)加入寫保護(hù)
}
void read_rtc(void)//讀時(shí)鐘
{
uchar i;
for(i=0;i<7;i++)
{
time_data[i]=read_ds1302(read_add[i]);//把時(shí)鐘放到數(shù)組里
}
}
void time_pro(void)//時(shí)間處理函數(shù)(16進(jìn)制轉(zhuǎn)換為十進(jìn)制)
{
table[0]=time_data[6]%16;//顯示秒個(gè)位
table[1]=time_data[6]/16;//顯示秒十位
table[2]=time_data[5]%16;//顯示分個(gè)位
table[3]=time_data[5]/16;//顯示分十位
table[4]=time_data[4]%16;//顯示小時(shí)個(gè)位
table[5]=time_data[4]/16;//顯示小時(shí)十位
table[6]=time_data[3]%16;//顯示日個(gè)位
table[7]=time_data[3]/16;//顯示日十位
table[8]=time_data[2]%16;//顯示月個(gè)位
table[9]=time_data[2]/16;//顯示月十位
table[10]=time_data[1]%16;//顯示星期
table[12]=time_data[0]%16;//顯示年個(gè)位
table[13]=time_data[0]/16;//顯示年十位
}
void hour_mode(uchar mode)//mode為12時(shí)為12小時(shí)格式,為24時(shí)為24小時(shí)格式
{
uint value;
write_ds1302(0x8e,0x00);//去除寫保護(hù)(control寄存器)
if(mode==12)
{
value=read_ds1302(0x85);//讀取小時(shí)當(dāng)前值
value=value|0x80; //將小時(shí)數(shù)據(jù)最高位置1
write_ds1302(0x84,value);//將置1后的小時(shí)數(shù)據(jù)寫入小時(shí)寄存器
//變?yōu)?2小時(shí)格式
}
if(mode==24)
{
value=read_ds1302(0x85);//讀取小時(shí)當(dāng)前值
value=value&0x7F; //將小時(shí)數(shù)據(jù)最高位置0
write_ds1302(0x84,value);//將置1后的小時(shí)數(shù)據(jù)寫入小時(shí)寄存器
//變?yōu)?4小時(shí)格式
}
}
void int_init(void)
{
MCUCR |= 0x00;
MCUCSR|= 0x00;
GICR |= 0x40;
}
#pragma interrupt_handler int0_isr:2
void int0_isr(void)//在外部中斷中進(jìn)行時(shí)間設(shè)置
{
uchar i=0,num=0,n=0,m=0,u=0,k=0,j=0,h=0;
CLI();//進(jìn)制中斷
LCD_init();//清屏
showprompt();//顯示提示信息
write_ds1302(0x80,0x80);//時(shí)鐘停止
write_ds1302(0x8e,0x00);//去除寫保護(hù)(control寄存器)
while(!(num==4)) //num含義:1(加一),2(選擇),3(設(shè)置),4(確定)
{
if(key_press()) //檢測(cè)是否有按鍵按下
{
num=key_scan(); //掃描并返回翻譯后的鍵碼
if(num==2)//進(jìn)入選擇狀態(tài)
{
i++;
switch(i)
{
case 1://設(shè)置年
LCD_init();//清屏
&nbs設(shè)置年
LCD_init();//清屏
while(!(n==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
n=key_scan(); //掃描并返回翻譯后的鍵碼
if(n==1)
time_data[0]++;//按一下年加一
}
//以下是時(shí)間微調(diào),因?yàn)樵贒S1302中寫入的是BCD碼,所以在實(shí)際中
//可以用下面的調(diào)整方式,以下只處理到60年
if(time_data[0]==0x0a)
{
time_data[0]=0x10;
}
if(time_data[0]==0x1a)
{
time_data[0]=0x20;
}
if(time_data[0]==0x2a)
{
time_data[0]=0x30;
}
if(time_data[0]==0x3a)
{
time_data[0]=0x40;
}
if(time_data[0]==0x4a)
{
time_data[0]=0x50;
}
write_ds1302(write_add[0],time_data[0]);//寫入地址和數(shù)據(jù)
time_pro();//時(shí)間處理
showyear();//顯示年
}
// break;不用終止程序,當(dāng)程序跳出上邊循環(huán)時(shí),會(huì)進(jìn)入下邊程序
case 2://月設(shè)置
LCD_init();//清屏
while(!(m==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
m=key_scan(); //掃描并返回翻譯后的鍵碼
if(m==1)
time_data[2]++;//按一下月加一
if(time_data[2]==0x13)//一年有12個(gè)月
time_data[2]=1;
}
//BCD碼處理
if(time_data[2]==0x0a)
{
time_data[2]=0x10;
}
if(time_data[2]==0x1a)
{
time_data[2]=0x20;
}
write_ds1302(write_add[2],time_data[2]);
time_pro();//時(shí)間處理
showmonth();//顯示月
}
//break;
case 3: //日設(shè)置
LCD_init();//清屏
while(!(u==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
u=key_scan(); //掃描并返回翻譯后的鍵碼
if(u==1)
time_data[3]++;//按一下日加一
if(time_data[3]==0x32)//一個(gè)月最多有31天
time_data[3]=1;
}
//BCD碼處理
if(time_data[3]==0x0a)
{
time_data[3]=0x10;
}
if(time_data[3]==0x1a)
{
time_data[3]=0x20;
}
if(time_data[3]==0x2a)
{
time_data[3]=0x30;
}
write_ds1302(write_add[3],time_data[3]);
time_pro();//時(shí)間處理
showdaytime();//顯示日
}
//break;
case 4: //小時(shí)設(shè)置
LCD_init();//清屏
while(!(k==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
k=key_scan(); //掃描并返回翻譯后的鍵碼
if(k==1)
time_data[4]++;//按一下小時(shí)加一
if(time_data[4]==0x25)//一天24小時(shí)
time_data[4]=1;
}
//BCD碼處理
if(time_data[4]==0x0a)
{
time_data[4]=0x10;
}
if(time_data[4]==0x1a)
{
time_data[4]=0x20;
}
write_ds1302(write_add[4],time_data[4]);
time_pro();//時(shí)間處理
showhour();//顯示小時(shí)
}
//break;
case 5: //分鐘設(shè)置
LCD_init();//清屏
while(!(j==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
j=key_scan(); //掃描并返回翻譯后的鍵碼
if(j==1)
time_data[5]++;//按一下分鐘加一
if(time_data[5]==0x5a)//一小時(shí)60分鐘
time_data[5]=0x00;
}
//BCD碼處理
if(time_data[5]==0x0a)
{
time_data[5]=0x10;
}
if(time_data[5]==0x1a)
{
time_data[5]=0x20;
}
if(time_data[5]==0x2a)
{
time_data[5]=0x30;
}
if(time_data[5]==0x3a)
{
time_data[5]=0x40;
}
if(time_data[5]==0x4a)
{
time_data[5]=0x50;
}
if(time_data[5]==0x5a)
{
time_data[5]=0x60;
}
write_ds1302(write_add[5],time_data[5]);
time_pro();//時(shí)間處理
showminute();//顯示分鐘
}
//break;
case 6: //星期設(shè)置
LCD_init();//清屏
while(!(h==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
h=key_scan(); //掃描并返回翻譯后的鍵碼
if(h==1)
time_data[1]++;//按一下小時(shí)加一
if(time_data[1]==0x08)//一天24小時(shí)
time_data[1]=1;
}
write_ds1302(write_add[2],time_data[2]);
time_pro();//時(shí)間處理
showweek();//顯示星期
}
default:
LCD_init();//清屏
showmessage();
break;
}
}
}
}
write_ds1302(0x8e,0x80);//(wp位置1)加入寫保護(hù)
write_ds1302(0x80,0x00);//時(shí)鐘開始
LCD_init();//清屏
SEI();
}
key.c:
#include <iom16v.h>
#include <macros.h>
#include "delay.h"
#define uchar unsigned char
#define uint&n月設(shè)置
LCD_init();//清屏
while(!(m==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
m=key_scan(); //掃描并返回翻譯后的鍵碼
if(m==1)
time_data[2]++;//按一下月加一
if(time_data[2]==0x13)//一年有12個(gè)月
time_data[2]=1;
}
//BCD碼處理
if(time_data[2]==0x0a)
{
time_data[2]=0x10;
}
if(time_data[2]==0x1a)
{
time_data[2]=0x20;
}
write_ds1302(write_add[2],time_data[2]);
time_pro();//時(shí)間處理
showmonth();//顯示月
}
//break;
case 3: //日設(shè)置
LCD_init();//清屏
while(!(u==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
u=key_scan(); //掃描并返回翻譯后的鍵碼
if(u==1)
time_data[3]++;//按一下日加一
if(time_data[3]==0x32)//一個(gè)月最多有31天
time_data[3]=1;
}
//BCD碼處理
if(time_data[3]==0x0a)
{
time_data[3]=0x10;
}
if(time_data[3]==0x1a)
{
time_data[3]=0x20;
}
if(time_data[3]==0x2a)
{
time_data[3]=0x30;
}
write_ds1302(write_add[3],time_data[3]);
time_pro();//時(shí)間處理
showdaytime();//顯示日
}
//break;
case 4: //小時(shí)設(shè)置
LCD_init();//清屏
while(!(k==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
k=key_scan(); //掃描并返回翻譯后的鍵碼
if(k==1)
time_data[4]++;//按一下小時(shí)加一
if(time_data[4]==0x25)//一天24小時(shí)
time_data[4]=1;
}
//BCD碼處理
if(time_data[4]==0x0a)
{
time_data[4]=0x10;
}
if(time_data[4]==0x1a)
{
time_data[4]=0x20;
}
write_ds1302(write_add[4],time_data[4]);
time_pro();//時(shí)間處理
showhour();//顯示小時(shí)
}
//break;
case 5: //分鐘設(shè)置
LCD_init();//清屏
while(!(j==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
j=key_scan(); //掃描并返回翻譯后的鍵碼
if(j==1)
time_data[5]++;//按一下分鐘加一
if(time_data[5]==0x5a)//一小時(shí)60分鐘
time_data[5]=0x00;
}
//BCD碼處理
if(time_data[5]==0x0a)
{
time_data[5]=0x10;
}
if(time_data[5]==0x1a)
{
time_data[5]=0x20;
}
if(time_data[5]==0x2a)
{
time_data[5]=0x30;
}
if(time_data[5]==0x3a)
{
time_data[5]=0x40;
}
if(time_data[5]==0x4a)
{
time_data[5]=0x50;
}
if(time_data[5]==0x5a)
{
time_data[5]=0x60;
}
write_ds1302(write_add[5],time_data[5]);
time_pro();//時(shí)間處理
showminute();//顯示分鐘
}
//break;
case 6: //星期設(shè)置
LCD_init();//清屏
while(!(h==2))//再次按選擇鍵就進(jìn)入下個(gè)項(xiàng)目的設(shè)置
{
if(key_press())
{
h=key_scan(); //掃描并返回翻譯后的鍵碼
if(h==1)
time_data[1]++;//按一下小時(shí)加一
if(time_data[1]==0x08)//一天24小時(shí)
time_data[1]=1;
}
write_ds1302(write_add[2],time_data[2]);
time_pro();//時(shí)間處理
showweek();//顯示星期
}
default:
LCD_init();//清屏
showmessage();
break;
}
}
}
}
write_ds1302(0x8e,0x80);//(wp位置1)加入寫保護(hù)
write_ds1302(0x80,0x00);//時(shí)鐘開始
LCD_init();//清屏
SEI();
}
key.c:
#include <iom16v.h>
#include <macros.h>
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
uchar key_press()//判斷按鍵是否被按下(按下返回1,沒(méi)按下返回0)
{
uchar j;
DDRD|=0X0F;//低四位為輸出
PORTD|=0X0F;//低四位輸出低電平
DDRD&=0XF0;//低四位為輸入
j=PIND;//讀一下輸入寄存器
j&=0X0F;//屏蔽高四位
if(j==0X0F)//如果j沒(méi)變化,則返回0,否則返回1
{
return 0;
}
else
{
return 1;
}
}
uchar key_scan()//按鍵掃描函數(shù)
{
uchar key;
delay(10);
if(key_press())//有按鍵按下時(shí)key_press()的值為1
{
key=PIND;//讀取PIND值
key&=0X0F;//去掉高4位
switch(key)//開關(guān)語(yǔ)句,用于判斷
{
case 0X0E://1110連接PD0的按鍵按下
key=1;break;
case 0X0D://1101連接PD1的按鍵按下
key=2;break;
case 0X0B://1011連接PD2的按鍵按下
key=3;break;
case 0X07://0111連接PD3的按鍵按下
key=4;break;
default://都不是時(shí)隨便返回一個(gè)值
key=16;
}
while(key_press());//在按鍵按下時(shí)執(zhí)行完上邊的程序后就執(zhí)行此循環(huán)
//當(dāng)按鍵松開時(shí)就跳出循環(huán),目的是按一下就執(zhí)行一次程序
}
else//沒(méi)有按下時(shí)隨便返回一個(gè)值
{
key=16;
}
return key;
}
程序未完,完整代碼下載: http://m.raoushi.com/f/1302cc.rar

