制作出來的實物圖如下:
實驗截圖.PNG (444.52 KB, 下載次數: 55)
下載附件
2020-11-30 10:24 上傳
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
仿真截圖.png (15.41 KB, 下載次數: 68)
下載附件
2020-11-30 10:25 上傳
單片機源程序如下:
- /**
- P2.7置低電平時,開機接入串口,自動進入時間設置界面
- 每秒鐘自動檢測溫度一次,并在LCD上顯示
- 每分鐘自動刷新日期、時間、溫度,在LCD上顯示,并在串口中輸出(方便電腦讀取)
- */
- #include <stdio.h>
- //#include <AT89X51.H>
- #include<reg51.h>
- #include"ds1302.h"
- #include"temp.h"
- #include <nokia_5110.h>
- //***********************************
- #define delay_time 25767
- sbit SETTIME = P2^7; //為0時,開機進入設置時間界面
- uchar TIME[7];
- char word2[10];
- //毫秒級延時函數
- void delay(unsigned int x)
- {
- unsigned char i;
- while(x--)
- {
- for(i = 0;i < 120;i++);
- }
- }
- char* tempDisplay(int temp) //lcd顯示
- {
-
- unsigned char datas[5]; //定義數組
- float tp;
- unsigned char ReturnTemp[9],x;
- if(temp< 0) //當溫度值為負數
- {
- ReturnTemp[0]='-';
- //因為讀取的溫度是實際溫度的補碼,所以減1,再取反求出原碼
- temp=temp-1;
- temp=~temp;
- tp=temp;
- temp=tp*0.0625*100+0.5;
- //留兩個小數點就*100,+0.5是四舍五入,因為C語言浮點數轉換為整型的時候把小數點
- //后面的數自動去掉,不管是否大于0.5,而+0.5之后大于0.5的就是進1了,小于0.5的就
- //算由?.5,還是在小數點后面。
-
- }
- else
- {
- // LcdWriteCom(0x80); //寫地址 80表示初始地址
- // LcdWriteData('+'); //顯示正
- ReturnTemp[0]='+';
- tp=temp;//因為數據處理有小數點所以將溫度賦給一個浮點型變量
- //如果溫度是正的那么,那么正數的原碼就是補碼它本身
- temp=tp*0.0625*100+0.5;
- //留兩個小數點就*100,+0.5是四舍五入,因為C語言浮點數轉換為整型的時候把小數點
- //后面的數自動去掉,不管是否大于0.5,而+0.5之后大于0.5的就是進1了,小于0.5的就
- //算加上0.5,還是在小數點后面。
- }
- datas[0] = temp / 10000;
- datas[1] = temp % 10000 / 1000;
- datas[2] = temp % 1000 / 100;
- datas[3] = temp % 100 / 10;
- datas[4] = temp % 10;
-
- // LcdWriteCom(0x82); //寫地址 80表示初始地址
- // LcdWriteData('0'+datas[0]); //百位
- // ReturnTemp[1]=datas[0]+48;
- if(datas[0]!=0)
- {
- ReturnTemp[1]=48+datas[0];
- x=1;
- } else {
- x=0;
- }
- //putchar(ReturnTemp[1]);
- // LcdWriteCom(0x83); //寫地址 80表示初始地址
- // LcdWriteData('0'+datas[1]); //十位
- if(( datas[1])!=0)
- {
- ReturnTemp[1+x]=datas[1]+48;
- x=x+1;
- } else {
- if(x!=0)
- {
- ReturnTemp[1+x]='0';
- x=x+1;
- }
- }
- // LcdWriteCom(0x84); //寫地址 80表示初始地址
- // LcdWriteData('0'+datas[2]); //個位
- ReturnTemp[1+x]='0'+datas[2];
- // putchar(ReturnTemp[1+x]);
- // LcdWriteCom(0x85); //寫地址 80表示初始地址
- // LcdWriteData('.'); //顯示 ‘.’
- ReturnTemp[2+x]='.';
- // LcdWriteCom(0x86); //寫地址 80表示初始地址
- // LcdWriteData('0'+datas[3]); //顯示小數點
- ReturnTemp[3+x]=48+datas[3];
- // putchar(ReturnTemp[3+x]);
- // LcdWriteCom(0x87); //寫地址 80表示初始地址
- // LcdWriteData('0'+datas[4]); //顯示小數點
- ReturnTemp[4+x]=datas[4]+48;
- ReturnTemp[5+x]='C';
- ReturnTemp[6+x]='\0';
- // printf("\n xx %s\n",ReturnTemp);
- return ReturnTemp;
- }
- //設置日期,格式為: setdate 2015-2-21, 可以省略0
- int setdate()
- {
- char year[5],month[3],day[3],i,
- y,m,d; //y存放年,m存放月, d存放日
- for(i=0;i<4;i++)
- year[i]=word2[i];
-
- for(i=0; i<10; i++) //檢查WORD2中字符的合法性,只能有數字或者-
- {
- if((word2[i]-48)<0 | word2[i]-48>9)
- {
- if(word2[i] == '\0')
- break;
- if(word2[i] != '-')
- {
- return 0;
- }
- }
- }
- if(word2[7]!='-' & word2[6] != '-')
- {
- return 0;
- }
- if(word2[7] == '-')
- {
- month[0]=word2[5];
- month[1]=word2[6];
- m = 1; //m=1的話,表示月份是2位,否則是1位,節約內存,借變量用一下
- }
- if(word2[6] == '-')
- {
- month[0] = '0';
- month[1] = word2[5];
- m = 0;
- }
- if(word2[9+m]!='\0' & word2[8+m] != '\0')
- {
- return 0;
- }
- if(word2[9+m] == '\0') //處理日期,因為要考慮1位的情況,使情況復雜多了
- {
- day[0] = word2[7+m];
- day[1] = word2[8+m];
- }
- if(word2[8+m]=='\0')
- {
- day[0] = '0';
- day[1] = word2[7+m];
- }
- year[4]='\0',month[2]='\0',day[2]='\0';
- y = (year[2]-48)*10 + (year[3]-48);
- m = (month[0]-48)*10 + (month[1]-48);
- d = (day[0]-48)*10 + day[1]-48; //先獲取年月日的值,再判斷合法性
- if(year[0] != (2+48) | year[1] != (0+48) | //這個簡單,必須是20XX年
- y > 100 | y < 1 | m > 12 | m <1) //年與月都簡單,日最麻煩
- {
- return 0;
- }
- if(!(m==1|m==3|m==5|m==7|m==8|m==10|m==12) & (d>=31)) //除了大月外都不能有31號
- {
- return 0;
- }
- if(d>31)
- {
- return 0;
- }
- if(m==2 & d>28)
- {
- if(!(((y%4)==0) & (d==29))) //2月是很蛋痛的,好在只是100年內
- {
- return 0;
- }
- }
- TIME[6]=(year[2]-48)*16+(year[3]-48);
- TIME[4]=(month[0]-48)*16+(month[1]-48);
- TIME[3]=(day[0]-48)*16+(day[1]-48);
-
- //下面這段把設置的日期寫入到DS1302中
- Ds1302Write(0x8E,0X00); //禁止寫保護,就是關閉寫保護功能
- for (i=0; i<7; i++)//寫入7個字節的時鐘信號:分秒時日月周年
- {
- Ds1302Write(WRITE_RTC_ADDR[i],TIME[i]);
- }
- Ds1302Write(0x8E,0x80); //打開寫保護功能
- /*
- putstring(year);
- putstring(month);
- putstring(day);
- putstring("\r\n");
- */
- Ds1302ReadTime();
- return 1;
- }
- //設置時間,格式為settimer 02:22, 不支持省略0
- int settime()
- {
- char minutes[3],hour[3],i,
- h,m; //h存放小時,m存放分
-
- for(i=0; i<6; i++) //檢查WORD2中字符的合法性,只能有數字或者:
- {
- if((word2[i]-48)<0 | word2[i]-48>9)
- {
- if(word2[i] == '\0')
- break;
- if(word2[i] != ':')
- {
- return 0;
- }
- }
- }
-
- if(word2[2]!=':' & word2[1] != ':')
- {
- return 0;
- }
- if(word2[2] == ':')
- {
- hour[0]=word2[0];
- hour[1]=word2[1];
- m = 1; //m=1的話,表示小時是2位,=0是1位
- }
- if(word2[1] == ':')
- {
- hour[0] = '0';
- hour[1] = word2[0];
- m = 0;
- }
- if(word2[4+m]!='\0' & word2[3+m] != '\0')
- {
- return 0;
- }
- if(word2[4+m] == '\0') //要考慮小時1位的情況
- {
- minutes[0] = word2[2+m];
- minutes[1] = word2[3+m];
- }
- if(word2[3+m]=='\0')
- {
- minutes[0] = '0';
- minutes[1] = word2[2+m];
- }
- minutes[2]='\0',hour[2]='\0';
- h = (hour[0]-48)*10 + (hour[1]-48);
- m = (minutes[0]-48)*10 + (minutes[1]-48);
- if(h > 23 | h <= 0 | m > 59 | m < 0) //這個比日期簡單多了
- {
- return 0;
- }
- Ds1302ReadTime();
- TIME[2]=(hour[0]-48)*16+(hour[1]-48); //BCD碼
- TIME[1]=(minutes[0]-48)*16+(minutes[1]-48);
- TIME[0]=0;
- Ds1302Write(0x8E,0X00); //禁止寫保護,就是關閉寫保護功能
- for (i=0; i<7; i++)//寫入7個字節的時鐘信號:分秒時日月周年
- {
- Ds1302Write(WRITE_RTC_ADDR[i],TIME[i]);
- }
- Ds1302Write(0x8E,0x80); //打開寫保護功能
- Ds1302ReadTime();
- // printf("\nThe current time: ");
- return 1;
- }
- void main()
- {
- char Secondcheck, //檢查秒有沒有改變
- Mincheck, //檢查分有沒有改變
- date[11];
- SCON = 0x50; //串口方式1,允許接收
- TMOD = 0x20; //定時器1定時方式2
- TCON = 0x40; //設定時器1開始計數
- TH1 = 0xFD; //11.0592MHz 1200波特率 只有9600能用未找原因
- TL1 = 0xFD;
- TI = 1;
- TR1 = 1; //啟動定時器
- printf ("Initing.... \n");
- tempDisplay(Ds18b20ReadTemp());
- LCD_init(); //初始化液晶
- LCD_clear();
- LCD_write_english_string(0,1," Initing.... ");
- delay(1000);
- Mincheck=11; //解決分鐘為0時初始化過久的問題
- if(SETTIME==0)
- {
- for(Mincheck=3;Mincheck>0;Mincheck--)
- {
- printf("\nPlease Set Date:");
- scanf("%s",word2);
- //printf("%s",word2);
- if(setdate())
- break;
- }
- for(Mincheck=3;Mincheck>0;Mincheck--)
- {
- printf("\nPlease Set Time:");
- scanf("%s",word2);
- //printf("%s\n",word2);
- if(settime())
- break;
- }
- }
- LCD_clear();//清除LCD
- while(1)
- {
- Ds1302ReadTime();//讀取時間1302
-
- delay(500);//多給點時間發送,但是影響秒的同步看來要改定時器發送
-
-
-
- if(Mincheck!=TIME[0])////如果時間秒變化就發送一次串口數據
-
- {
-
- Mincheck=TIME[0];//讓Mincheck等于秒,用于下次發送檢測
-
- date[0]='2',//發送年
- date[1]='0',
- date[2]=TIME[6]/16+48,//發送年
- date[3]=TIME[6]%16+48;
- date[4]='-',
- date[5]=(TIME[4]/16+48),//發送月
- date[6]=(TIME[4]%16+48),
- date[7]='-',
- date[8]=(TIME[3]/16+48),//發送日
- date[9]=TIME[3]%16+48;
- printf("%s",date);//發送以上全部的 date
-
- printf(" Time: ");
- putchar(TIME[2]/16+48);//發送時
- putchar(TIME[2]%16+48);
- putchar(':');//發送“ :”
- putchar(TIME[1]/16+48);//發送分
- putchar(TIME[1]%16+48);
- putchar(':');//發送“ :”
- putchar(TIME[0]/16+48);//發送秒
- putchar(TIME[0]%16+48);
- printf(" WD: ");
- printf(tempDisplay(Ds18b20ReadTemp()));
- putchar('\n');//結束串口開始符號
-
-
- LCD_write_english_string(25,1," bbjj ");
- LCD_write_english_string(8,0,date);
- LCD_write_chinese_string(0,3,12,1,TIME[2]/16,5);//顯示時
- LCD_write_chinese_string(10,3,12,1,TIME[2]%16,5);
- LCD_write_chinese_string(20,3,12,1,11,5);
- LCD_write_chinese_string(30,3,12,1,TIME[1]/16,5);//顯示分
- LCD_write_chinese_string(40,3,12,1,TIME[1]%16,5);
- LCD_write_chinese_string(50,3,12,1,11,5);
- LCD_write_chinese_string(60,3,12,1,TIME[0]/16,5);//顯示秒
- LCD_write_chinese_string(70,3,12,1,TIME[0]%16,5);
-
-
- }
-
-
- if(Secondcheck!=TIME[0])//如果溫度變化就顯示一下
- {
- Secondcheck=TIME[0];
- LCD_write_english_string(10,5,"WD:");
- LCD_write_english_string(30,5,tempDisplay(Ds18b20ReadTemp()));//讀取溫度顯示18B20
- }
-
- }
- }
復制代碼
51hei.png (8.64 KB, 下載次數: 73)
下載附件
2020-11-30 16:22 上傳
所有資料51hei提供下載:
51單片機&5110液晶顯示屏實現時間溫度串口發送(附仿真截圖).7z
(544.03 KB, 下載次數: 60)
2020-11-30 16:19 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|