1. 程式人生 > >【微控制器】時鐘及溫度的顯示

【微控制器】時鐘及溫度的顯示

回頭看我所寫的文章,基本都是軟體方面的,是個典型的“欺軟怕硬”的人。然而,在最開始的時候,我學習的是硬體。在前面文章《我的2013–一起從心開始》一文中寫道,我在大一暑假的時候開始了微控制器的學習,在大二、大三期間做過些小東西。剛進入程式設計師的領域的時候,顯然是微控制器帶我入了門。下面我將寫寫用微控制器做過的一些東西,權當紀念。

本文介紹我大一暑假學完微控制器後,在大二上學期為參加學校星火盃而完成的作品(最終沒有參加比賽)。這個電子製作是關於用微控制器顯示時間的作品,其功能就用微控制器控制LCD、LED來顯示時間和溫度。

功能描述

  • 顯示精確度為0.1攝氏度的溫度(低於0攝氏度和高於100攝氏度響鈴)
  • 液晶時鐘,斷電後仍然繼續走動,每月誤差不到一分鐘,無電源可工作10年左右,區分平年和閏年;
  • 指標式時鐘(黃燈為時針,紅色為分針,最小誤差5分鐘,整點報時)與考試計時器(計時2兩小時)

電子元器件

  • 2個微控制器最小系統 (微控制器型號為STC89C52)
  • 雙色發光二級管
  • 液晶顯示屏
  • 按鍵
  • DS12C887時鐘晶片
  • DS18b20溫度感測器
  • 蜂鳴器(整點報時)
  • LED數碼管(顯示溫度)

作品展示圖

  • 由於所有電路都是由杜邦線連線,所以存在接觸不良,導致有時不能正常顯示,於是就沒有參賽,下圖為雙色二極體的顯示。
    這裡寫圖片描述
    這裡寫圖片描述
  • 下圖為用1602液晶顯示日期和時間
    這裡寫圖片描述
    這裡寫圖片描述
  • 下圖為用數碼管來顯示溫度
    這裡寫圖片描述
  • 下圖為作品的佈線,簡直是亂成一團,要是用PCB就好了。
    這裡寫圖片描述

附錄:程式碼實現

對於硬體來說,給程式碼不給管腳圖沒啥意義,不過由於年代久遠,我已經找不到當初設計的電路圖了。但仍然給出程式碼圖,希望能起到一點點的參考作用。

//--------------------------------溫度顯示程式 第一個晶片------------------------------------------------------------------//

#include<reg52.h>
#include<intrins.h>
#include<stdio.h>
#define uchar unsigned char #define uint unsigned int sbit ds=P2^2; unsigned int te; unsigned char code tabledu[]= { 0x3f0x060x5b0x4f 0x660x6d0x7d0x07 0x7f0x6f0x770x7c 0x390x5e0x790x71 }; unsigned char code tabledu1[]= { 0xbf0x860xdb0xcf 0xe60xed0xfd0x87 0xff0xef0xf70xfc 0x390x5e0x790x71 }; unsigned char code tablewe[]= { 0xfe0xfd0xfb0xf70xef0xdf }; void delayxms(unsigned int x) { unsigned int ij; for(i=x;i>0;i--) for(j=110;j>0;j--); } void delayx2us(unsigned char t) { while(--t); } void dsreset() // 復位 { ds=1; _nop_(); ds=0; delayx2us(200);//注意時間 ds=1; delayx2us(20); } void writetemp(unsigned char dat) { unsigned char i=0; for (i=8; i>0; i--) { ds = 0; ds = dat&0x01; delayx2us(25); ds = 1; dat>>=1; } delayx2us(25); } unsigned char readtemp(void) { unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) { ds = 0; // 給脈衝訊號 dat>>=1; ds = 1; // 給脈衝訊號 if(ds) dat|=0x80; delayx2us(25); } return(dat); } uint temp() { uint ab; dsreset(); delayxms(1); writetemp(0xcc); writetemp(0x44); delayxms(1); dsreset(); delayxms(1); writetemp(0xcc); writetemp(0xbe); delayx2us(50); a=readtemp(); b=readtemp(); a=a*10; te=b*160+a/16; return te; } void disp(long int num) { uchar cde; c=num/100; d=num%100/10; e=num%10; P0=tabledu[c]; P1=0xfe; delayxms(6); P0=tabledu1[d]; P1=0xfd; delayxms(6); P0=tabledu[e]; P1=0xfb; delayxms(6); P0=0xcc; P1=0xf7; delayxms(2); } void main() { while(1) { disp(temp()); if((temp()>=1000)||(temp()<=0)) beep=0; else beep=1; } //--------------------------------時鐘顯示程式 第二個晶片------------------------------------------------------------------// #include<reg52.h> #define uchar unsigned char #define uint unsigned int //流水燈鎖存器 sbit wela1=P2^0;//1 sbit wela2=P2^1;//2 sbit wela3=P2^2;//1 sbit wela4=P2^3;//2 //蜂鳴器 sbit beep=P2^4; //按鍵 sbit key1=P2^5;//功能選擇鍵 sbit key2=P2^6;//+(時間、日期加) sbit key3=P2^7;//-(時間、日期減) sbit key4=P3^7;//模式鍵(平時或考試) //液晶介面 sbit lcden=P3^4; sbit lcdrs=P3^5; sbit lcdwr=P3^6; //ds12c887介面 sbit dscs=P1^6; sbit dsas=P1^7; sbit dsrw=P3^0; sbit dsds=P3^1; sbit dsirq=P3^3; //定義變數 uchar hour minseccountriweekyuenianj; //uchar counthcountmcountycountkloop1; uchar code table1[]=" - - "; uchar code table2[]=" : : "; uchar code table3[]="SUNMONTUEWEDTHUFRISAT"; //延遲函式 void delayxms(unsigned int x) { unsigned int ij; for(i=x;i>0;i--) for(j=110;j>0;j--); } //--------------------1602液晶函式---------------------------------- //液晶寫命令 void write_com(unsigned char com) { lcdrs=0; P0=com; delayxms(5); lcden=1; delayxms(5); lcden=0; } //液晶寫資料 void write_data(unsigned char date) { lcdrs=1; P0=date; delayxms(5); lcden=1; delayxms(5); lcden=0; } //液晶初始化 void lcdinit() { lcdwr=0; write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01); } // 液晶顯示 void disp() { uchar i; write_com(0x80); for(i=0;i<15;i++) { write_data(table1[i]); delayxms(5); } write_com(0x80+0x40); for(i=0;i<12;i++) { write_data(table2[i]); delayxms(5); } } //寫時間 void write_sfm(uchar addressuchar shu) { uchar shige; shi=shu/10; ge=shu%10; write_com(0x80+0x40+address); write_data(0x30+shi); write_data(0x30+ge); } //寫日曆 void write_calendar(uchar addressuchar shu) { uchar shige; shi=shu/10; ge=shu%10; write_com(0x80+address); write_data(0x30+shi); write_data(0x30+ge); } //-------------------------DS12C887程式---------------------------- //寫時鐘 void write_ds(uchar adduchar date) { dscs=0; dsas=1; dsds=1; dsrw=1; P0=add; dsas=0; dsrw=0; P0=date; dsrw=1; dsas=1; dscs=1; } //讀時鐘 uchar read_ds(uchar add) { uchar ds_date; dsas=1; dsds=1; dsrw=1; dscs=0; P0=add; dsas=0; dsds=0; P0=0xff; ds_date=P0; dsds=1; dsas=1; dscs=1; return ds_date; } //寫星期 void write_week(uchar date) { write_com(0x80+12); write_data(table3[3*date]); write_data(table3[3*date+1]); write_data(table3[3*date+2]); } //鍵盤檢測 void keyscan() //鍵盤檢測 key1 為功能鍵 key2為加 key3為減 :時間與日期的改變 { if(key1==0) { delayxms(10); if(key1==0) { while(!key1); count++; if(count==1) { write_com(0x80+0x40+11); write_com(0x0f); } if(count==2) { write_com(0x80+0x40+8); write_com(0x0f); } if(count==3) { write_com(0x80+0x40+5); write_com(0x0f); } if(count==4) { write_com(0x80+13); write_com(0x0f); } if(count==7) { write_com(0x80+10); write_com(0x0f); } if(count==6) { write_com(0x80+7); write_com(0x0f); } if(count==5) { write_com(0x80+4); write_com(0x0f); } if(count==8) { count=0; write_com(0x0c); write_ds(0sec); write_ds(2min); write_ds(4hour); } } } if(key2==0) { delayxms(10); if(key2==0) { while(!key2); if(count==1) { sec++; if(sec==60) sec=0; write_ds(0sec); write_sfm(10sec); write_com(0x80+0x40+11); } if(count==2) { min++; if(min==60) min=0; write_ds(2min); write_sfm(7min); write_com(0x80+0x40+8); } if(count==3) { hour++; if(hour==24) hour=0; write_ds(4hour); write_sfm(4hour); write_com(0x80+0x40+5); } if(count==4) { week++; if(week==7) week=0; write_week(week); write_ds(6week); } if(count==5) { nian++; if(nian==100) nian=0; write_ds(9nian); write_calendar(3nian); write_com(0x80+4); } if(count==6) { yue++; if(yue==13) yue=1; write_ds(8yue); write_calendar(6yue); write_com(0x80+7); } if(count==7) // 判斷閏年 { ri++; week++; if(nian%4==0) { if((yue==4)||(yue==6)||(yue==9)||(yue==11)) { if(ri==31) ri=1; } else if(yue==2) { if(ri==30) ri=1; } else { if(ri==32) ri=1; } } if(nian%4!=0) { if((yue==4)||(yue==6)||(yue==9)||(yue==11)) { if(ri==31) ri=1; } else if(yue==2) { if(ri>=29) ri=1; } else { if(ri==32) ri=1; } } write_ds(7ri); write_calendar(9ri); write_com(0x80+10); delayxms(2); if(week==7) week=0; write_week(week); write_ds(6week); } } } if(key3==0) { delayxms(10); if(key3==0) { while(!key3); if(count==1) { if(sec==0) sec=59; else sec--; write_ds(0sec); write_sfm(10sec); write_com(0x80+0x40+11); } if(count==2) { if(min==0) min=59; else min--; write_ds(2min); write_sfm(7min); write_com(0x80+0x40+8); } if(count==3) { if(hour==0) hour=23; else hour--; write_ds(4hour); write_sfm(4hour); write_com(0x80+0x40+5); } if(count==5) { if(nian==0) nian=99; else nian--; write_ds(9nian); write_calendar(3nian); write_com(0x80+4); } if(count==6) { if(yue==1) yue=12; else yue--; write_ds(8yue); write_calendar(6yue); write_com(0x80+7); } if(count==7) // 判斷閏年 { ri--; week--; if(nian%4==0) { if((yue==4)||(yue==6)||(yue==9)||(yue==11)) { if(ri==0) ri=30; } else if(yue==2) { if(ri==0) ri=29; } else { if(ri==0) ri=31; } } if(nian%4!=0) { if((yue==4)||(yue==6)||(yue==9)||(yue==11)) { if(ri==0) ri=30; } else if(yue==2) { if(ri==0) ri=28; } else { if(ri==0) ri=31; } } write_ds(7ri); write_calendar(9ri); write_com(0x80+10); delayxms(2); if(week==-1) week=7; write_week(week); write_ds(6week); } } } } //----------------初始化---------------------------------// void init() { lcdinit(); disp(); week=0; nian=11; yue=9; ri=1; } //---------------------------流水燈-----------------------------------// void lampinit() { P1=0xff; wela1=1; wela2=1; wela3=1; wela3=1; wela1=0; wela2=0; wela3=0; wela4=0; } //----------------時鐘用黃燈顯示程式-------------------------------// void clock() { if((hour==1)&&(hour==13)) { P1=0xfd; wela3=1; wela3=0; } if((hour==2)&&(hour==14)) { P1=0xfb; wela3=1; wela3=0; } if((hour==3)&&(hour==15)) { P1=0xf7; wela3=1; wela3=0; } if((hour==4)&&(hour==16)) { P1=0xef; wela3=1; wela3=0; } if((hour==5)&&(hour==17)) { P1=0xdf; wela3=1; wela3=0; } if((hour==6)&&(hour==18)) { P1=0xfe; wela4=1; wela4=0; } if((hour==7)&&(hour==19)) { P1=0xfd; wela4=1; wela4=0; } if((hour==8)&&(hour==20)) { P1=0xfb; wela4=1; wela4=0; } if((hour==9)&&(hour=21)) { P1=0xf7; wela4=1; wela4=0; } if((hour==10)&&(hour==22)) { P1=0xef; wela4=1; wela4=0; } if((hour==11)&&(hour==23)) { P1=0xdf; wela4=1; wela4=0; } if((hour==12)&&(hour==0)) { P1=0xfe; wela3=1; wela3=0; } if(min<5) { if((hour!=12)&&(hour!=24)) { P1=0xfe; wela1=1; wela1=0; } } //----------------分鐘用紅燈顯示------------------------// if((min>=5)&&(min<10)) { if((hour!=13)&&(hour!=1)) { P1=0xfd; wela1=1; wela1=0; } } if((min>=10)&&(min<15)) { if((hour!=14)&&(hour!=2)) { P1=0xfb; wela1=1; wela1=0; } } if((min>=15)&&(min<20)) { if((hour!=15)&&(hour!=3)) { P1=0xf7; wela1=1; wela1=0; } } if((min>=20)&&(min<25)) { if((hour!=16)&&(hour!=4)) { P1=0xef; wela1=1; wela1=0; } } if((min>=25)&&(min<30)) { if((hour!=17)&&(hour!=5)) { P1=0xdf; wela1=1; wela1=0; } } if((min>=30)&&(min<35)) { if((hour!=18)&&(hour!=6)) { P1=0xfe; wela2=1; wela2=0; } } if((min>=35)&&(min<40)) { if((hour!=19)&&(hour!=7)) { P1=0xfd; wela2=1; wela2=0; } } if((min>=40)&&(min<45)) { if((hour!=20)&&(hour!=8)) { P1=0xfb; wela2=1; wela2=0; } } if((min>=45)&&(min<50)) { if((hour!=21)&&(hour!=9)) { P1=0xf7; wela2=1; wela2=0; } } if((min>=50)&&(min<55)) { if((hour!=22)&&(hour!=10)) { P1=0xef; wela2=1; wela2=0; } } if(min>=55) { if((hour!=23)&&(hour!=11)) { P1=0xdf; wela2=1; wela2=0; } } } //---------------考試倒計時模式-----------------------// void test() { uchar hour1min1min2shi; hour1=hour+2; if(hour==24) hour1=0; if(hour==25) hour1=1; min1=min+20; if(min1>=60) { min1=min1-60; hour1=hour1+1; if(hour1==24) hour1=0; } shi=min1/10; min1=shi*10; if((min==min1)&&(sec==0)) { min2=min+5; if(min2==60) min2=0; P1=0xfe; wela3=1; wela3=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xfc; wela1=1; wela1=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xf8; wela1=1; wela1=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xf0; wela1=1; wela1=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xe0; wela1=1; wela1=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xc0; wela1=1; wela1=0; } //-------------------------------------------------// if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xfe; wela2=1; wela2=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xfc; wela2=1; wela2=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xf8; wela2=1; wela2=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xf0; wela2=1; wela2=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xe0; wela2=1; wela2=0; } if(min==min2) { min2=min+5; if(min2==60) min2=0; P1=0xc0; wela2=1; wela2=0; } //----------------------時間到後開始響鈴------------------------------------------// if(min==min2) { P1=0; wela1=1; wela1=0; beep=0; delayxms(1000); beep=1; delayxms(1000); beep=0; delayxms(1000); beep=1; beep=0; delayxms(1000); beep=1; delayxms(1000); beep=0; delayxms(6000); delayxms(6000); beep=1; lampinit(); } } //-----------------主函式--------------------------------------// void main() { init(); while(1) { keyscan(); if(count==0) { sec=read_ds(0); min=read_ds(2); hour=read_ds(4); week=read_ds(6); nian=read_ds(9); yue=read_ds(8); ri=read_ds(7); write_sfm(10sec); write_sfm(7min); write_sfm(4hour); write_week(week); write_calendar(3nian); write_calendar(6yue); write_calendar(9ri); write_calendar(120); } } }