?? 可調時鐘.c
字號:
//******DS1302驅動程序*************
#include"REGX52.H"
#include "stdio.h"
#include <intrins.h>
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
#define AM(X) X
#define PM(X) (X+12) // 轉成24小時制
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C
#define DS1302_RAM(X) (0xC0+(X)*2) //用于計算 DS1302_RAM 地址的宏
sbit DS1302_CLK = P0^7; //實時時鐘時鐘線引腳
sbit DS1302_IO = P0^6; //實時時鐘數據線引腳
sbit DS1302_RST = P0^5; //實時時鐘復位線引腳
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
sbit rs = P0^0; //LCD數據/命令選擇端(H/L)
sbit rw = P0^1; //LCD讀/寫選擇端(H/L)
sbit ep = P0^2;
sbit PRE = P3^2;
sbit SET = P3^1;
unsigned char data DateString[9]; //lcd上排顯示緩沖區
unsigned char data TimeString[9]; //lcd下排顯示緩沖區
unsigned char Second, Minute,Hour,Week,Day, Month, Year;
unsigned char flag1,skey,vkey;
void pro_key();
// 延時程序
void delay(unsigned char ms)
{ while(ms--)
{ unsigned char i;
for(i = 0; i< 250; i++)
{
_nop_(); //執行一條_nop_()指令為一個機器周期
_nop_();
_nop_();
_nop_();
}
}
}
//測試LCD忙碌狀態
bit lcd_busy()
{
bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result =(bit)(P1&0x80); //LCD的D0--D7中,D7=1為忙碌,D7=0為空閑
ep = 0;
return result;
}
//寫入指令到LCD
void lcd_wcmd(char cmd)
{
while(lcd_busy()); //當lcd_busy為1時,再次檢測LCD忙碌狀態,lcd-busy為0時,開始寫指令
rs = 0;
rw = 0;
ep = 0;
_nop_();
_nop_();
P1 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
//寫入數據到LCD
void lcd_wdat(char dat)
{
while(lcd_busy()); //當lcd_busy為1時,再次檢測LCD忙碌狀態,lcd-busy為0時,開始寫數據
rs = 1;
rw = 0;
ep = 0;
P1 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
//LCD數據指針位置程序
void lcd_pos(char pos)
{
lcd_wcmd(pos|0x80); //數據指針=80+地址碼(00H~27H,40H~67H)
}
//顯示處理程序
void pro_display()
{ unsigned char i;
lcd_pos(0x00);
for (i=0;i<9;i++)
{lcd_wdat(DateString[i]);}
lcd_pos(0x40);
for (i=0;i<9;i++)
{lcd_wdat(TimeString[i]);}
}
//LCD初始化設定
void lcd_init()
{
lcd_wcmd(0x38); //設置LCD為16X2顯示,5X7點陣,八位數據借口
delay(1);
lcd_wcmd(0x0c); //LCD開顯示及光標設置(光標不閃爍,不顯示"-")
delay(1);
lcd_wcmd(0x06); //LCD顯示光標移動設置(光標地址指針加1,整屏顯示不移動)
delay(1);
lcd_wcmd(0x01); //清除LCD的顯示內容
delay(1);
}
void DS1302InputByte(unsigned char d) //實時時鐘寫入一字節(內部函數)
{
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相當于匯編中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;
}
}
unsigned char DS1302OutputByte(void) //實時時鐘讀取一字節(內部函數)
{
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相當于匯編中的 RC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;
}
return(ACC);
}
void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要寫的數據
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 寫1Byte數據
DS1302_CLK = 1;
DS1302_RST = 0;
}
unsigned char Read1302(unsigned char ucAddr) //讀取DS1302某地址的數據
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 讀1Byte數據
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);
}
void DS1302_SetProtect(bit flag) //是否寫保護
{
if(flag)
Write1302(0x8E,0x10);
else
Write1302(0x8E,0x00);
}
void DS1302_SetTime(unsigned char Address, unsigned char Value) // 設置時間函數
{
DS1302_SetProtect(0);
Write1302(Address, ((Value/10)<<4 | (Value%10)));
}
void DS1302_GetTime()
{
unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MINUTE);
Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
}
void DateToStr()
{
DateString[0] =Year/10 + 48;
DateString[1] =Year%10 + 48;
DateString[2] = 0x2d;
DateString[3] =Month/10 +48;
DateString[4] =Month%10 +48;
DateString[5] = 0x2d;
DateString[6] =Day/10 +48;
DateString[7] =Day%10 +48;
DateString[8] = 0x20;
TimeString[0] =Hour/10 + 48;
TimeString[1] =Hour%10 + 48;
TimeString[2] = 0x2d;
TimeString[3] =Minute/10 + 48;
TimeString[4] =Minute%10 + 48;
TimeString[5] = 0x2d;
TimeString[6] =Second/10 + 48;
TimeString[7] =Second%10 + 48;
TimeString[8] = 0x20;
}
void Initial_DS1302(void)
{
unsigned char Second=Read1302(DS1302_SECOND);
if(Second&0x80)
DS1302_SetTime(DS1302_SECOND,0);
}
void DS1302_TimeStop(bit flag) // 是否將時鐘停止
{
unsigned char Data;
Data=Read1302(DS1302_SECOND);
DS1302_SetProtect(0);
if(flag)
Write1302(DS1302_SECOND, Data|0x80);
else
Write1302(DS1302_SECOND, Data&0x7F);
}
//閏年的計算
bit leap_year()
{
bit leap;
if((Year%4==0&&Year%100!=0)||Year%400==0)//閏年的條件
leap=1;
else
leap=0;
return leap;
}
unsigned char scan_key()
{
skey=0x00; //給變量vkey置初值
skey|=PRE; //讀取PRE鍵的狀態
skey=skey<<1; //將PRE鍵的狀態存于skey的B1位
skey|=SET; //讀取SET鍵的狀態,并存于skey的B0位
return skey; //返回skey的鍵值(即PRE,SET的狀態)
}
//外部中斷INT0中斷處理程序
void int0() interrupt 0
{
TR0=0; //禁止Timer0
IE=0; //禁止中斷
lcd_wcmd(0x0e); //顯示光標"_",整個光標不閃爍
DateToStr();
pro_display();
lcd_pos(0x01); //使光標位于第一個調整項下
flag1=0;
vkey=0x03;
while(flag1^0x07)
{skey = scan_key();
//掃描按鍵狀態
if (skey^vkey) //若skey與vkey相同,跳出循環,相異執行循環體
{ delay(10); //去按鍵抖動
skey = scan_key(); //轉回掃描按鍵狀態
if (skey^vkey) //若skey與vkey相同,跳出循環,相異執行循環體
{ vkey=skey; //將skey的值付給vkey
if (skey==0x01) //PRE鍵按下
{ flag1++; //調整標志位加1
switch (flag1) //將光標置于相應調整位置
{
case 1: lcd_pos(0x01);DS1302_TimeStop(1); break; //光標置年調整位置
case 2: lcd_pos(0x04);break; //光標置月調整位置
case 3: lcd_pos(0x07);break; //光標置日
case 4: lcd_pos(0x41);break;
//光標置小時設置位置
case 5: lcd_pos(0x44);break; //光標置分鐘設置位置
case 6: lcd_pos(0x47);break; //光標置秒時報警設置位置調整位置
case 7: DS1302_TimeStop(0);break; //啟動時鐘
default:break;
}
}
if (skey==0x02) //SET鍵按下
pro_key(); //轉設置按鍵處理程序
}
}
}
lcd_wcmd(0x0c); //設置LCD開顯示及光標不閃爍,不顯示"-"
lcd_wcmd(0x01); //清除LCD的顯示內容
IE=0x81; //CPU開中斷,INT0,INT1,開中斷
TR0=1; //Timer0啟動
delay(30);
}
//設置按鍵處理程序
void pro_key()
{
switch (flag1)
{
case 1:Year++;
DS1302_SetTime(0X8C, Year);
if (Year> 99) Year= 0;
DateToStr();
pro_display();
lcd_pos(0x01);break;
case 2:Month++;
DS1302_SetTime(0X88, Month);
if (Month>12) Month=1;
DateToStr();
pro_display();
lcd_pos(0x04);break;
case 3:Day++;
DS1302_SetTime(DS1302_DAY , Day);
if (Month==1||Month==3||Month==5||Month==7||Month==8||Month==10||Month==12)
if (Day>31) Day=1; //大月31天
if (Month==4||Month==6||Month==9||Month==11)
if (Day>30) Day=1; //小月30天
if (Month==2)
{if(leap_year()) //閏年的條件
{if (Day>29) Day=1;} //閏年2月為29天
else
{if (Day>28) Day=1;}} //平年2月為28天
DateToStr();
pro_display();
lcd_pos(0x07);break;
case 4:Hour++;
DS1302_SetTime(DS1302_HOUR , Hour);
if (Hour>23) Hour=0;
DateToStr();
pro_display();
lcd_pos(0x41);break;
case 5: Minute++;
DS1302_SetTime(DS1302_MINUTE , Minute);
if ( Minute>59) Minute=0;
DateToStr();
pro_display();
lcd_pos(0x44);break;
case 6:Second++;
DS1302_SetTime(DS1302_SECOND ,Second);
if (Second>59) Second=0;
DateToStr();
pro_display();
lcd_pos(0x47);break;
default: break ;
}
}
main()
{ IE=0X81;
IT0=0;
TR0=1;
TH0=0XDC;
TL0=0X00;
TR0=1;
lcd_init();
Initial_DS1302();
while(1)
{DS1302_GetTime();
DateToStr();
pro_display();
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -