MCU-51:单片机实时时钟
目錄
- 一、什么是時鐘
- 1.1 實時時鐘
- 1.2 時序
- 二、DS1302實時時鐘
- 2.1 DS1302介紹
- 2.2 引腳定義和應用電路
- 三、代碼演示
- 3.1 數(shù)字時鐘
- 3.2 DS1302可調時鐘
- 注意:一定要看
一、什么是時鐘
1.1 實時時鐘
real time clock,真實時間,就是所謂的xx年x月x日x時x分x秒星期x
RTC是SoC中一個內部外設,RTC有自己獨立的晶振提供RTC時鐘源,內部有一些寄存器用來記錄時間(年月日時分秒星期)。一般情況下為了在系統(tǒng)關機時時間仍然在走,還會給RTC提供一個電池供電。
RTC在早期的單片機應用中是外置的,后來因為這個功能比較基礎比較常用,比較高端的單片機或者SOC就將RTC直接內置了。
1.2 時序
時序:字面意思,時序就是時間順序,實際上在通信中時序就是通信線上按照時間順序發(fā)生的電平變化,以及這些變化對通信的意義就叫時序。
注意,時序的橫軸的時間,所以對于字節(jié)是先發(fā)低位還是先發(fā)高位,可以看誰在前誰在后,在前的先發(fā),在后的后發(fā)。
二、DS1302實時時鐘
2.1 DS1302介紹
DS1302是由美國DALLAS公司推出的具有涓細電流充電能力的低功耗實時時鐘芯片。它可以對年、月、日、周、時、分、秒進行計時,且具有閏年補償?shù)榷喾N功能
2.2 引腳定義和應用電路
DS1302 與單片機之間能簡單地采用同步串行的方式進行通信,僅需用到三個口線:
RST 復位
I/O 數(shù)據(jù)線
SCLK 串行時鐘
Vcc2為主電源,VCC1為后備電源。
X1和X2是振蕩源,外接32.768kHz晶振。
RST是復位/片選線,通過把RST輸入驅動置高電平來啟動所有的數(shù)據(jù)傳送。RST輸入有兩種功能:首先,RST接通控制邏輯,允許地址/命令序列送入移位寄存器;其次,RST提供終止單字節(jié)或多字節(jié)數(shù)據(jù)傳送的方法。
當RST為高電平時,所有的數(shù)據(jù)傳送被初始化,允許對DS1302進行操作。如果在傳送過程中RST置為低電平,則會終止此次數(shù)據(jù)傳送,I/O引腳變?yōu)楦咦钁B(tài)。上電運行時,在Vcc>2.0V之前,RST必須保持低電平。只有在SCLK為低電平時,才能將RST置為高電平。
I/O為串行數(shù)據(jù)輸入輸出端(雙向)。SCLK為時鐘輸入端。
1、時鐘操作可通過AM/PM 指示決定采用24 或12 小時格式;
2、DS1302有12個寄存器,其中有7個寄存器與日歷、時鐘相關;
3、寄存器中存放的數(shù)據(jù)位為BCD碼形式;
操作DS1302的大致過程,就是將各種數(shù)據(jù)寫入DS1302的寄存器,以設置它當前的時間和格式。然后使DS1302開始運作,DS1302時鐘會按照設置情況運轉,再用單片機將其寄存器內的數(shù)據(jù)讀出。再用液晶顯示,就是我們常說的簡易電子鐘。
DS1302的寄存器樣式如下,我們看到:
第7 位永遠都是1;
第6 位,1表示RAM,尋址內部存儲器地址;0表示CK,尋址內部寄存器;
第5位到第1位,為RAM或者寄存器的地址;
最低位,高電平表示RD:即下一步操作將要“讀”;低電平表示W(wǎng):即下一步操作將要“寫”。
SEC:秒寄存器,注意具體右邊內容:低四位為SEC,高的次三位為10SEC,最高位CH為DS1302 的運行標志,當CH=0時,DS1302內部時鐘運行,反之CH=1時停止;
MIN:分寄存器;
HR:時寄存器,最高位為12/24 小時的格式選擇位,該位為1時表示12小時格式。當設置為12小時顯示格式時,第5位的高電平表示下午(PM);而當設置為24 小時格式時,第5位為具體的時間數(shù)據(jù)。
DATE:日寄存器;
MONTH:月寄存器;
DAY:周寄存器,注意一周只有7天,所以該寄存器只有低三位有效,周一到周日;
YEAR:年寄存器;
CONTROL:寫保護寄存器,當該寄存器最高位WP為1時,DS1302 只讀不寫,所以要在往DS1302 寫數(shù)據(jù)之前確保WP為0;
TRICKLE CHARGE REGISTER:涓細電流充電設置寄存器,我們知道,當DS1302掉電時,可以馬上調用外部電源保護時間數(shù)據(jù)。該寄存器就是配置備用電源的充電選項的。其中高四位(4個TCS)只有在1010 的情況下才能使用充電選項;低四位的情況,與DS1302內部電路有關。
CLOCK BURST:批量讀寫操作設置寄存器,設置該寄存器后,可以對DS1302的各個寄存器進行連續(xù)寫入。DS1302的另外一種讀寫方式。筆者還沒用過,感興趣的朋友可以嘗試。
寄存器定義表:
單字節(jié)讀寫時序圖如下:
三、代碼演示
3.1 數(shù)字時鐘
main.c
#include <REGX52.H> #include "LCD1602.h" #include "DS1302.h"unsigned char Second,Minute;void main() { LCD_Init();DS1302_Init();LCD_ShowString(1,1," - - ");LCD_ShowString(2,1," : : ");DS1302_WriteByte(0x8e,0x00);//關閉寫保護DS1302_SetTime();while(1){DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);} }DS1302.c
#include <REGX52.H>sbit DS1302_SCLK=P3^6; sbit DS1302_IO=P3^4; sbit DS1302_CE=P3^5;#define DS1302_SECOND 0x80 #define DS1302_MINUTE 0x82 #define DS1302_HOUR 0x84 #define DS1302_DATE 0x86 #define DS1302_MONTHE 0x88 #define DS1302_DAY 0x8A #define DS1302_YEAR 0x8C #define DS1302_WP 0x8Eunsigned char DS1302_Time[]={22,12,29,16,35,55,6};void DS1302_Init() {DS1302_CE=0;DS1302_SCLK=0; }void DS1302_WriteByte(unsigned char Command,Data) {unsigned char i;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0; }unsigned DS1302_ReadByte(unsigned char Command) {unsigned char i,Data=0x00;Command=Command|0x01;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=0;DS1302_SCLK=1;}for(i=0;i<8;i++){DS1302_SCLK=1;DS1302_SCLK=0;if(DS1302_IO){Data=Data|(0x01<<i);}}DS1302_CE=0;DS1302_IO=0;return Data; }void DS1302_SetTime(void) {DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);DS1302_WriteByte(DS1302_MONTHE,DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP,0x80); }void DS1302_ReadTime(void) {unsigned char Temp;Temp=DS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MONTHE);DS1302_Time[1]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DATE);DS1302_Time[2]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_HOUR);DS1302_Time[3]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MINUTE);DS1302_Time[4]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_SECOND);DS1302_Time[5]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DAY);DS1302_Time[6]=Temp/16*10+Temp%16; }DS1302.h
#ifndef __DS1302_H__ #define __DS1302_H__extern unsigned char DS1302_Time[];void DS1302_Init(); void DS1302_WriteByte(unsigned char Command,Data); unsigned DS1302_ReadByte(unsigned char Command); void DS1302_SetTime(void); void DS1302_ReadTime(void);#endifLCD1602.c
#include <REGX52.H>//引腳配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0//函數(shù)定義: /*** @brief LCD1602延時函數(shù),12MHz調用可延時1ms* @param 無* @retval 無*/ void LCD_Delay() {unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i); }/*** @brief LCD1602寫命令* @param Command 要寫入的命令* @retval 無*/ void LCD_WriteCommand(unsigned char Command) {LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602寫數(shù)據(jù)* @param Data 要寫入的數(shù)據(jù)* @retval 無*/ void LCD_WriteData(unsigned char Data) {LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602設置光標位置* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @retval 無*/ void LCD_SetCursor(unsigned char Line,unsigned char Column) {if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));} }/*** @brief LCD1602初始化函數(shù)* @param 無* @retval 無*/ void LCD_Init() {LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣LCD_WriteCommand(0x0c);//顯示開,光標關,閃爍關LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動LCD_WriteCommand(0x01);//光標復位,清屏 }/*** @brief 在LCD1602指定位置上顯示一個字符* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @param Char 要顯示的字符* @retval 無*/ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) {LCD_SetCursor(Line,Column);LCD_WriteData(Char); }/*** @brief 在LCD1602指定位置開始顯示所給字符串* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param String 要顯示的字符串* @retval 無*/ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) {unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);} }/*** @brief 返回值=X的Y次方*/ int LCD_Pow(int X,int Y) {unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result; }/*** @brief 在LCD1602指定位置開始顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:0~65535* @param Length 要顯示數(shù)字的長度,范圍:1~5* @retval 無*/ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以有符號十進制顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:-32768~32767* @param Length 要顯示數(shù)字的長度,范圍:1~5* @retval 無*/ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) {unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以十六進制顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:0~0xFFFF* @param Length 要顯示數(shù)字的長度,范圍:1~4* @retval 無*/ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}} }/*** @brief 在LCD1602指定位置開始以二進制顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:0~1111 1111 1111 1111* @param Length 要顯示數(shù)字的長度,范圍:1~16* @retval 無*/ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');} }LCD1602.h
#ifndef __LCD1602_H__ #define __LCD1602_H__//用戶調用函數(shù): void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif3.2 DS1302可調時鐘
main.c
#include <REGX52.H> #include "LCD1602.h" #include "DS1302.h" #include "key.h" #include "Timer0.h"unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;void TimeShow(void) {DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2); }void TimeSet(void) {if(KeyNum==2){TimeSetSelect++;TimeSetSelect=TimeSetSelect%6;//越界清零}if(KeyNum==3){DS1302_Time[TimeSetSelect]++;if(DS1302_Time[0]>99){DS1302_Time[0]=0;}if(DS1302_Time[1]>12){DS1302_Time[1]=1;}if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==7||DS1302_Time[1]==8||DS1302_Time[1]==10||DS1302_Time[1]==12){if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11){if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]>29){DS1302_Time[2]=1;}else{if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}}if(DS1302_Time[3]>23){DS1302_Time[3]=0;}if(DS1302_Time[4]>59){DS1302_Time[4]=0;}if(DS1302_Time[5]>59){DS1302_Time[5]=0;}}if(KeyNum==4){DS1302_Time[TimeSetSelect]--;if(DS1302_Time[0]<0){DS1302_Time[0]=99;}if(DS1302_Time[1]<1){DS1302_Time[1]=12;}if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==7||DS1302_Time[1]==8||DS1302_Time[1]==10||DS1302_Time[1]==12){if(DS1302_Time[2]<1){DS1302_Time[2]=31;}}else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11){if(DS1302_Time[2]<1){DS1302_Time[2]=30;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]<1){DS1302_Time[2]=29;}else{if(DS1302_Time[2]<1){DS1302_Time[2]=28;}}}}if(DS1302_Time[3]<0){DS1302_Time[3]=23;}if(DS1302_Time[4]<0){DS1302_Time[4]=59;}if(DS1302_Time[5]<0){DS1302_Time[5]=59;}}if(TimeSetSelect==0&&TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}else {LCD_ShowNum(1,1,DS1302_Time[0],2);}if(TimeSetSelect==1&&TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}else {LCD_ShowNum(1,4,DS1302_Time[1],2);}if(TimeSetSelect==2&&TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}else {LCD_ShowNum(1,7,DS1302_Time[2],2);}if(TimeSetSelect==3&&TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}else {LCD_ShowNum(2,1,DS1302_Time[3],2);}if(TimeSetSelect==4&&TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}else {LCD_ShowNum(2,4,DS1302_Time[4],2);}if(TimeSetSelect==5&&TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}else {LCD_ShowNum(2,7,DS1302_Time[5],2);}}void main() { LCD_Init();DS1302_Init();TImer0_Init();LCD_ShowString(1,1," - - ");LCD_ShowString(2,1," : : ");DS1302_WriteByte(0x8e,0x00);//關閉寫保護DS1302_SetTime();while(1){KeyNum=Key();if(KeyNum==1){if(MODE==0){MODE=1;}else if(MODE==1){MODE=0;DS1302_SetTime();}}switch(MODE){case 0:TimeShow();break;case 1:TimeSet();break;}} }void Timer0_Routine() interrupt 1 {static unsigned int T0Count;TL0=0x18;//設置定時初值TH0=0xFC;//設置定時初值T0Count++;if(T0Count>=500){T0Count=0;TimeSetFlashFlag=!TimeSetFlashFlag;} }DS1302.c
#include <REGX52.H>sbit DS1302_SCLK=P3^6; sbit DS1302_IO=P3^4; sbit DS1302_CE=P3^5;#define DS1302_SECOND 0x80 #define DS1302_MINUTE 0x82 #define DS1302_HOUR 0x84 #define DS1302_DATE 0x86 #define DS1302_MONTHE 0x88 #define DS1302_DAY 0x8A #define DS1302_YEAR 0x8C #define DS1302_WP 0x8Echar DS1302_Time[]={22,12,29,16,35,55,6};void DS1302_Init() {DS1302_CE=0;DS1302_SCLK=0; }void DS1302_WriteByte(unsigned char Command,Data) {unsigned char i;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0; }unsigned DS1302_ReadByte(unsigned char Command) {unsigned char i,Data=0x00;Command=Command|0x01;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=0;DS1302_SCLK=1;}for(i=0;i<8;i++){DS1302_SCLK=1;DS1302_SCLK=0;if(DS1302_IO){Data=Data|(0x01<<i);}}DS1302_CE=0;DS1302_IO=0;return Data; }void DS1302_SetTime(void) {DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);DS1302_WriteByte(DS1302_MONTHE,DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP,0x80); }void DS1302_ReadTime(void) {unsigned char Temp;Temp=DS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MONTHE);DS1302_Time[1]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DATE);DS1302_Time[2]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_HOUR);DS1302_Time[3]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MINUTE);DS1302_Time[4]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_SECOND);DS1302_Time[5]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DAY);DS1302_Time[6]=Temp/16*10+Temp%16; }LCD1602.c
#include <REGX52.H>//引腳配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0//函數(shù)定義: /*** @brief LCD1602延時函數(shù),12MHz調用可延時1ms* @param 無* @retval 無*/ void LCD_Delay() {unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i); }/*** @brief LCD1602寫命令* @param Command 要寫入的命令* @retval 無*/ void LCD_WriteCommand(unsigned char Command) {LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602寫數(shù)據(jù)* @param Data 要寫入的數(shù)據(jù)* @retval 無*/ void LCD_WriteData(unsigned char Data) {LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay(); }/*** @brief LCD1602設置光標位置* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @retval 無*/ void LCD_SetCursor(unsigned char Line,unsigned char Column) {if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));} }/*** @brief LCD1602初始化函數(shù)* @param 無* @retval 無*/ void LCD_Init() {LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣LCD_WriteCommand(0x0c);//顯示開,光標關,閃爍關LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動LCD_WriteCommand(0x01);//光標復位,清屏 }/*** @brief 在LCD1602指定位置上顯示一個字符* @param Line 行位置,范圍:1~2* @param Column 列位置,范圍:1~16* @param Char 要顯示的字符* @retval 無*/ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) {LCD_SetCursor(Line,Column);LCD_WriteData(Char); }/*** @brief 在LCD1602指定位置開始顯示所給字符串* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param String 要顯示的字符串* @retval 無*/ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) {unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);} }/*** @brief 返回值=X的Y次方*/ int LCD_Pow(int X,int Y) {unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result; }/*** @brief 在LCD1602指定位置開始顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:0~65535* @param Length 要顯示數(shù)字的長度,范圍:1~5* @retval 無*/ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以有符號十進制顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:-32768~32767* @param Length 要顯示數(shù)字的長度,范圍:1~5* @retval 無*/ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) {unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');} }/*** @brief 在LCD1602指定位置開始以十六進制顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:0~0xFFFF* @param Length 要顯示數(shù)字的長度,范圍:1~4* @retval 無*/ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}} }/*** @brief 在LCD1602指定位置開始以二進制顯示所給數(shù)字* @param Line 起始行位置,范圍:1~2* @param Column 起始列位置,范圍:1~16* @param Number 要顯示的數(shù)字,范圍:0~1111 1111 1111 1111* @param Length 要顯示數(shù)字的長度,范圍:1~16* @retval 無*/ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');} }key.c
#include <REGX52.H> #include "Delay.h"unsigned char Key() {unsigned char KeyNumber=0;if(P3_1==0){Delay(20);while(P2_1==0);Delay(20);KeyNumber=1;}if(P3_0==0){Delay(20);while(P2_0==0);Delay(20);KeyNumber=2;}if(P3_2==0){Delay(20);while(P2_2==0);Delay(20);KeyNumber=3;}if(P3_3==0){Delay(20);while(P2_3==0);Delay(20);KeyNumber=4;}return KeyNumber;}Timer0.c
#include <REGX52.H> //簡介:定時器0初始化,1毫秒@12.000MHZ void TImer0_Init() {//TMOD=0x01;//0000 0001TMOD=TMOD&0xF0;//把TM0D的低四位清零,高四位保持不變TMOD=TMOD|0x01;//把TM0D的最低位置置1,高四位保持不變TL0=0x18;//設置定時初值TH0=0xFC;//設置定時初值TF0=0;//清除TF0標志TR0=1;//計時器0開始計時ET0=1;EA=1;PT0=0; }//定時器中斷函數(shù)模板 //void Timer0_Routine() interrupt 1 //{ // static unsigned int T0Count; // TL0=0x18;//設置定時初值 // TH0=0xFC;//設置定時初值 // T0Count++; // if(T0Count>=1000) // { // T0Count=0; // P2_0=~P2_0; // } //}Timer0.h
#ifndef __TIMER0_H__ #define __TIMER0_H__void TImer0_Init(void);#endifkey.h
#ifndef __KEY_H__ #define __KEY_H__unsigned char Key();#endifDS1302.h
#ifndef __DS1302_H__ #define __DS1302_H__extern char DS1302_Time[];void DS1302_Init(); void DS1302_WriteByte(unsigned char Command,Data); unsigned DS1302_ReadByte(unsigned char Command); void DS1302_SetTime(void); void DS1302_ReadTime(void);#endifLCD1602.h
#ifndef __LCD1602_H__ #define __LCD1602_H__//用戶調用函數(shù): void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif注意:一定要看
千萬不要直接復制代碼,因為是模塊化編寫,模塊的代碼沒有往上復制,大家一定要自己動手跟著教學視屏自己寫!!!!!
總結
以上是生活随笔為你收集整理的MCU-51:单片机实时时钟的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++之this指针
- 下一篇: DIY客制化键盘