引言
本設計以AT89S52單片機為控制核心,時鍾芯片DS1302提供時鍾源,配合LCD1602液晶顯示模塊,組成基本硬件系統,同時利用HC-05嵌入式藍牙串口通訊模塊,可在手機端進行日期、時間的校准。具有走時精確,功耗低,顯示直觀,調整簡單方便等優點。
功能描述
基本顯示:
第一行為日期,依次為:年-月-日-星期
第二行為時間,依次為:時:分:秒
說明:
每月的天數,閏年的天數可自動調整
藍牙校准日期:
命令d+年月日星期+#,如設置2016年12月8日星期四,手機發送命令:d16120804
藍牙校准時間:
命令t+時分秒+#,如設置15:11:46,手機發送命令:t151146#
硬件電路設計
硬件概述:
AT89S52單片機介紹:AT89S52_百度百科
DS1302時鍾芯片介紹:DS1302_百度百科
LCD1602液晶模塊介紹:LCD1602_百度百科
HC-05嵌入式藍牙串口通訊模塊介紹:HC-05
藍牙通信原理:
硬件電路圖:
程序設計:
主程序:main.c
1 #include <reg52.h> 2 #include <LCD1602.c> 3 #include <DS1302.c> 4 #include <bluetooth.c> 5 void serial_initial() 6 { 7 EA = 1; //開總中斷 8 ES = 1; //開串口中斷 9 TMOD = 0x20; //定時器1,方式2,8位自動重裝,作波特率發生器 10 TH1 = 0xfa; //波特率9600 11 TL1 = 0xfa; 12 TR1 = 1; 13 SCON = 0x50; //串口工作方式1,允許接收 14 PCON = 0x80; //SMOD=1,bps倍增9600 15 } 16 void clock_initial() 17 { 18 lcd_initial(); //1602初始化 19 serial_initial(); //中斷初始化 20 Set_DS1302_Time(0x80); //先寫入寄存器起始地址設置時鍾日歷初值 21 dis_string(0x80,"Date:11-11-11-11"); 22 dis_string(0xc0,"Time: 11:11:11 "); 23 flag_date = 0; 24 flag_time = 0; 25 bt_flag = 0; 26 } 27 28 void main() 29 { 30 clock_initial(); 31 while(1) 32 { 33 if(flag_date == 1&&cmd_end==1) 34 date_set(); 35 if(flag_time == 1&&cmd_end==1) 36 time_set(); 37 Read_DS1302_Time(0x81); 38 dis_twonum (5, 0, TimeData[6]); //年 39 dis_twonum (8, 0, TimeData[4]); //月 40 dis_twonum (11, 0, TimeData[3]); //日 41 dis_twonum (14, 0, TimeData[5]); //星期 42 dis_twonum (6, 1, TimeData[2]); //時 43 dis_twonum (9, 1, TimeData[1]); //分 44 dis_twonum (12, 1, TimeData[0]); //秒 45 Delay_Ms(1000); //延時 46 } 47 } 48 49 50 void serial_int() interrupt 4 51 { 52 uchar temp; //定義串口接收數據變量 53 54 ES = 0; //關串口中斷 55 RI = 0; //令接收中斷標志位為0(軟件清零) 56 temp = SBUF; //將接收到的數據送入變量 temp 57 data_deal(temp); //對收到數據進行處理 58 ES = 1; //開串口中斷 59 /*SBUF = temp; //將接收的數據發送回去 60 while(TI == 0); 61 TI = 0; */ 62 }
DS1302時鍾芯片驅動程序:DS1302.c
1 sbit TSCLK = P2 ^ 0; //時鍾 2 sbit TIO = P2 ^ 1; //數據 3 sbit TRST = P2 ^ 2; //使能 4 5 //時鍾日歷暫存數組,秒、分、時、日、月、周、年 初值為= 16年2月15日 周1 23:58:50 6 uchar TimeData[7] = {50, 58, 23, 15, 2, 1, 16}; 7 void Delay_Ms(uint ms) 8 { 9 uint i; 10 do { 11 i = 11059200 / 96000; 12 while(--i); //96T per loop 13 } while(--ms); 14 } 15 /*寫一字節*/ 16 void DS1302_W_Byte(uchar dat) 17 { 18 uchar i; 19 for(i = 0; i < 8; i++) //每次寫1bit,寫8次 20 { 21 TSCLK = 0; //拉低時鍾總線 22 TIO = dat & 0x01; //從一字節最低位開始寫 23 TSCLK = 1; //拉高時鍾總線,DS1302把數據讀走 24 dat >>= 1; //數據右移一位 25 } 26 } 27 /*讀一字節*/ 28 uchar DS1302_R_Byte() 29 { 30 uchar i, dat; 31 for(i = 0; i < 8; i++) 32 { 33 TSCLK = 0; 34 dat >>= 1; 35 if(TIO) dat |= 0x80;//讀取數據 36 TSCLK = 1; 37 } 38 return dat; //返回讀取的數據 39 } 40 /*寫數據,命令*/ 41 void DS1302_W_DAT(uchar cmd, uchar dat) 42 { 43 TRST = 0; 44 TSCLK = 0; 45 TRST = 1; 46 DS1302_W_Byte(cmd); 47 DS1302_W_Byte(dat); 48 } 49 /*讀數據*/ 50 uchar DS1302_R_DAT(uchar cmd) 51 { 52 uchar dat; 53 TRST = 0; 54 TSCLK = 0; 55 TRST = 1; 56 DS1302_W_Byte(cmd); 57 dat = DS1302_R_Byte(); 58 return dat; 59 } 60 61 /*清除寫保護*/ 62 void DS1302_Clear_WP() 63 { 64 DS1302_W_DAT(0x8e, 0x00); 65 } 66 /*設置寫保護*/ 67 void DS1302_Set_WP() 68 { 69 DS1302_W_DAT(0x8e, 0x80); 70 TRST = 0; 71 TSCLK = 0; 72 } 73 /*時間預設*/ 74 void Set_DS1302_Time(uchar addr) 75 { 76 uchar i, j; 77 DS1302_Clear_WP(); //清除寫保護 78 for(i = 0; i < 7; i++) //寫入7個字節的時鍾初始值 79 { 80 j = TimeData[i] / 10; //BCD碼轉換 81 TimeData[i] %= 10; 82 TimeData[i] += j * 16; 83 DS1302_W_DAT(addr, TimeData[i]); 84 addr += 2; 85 } 86 DS1302_Set_WP(); //開寫保護 87 } 88 /*讀取1302時間*/ 89 void Read_DS1302_Time(uchar addr) 90 { 91 uchar i; 92 DS1302_Clear_WP(); 93 for(i = 0; i < 7; i++) //從DS1302讀取7個字節的時鍾日歷數據 94 { 95 TimeData[i] = DS1302_R_DAT(addr); 96 addr += 2; 97 } 98 DS1302_Set_WP(); 99 } 100
LCD1602液晶模塊驅動程序:LCD1602.c
1 #define uint unsigned int 2 #define uchar unsigned char 3 sbit RS = P2 ^ 3; 4 sbit RW = P2 ^ 4; 5 sbit EN = P2 ^ 5; 6 7 void check_busy() //檢測是否忙 8 { 9 uchar dat; 10 P0 = 0xff; 11 RS = 0; 12 RW = 1; 13 do 14 { 15 EN = 1; 16 dat = P0; 17 EN = 0; 18 } while(dat & 0x80); 19 } 20 21 void write_cmd(uchar cmd) //寫命令 22 { 23 check_busy(); 24 RS = 0; 25 RW = 0; 26 P0 = cmd; 27 EN = 1; 28 EN = 0; 29 } 30 31 void write_data(uchar dat) //寫數據 32 { 33 check_busy(); 34 RS = 1; 35 RW = 0; 36 P0 = dat; 37 EN = 1; 38 EN = 0; 39 } 40 /*顯示一位數字*/ 41 void dis_onenum (uchar X, uchar Y, uchar dat) 42 { 43 if(Y) X |= 0X40; 44 X |= 0X80; 45 write_cmd(X); 46 write_data(dat); 47 } 48 /*顯示兩位數字*/ 49 void dis_twonum (uchar X, uchar Y, uchar dat) 50 { 51 dis_onenum (X, Y, dat / 16 + '0'); 52 dis_onenum (X+1, Y, dat % 16 + '0'); 53 } 54 /*顯示字符串*/ 55 void dis_string(uchar location,uchar *p) 56 { 57 write_cmd(location); 58 while(*p) 59 { 60 write_data(*p); 61 p++; 62 } 63 } 64 65 void lcd_initial() 66 { 67 write_cmd(0x38); 68 write_cmd(0x0c); 69 write_cmd(0x06); 70 write_cmd(0x01); 71 } 72
藍牙控制程序:bluetooth.c
1 uchar date[20],time[20]; 2 uchar cmd_index, cmd_start, cmd_end, bt_flag; 3 bit flag_time, flag_date; 4 5 void time_set() 6 { 7 uchar a; 8 uchar i, j, addr = 0x80; 9 for(a = 1; a < 7; a++) 10 time[a] = time[a] - 0x30; //數據處理 11 TimeData[2] = (time[1] * 10 + time[2]) % 24; //小時 12 TimeData[1] = (time[3] * 10 + time[4]) % 60; //分鍾 13 TimeData[0] = (time[5] * 10 + time[6]) % 60; //秒 14 15 DS1302_Clear_WP(); //清除寫保護 16 for(i = 0; i < 3; i++) //寫入時間設置值 17 { 18 j = TimeData[i] / 10; //BCD碼轉換 19 TimeData[i] %= 10; 20 TimeData[i] += j * 16; 21 DS1302_W_DAT(addr, TimeData[i]); 22 addr += 2; 23 } 24 DS1302_Set_WP(); //開寫保護 25 flag_time = 0; 26 } 27 28 void date_set() 29 { 30 uchar a; 31 uchar i, j, addr = 0x86; 32 for(a = 1; a < 9; a++) 33 date[a] = date[a] - 0x30; //對數據處理 34 TimeData[3] = (date[5] * 10 + date[6]) ; //日 35 TimeData[4] = (date[3] * 10 + date[4]) ; //月 36 TimeData[6] = (date[1] * 10 + date[2]) ; //年 37 TimeData[5] = (date[7] * 10 + date[8]) ; //周 38 39 DS1302_Clear_WP(); 40 for(i = 3; i < 7; i++) //寫入日期設置值 41 { 42 j = TimeData[i] / 10; //BCD碼轉換 43 TimeData[i] %= 10; 44 TimeData[i] += j * 16; 45 DS1302_W_DAT(addr, TimeData[i]); 46 addr += 2; 47 } 48 DS1302_Set_WP(); //開寫保護 49 flag_date = 0; 50 } 51 52 void data_deal(uchar data_buf) 53 { 54 switch(data_buf) 55 { 56 case 'd': 57 cmd_start = 1; 58 cmd_end = 0; 59 flag_date = 1; 60 cmd_index = 0; 61 bt_flag = 1; 62 break; 63 case 't': 64 cmd_start = 1; 65 cmd_end = 0; 66 flag_time = 1; 67 cmd_index = 0; 68 bt_flag = 2; 69 break; 70 case '#': 71 cmd_start = 0; 72 cmd_end = 1; 73 break; 74 default:break; 75 } 76 if (cmd_start == 1) 77 { 78 switch (bt_flag) 79 { 80 case 1: 81 date[cmd_index] = data_buf; 82 cmd_index++; 83 break; 84 case 2: 85 time[cmd_index] = data_buf; 86 cmd_index++; 87 break; 88 default:break; 89 } 90 if (cmd_index >= 20) 91 cmd_index = 0; 92 } 93 }
總結:
2016.12.05——2016.12.07三天的單片機課程設計結束了,我的課程設計是——《基於AT89S52單片機和DS1302時鍾芯片的電子鍾(可手機藍牙校准)》,此次設計讓我對AT89S52單片機有了更深的認識,為了完成設計,我又學習了DS1302時鍾芯片時間寫入,時間讀取等基本的讀寫操作時序,對DS1302的操作方法有了一定了解。
當液晶時鍾第一次被成功的校准時,我很激動和興奮,也很有成就感。由於使用了藍牙串口校准時間,所以又復習了串口通訊的原理,在調試的過程中,對串口數據的處理也有了一定的經驗:由於串口是一個一個字符接收的,當接收到下一個字符時,上一個字符就會丟失,為了保存接收到的每個字符,先將接收到的數據存放到數組中,然后數組指針加一,這樣串口接收的每一個數據就會按照接收的先后順序有序的存放到數組中,然后數組中的元素就可以被我們拿來進行各種操作了,如本設計中的設置時間和日期。
由於課程設計的時間較短,所以此設計僅在時間顯示的基礎上,增加了藍牙串口校准時間功能,此設計還有很多可以完善和改進的功能,如:
1.增加鬧鍾功能,增加按鍵校准時間日期、設置鬧鍾功能,
3.增加星期計算功能,調整時只需調整年月日,調整完畢后自動計算出星期幾,
4.增加DS18B20溫度傳感器實時顯示溫度,手機可遠程獲取溫度,
5.星期顯示為英文縮寫,如周一:Mon,
6.簡單報警功能, 等其他功能,這些功能都是可以實現的。
雖然單片機課程設計結束了, 但我的學習之路還沒有結束,我將繼續學習51單片機的其他擴展功能,以及其他的通訊協議,如IIC通訊,SPI通訊,紅外通信,WiFI無線通訊,為以后學習性能更強大的單片機做個准備,MCS-51系列單片機雖然是低功耗可編程處理器,但它也只是8位微處理器,它的指令執行速度、驅動能力、程序存儲等其他片內資源都是非常有限的,已經不能滿足當今科技發展的需要,所以為了更好的發展,還要學習其他性能更強大的單片機。課程設計結束了,還要感謝老師的的指導我才能完成課程設計,衷心的感謝老師的幫助和提出的建議。
今天開通了博客園的個人博客,因為之前是用的新浪博客,沒有插入代碼的功能,所以排版非常亂,現在有了這個博客就可以美美的插入代碼了,哈哈,就把上學期做的課程設計作為新家的第一篇文章吧!
2017-03-12 18:24:01
歡迎大家關注我的個人博客 http://www.wangchaochao.top/
微信掃碼關注我的公眾號
不定期更新個人學習筆記和技術總結,歡迎大家互相學習交流!