|
|
通過(guò)幾天的調(diào)試用,單片機(jī)AT89C52,LCD液晶屏LC1602,溫度采集模塊DS18B20,時(shí)鐘模塊DS1302,和三個(gè)按鍵,以及一些電子元件完成了數(shù)字時(shí)鐘系統(tǒng)的設(shè)計(jì)。在一塊液晶顯示屏上實(shí)現(xiàn)動(dòng)態(tài),時(shí)、分、秒、年、月、日、星期、溫度數(shù)據(jù)的顯示, 通過(guò)三個(gè)按鍵,S1調(diào)時(shí)鍵、S2時(shí)間加鍵、S3時(shí)間減鍵、實(shí)現(xiàn)時(shí)鐘的年、月、日、星期、時(shí)、分、秒、的調(diào)整。本系統(tǒng)設(shè)計(jì)大部分功能有軟件來(lái)實(shí)現(xiàn),使電路簡(jiǎn)單明了。由于以前從沒(méi)有過(guò)單片機(jī)相關(guān)產(chǎn)品的制作經(jīng)驗(yàn),所以這個(gè)設(shè)計(jì)共用了約30多個(gè)鐘。在做這設(shè)計(jì)之前軟件思路非常模糊代碼都是想到哪寫到哪,結(jié)果寫到最后調(diào)試時(shí)出現(xiàn)了大把錯(cuò)誤,在調(diào)試程序中花了大把的時(shí)間,調(diào)程序真的是個(gè)考驗(yàn)?zāi)托牡墓ぷ鞲愕奈以译娔X的想法都有了。因?yàn)槭亲约阂粋(gè)人制作的出現(xiàn)了錯(cuò)誤只好在網(wǎng)上找資料,閱讀別人寫過(guò)的代碼,經(jīng)過(guò)長(zhǎng)時(shí)間的修改終于完成了這次制作。設(shè)計(jì)因?yàn)槭菢I(yè)余學(xué)習(xí)的單片機(jī)加上這斷時(shí)間工作比較忙,所以為了完成這個(gè)產(chǎn)品的制作可沒(méi)少睡過(guò)覺(jué),幾乎每天都沒(méi)在2點(diǎn)鐘前睡過(guò)。附原代碼
- #include"reg52.h"
- #include"12864.h"
- #include"ds1302.h"
- #include"ds18b20.h"
- #include"intrins.h"//_nop_聲明
-
- #define uchar unsigned char
- #define uint unsigned int
- sbit DQ=P3^7;
- sbit rs=P3^0;
- sbit rw=P3^1;
- sbit en=P3^2;
- uchar tou;
-
- sbit io=P3^6;
- sbit rst=P3^4; //定義各芯片跟單片機(jī)連接的定義
- sbit sck=P3^5;
- sbit s1=P1^0; //定義各芯片跟單片機(jī)連接的定義
- sbit s2=P1^4;
- sbit s3=P1^7; //定義各芯片跟單片機(jī)的連接的定義
- uchar tung=0; //定義
- uchar tab4[]={0x82,0x85,0x88,0x8f,0xc0,0xc3,0xc6};//用來(lái)存放年月日星期時(shí)分秒的地址
- char tab[]={13,5,4,5,00,59,33};//年 月 日 周 時(shí) 分 秒的初值
- uchar tab1[]; //
- uchar write_add[7]={0x8c,0x88,0x86,0x8a,0x84,0x82,0x80}; //寫寄存器地址
- uchar read_add[7]={0x8d,0x89,0x87,0x8b,0x85,0x83,0x81};//存放從1302中讀數(shù)寄存器地址
- void write_byte(uchar); //寫數(shù)據(jù)函數(shù)
- uchar read_byte(void); //讀數(shù)據(jù)函數(shù)
- uchar readtemperature(void);//一次性讀出溫度
-
- void write_ds1302_byte(uchar); //單字節(jié)寫函數(shù)
- void write_ds1302(uchar add,uchar dat);//寫 /寫地址數(shù)據(jù)+寫數(shù)據(jù)函數(shù)
- uchar read_ds1302(uchar);// 單字節(jié)讀函數(shù)
- void flx(uchar j); //
- void key(void); //按鍵函數(shù)
- void write_ds1302_byte(uchar dat)
- {
- uchar i;
- for(i=0;i<8;i++) //單字節(jié)寫
- {
- sck=0;
- io=dat&0x01;
- dat=dat>>1;
- sck=1;
- }
-
- }
- void write_ds1302(uchar add,uchar dat)
- {
- rst=0;
- _nop_();
- sck=0;
- _nop_();
- rst=1; //寫地址數(shù)據(jù)+寫數(shù)據(jù)函數(shù)
- _nop_();
- write_ds1302_byte(add); //寫地址
- write_ds1302_byte(dat); //寫數(shù)據(jù)
- rst=0;
- _nop_();
- io=1;
- sck=1;
-
- }
- uchar read_ds1302(uchar add)
- { uchar i,value;
- rst=0; //
- _nop_();
- sck=0;
- _nop_(); //單字節(jié)讀數(shù)據(jù)函數(shù)
- rst=1;
- _nop_();
- write_ds1302_byte(add );
- for(i=0;i<8;i++)
- {
- value=value>>1;
- sck=0;
- if(io) //因?yàn)槭谴谒砸?次讀數(shù)據(jù)
- value=value|0x80;
- sck=1;
- }
- rst=0;
- _nop_();
- sck=0;
- _nop_();
- sck=1;
- io=1;
- return value;
- }
- void read_ds1302_1(void)//一次讀出年月日 時(shí)分秒函數(shù)
- {
- uchar i,shi,ge,tun;
- write_ds1302(0x8e,0x00);//去除寫保護(hù)
- for(i=0;i<7;i++)
- {
- tun=read_ds1302(read_add[i]); //一次將年月日從DS1302中讀出送到數(shù)組中
- ge=tun%16;
- shi=tun/16; //將BCD碼分成十位和個(gè)位
- tab[i]=shi*10+ge; //再換成十進(jìn)制存到數(shù)組tab中
-
- }
- write_ds1302(0x8e,0x00);//加寫保護(hù)
- }
- void write_ds1302_1(void)
- { //將10進(jìn)制數(shù)送到1602;
- write_com(0x80+0x40+6);//秒的位置
- write_dat(tab[6]/10+0x30);
- write_dat(tab[6]%10+0x30);
-
- write_com(0x80+0x40+3);//
- write_dat(tab[5]/10+0x30); //分的位置
- write_dat(tab[5]%10+0x30);
- //將十進(jìn)制的數(shù)據(jù)換成1602的顯示碼送到顯示屏
- write_com(0x80+0x40+0);// //時(shí)的地址
- write_dat(tab[4]/10+0x30); //顯示屏的第二排要加0x80+40
- write_dat(tab[4]%10+0x30);
-
- write_com(0x80+2);//
- write_dat(tab[0]/10+0x30);//年的地址
- write_dat(tab[0]%10+0x30);
-
- write_com(0x80+5);// 顯示屏 的第一排地址要加0x80;
- write_dat(tab[1]/10+0x30);
- write_dat(tab[1]%10+0x30); //月的地址
-
- write_com(0x80+8);// 日的地址
- write_dat(tab[2]/10+0x30);
- write_dat(tab[2]%10+0x30);
-
- write_com(0x80+15); //星期的地址
- write_dat(tab[3]%10+0x30);
-
-
-
-
- }
- void set_rtc(void) //一次設(shè)置初始時(shí)間年月日函數(shù)
- {
- uchar i,j;
-
- for(i=0;i<7;i++)
- {
- j=tab[i]/10; //將設(shè)置的年月日時(shí)間2013—4-25 00-14-00中分解出十位放入J中
- tab1[i]=tab[i]%10; //將設(shè)置的年月日時(shí)間2013—4-25 00-14-00中分解出個(gè)位再放入time_data[]數(shù)組中
- tab1[i]=tab1[i]+j*16;//將十進(jìn)制的個(gè)位和十位轉(zhuǎn)換為BCD碼
-
- }
- write_ds1302(0x8e,0x00);//去除寫保護(hù)
- for(i=0;i<7;i++)
- {
- write_ds1302(write_add[i],tab1[i]); //寫要設(shè)置初始時(shí)間日期的操作寄存器的地址
- }
- write_ds1302(0x8e,0x00);//加寫保護(hù)
- }
-
- void ds1302_init(void)
- {
-
-
-
- key(); //按鍵函數(shù)
- read_ds1302_1();//一次讀出年月日 時(shí)分秒函數(shù)
- write_ds1302_1(); //時(shí)間的顯示函數(shù)
-
- }
- void key(void)
- {
- //按鍵函數(shù)
- if(s1==0) //如果S1按下
- {
- delay(3); //延時(shí)去抖
- if(s1==0)
- {
- while(!s1); //
- tung=0; //tung用來(lái)確定光標(biāo)的位置
-
- while(tung<=6) //循環(huán)7次 時(shí)分秒年月日星期
- {
-
-
- if(s2==0)
- {
- delay(3);
- if(s2==0)//去抖動(dòng)延時(shí)
- {
- while(!s2); // 檢測(cè)按鍵是否放開(kāi)
- tab[tung]++; //如果+鍵按下加1
- }
- }
- if(s3==0)
- {
- delay(3); // 檢測(cè)按鍵是否放開(kāi)
- if(s3==0)
- {
- while(!s3); //按鍵是否松手
- tab[tung]--; //如果—鍵按下減1
- }
- }
-
- switch(tung)
- { //通過(guò)tung的值確定光標(biāo)的位置
- case 0:
- if(tab[tung]<3) //如果tung=0;則表示正在調(diào)年讓年在2004到2098這個(gè)范圍內(nèi)
- tab[tung]=98;
- if(tab[tung]>98)
- tab[tung]=4;
- break;
-
- case 1:
- if(tab[tung]<1)
- tab[tung]=12;
- if(tab[tung]>12) //如果tung=1;則表示正在調(diào)月讓月在1到12這個(gè)范圍內(nèi)
- tab[tung]=1;
- break;
- case 2:
- if(tab[tung]==0)
- tab[tung]=31;
- if(tab[tung]==32) //如果tung=2;則表示正在調(diào)日讓在1到31這個(gè)范圍內(nèi)
- tab[tung]=1;
- break;
- case 3:
- if(tab[tung]<1)
- tab[tung]=7;
- if(tab[tung]>7) //如果tung =3則表示下在調(diào)星期讓在1到7這個(gè)范圍內(nèi)
- tab[tung]=1;
- break;
- case 4:
- if(tab[tung]<0)
- tab[tung]=23;
- if(tab[tung]>23) //如果tung=4則表示在調(diào)時(shí)讓時(shí)在1到23這個(gè)范圍內(nèi)
- tab[tung]=0;
- break;
- case 5:
- if(tab[tung]<0)
- tab[tung]=59;
- if(tab[tung]>59) //如果tung=5;則表示正在調(diào)分讓分在1到59這個(gè)范圍內(nèi)
- tab[tung]=0;
- break;
- default:
- if(tab[tung]<0)
- tab[tung]=59;
- if(tab[tung]>59) //如果tung=6;則表示正在調(diào)秒讓秒在1到59這個(gè)范圍內(nèi)
- tab[tung]=0;
- break;
- }
- write_com(tab4[tung]); //顯示正在調(diào)的位置
- flx(tab[tung]); //將數(shù)據(jù)分離成1602的顯示碼并送到1602顯示屏
-
-
- if(s1==0)
- {
- while(!s1); //判斷是否調(diào)好了時(shí)間如果好了則跳出key
- tung++; //每按一下S1調(diào)式模式鍵則加一次如果到了7次跳出KEY函數(shù)
- }
-
- }
-
- }
- write_com(0x0c);//調(diào)完了時(shí)間關(guān)閉光標(biāo)
- set_rtc(); //把調(diào)好的時(shí)間數(shù)據(jù)送到DS1302芯片中
- }
- }
- void flx(uchar j)
- {
- uchar k,a;
- write_com(0x0f); //開(kāi)光標(biāo)顯示指令
- k=j/10; //分離十位跟個(gè)位
- a=j%10;
- if(tung!=3) //年月日時(shí)分秒分離
- {
-
- write_dat(k+0x30); //將分離的十位跟個(gè)位換成LC1602能顯示的碼
- write_com(0x0c);//關(guān)光標(biāo)指令
- write_dat(a+0x30);
-
- }
- else
-
- write_dat(a+0x30); //星期分離
-
- }
-
- void delay1(uchar i)
- {
- while(i--);
- }
- void init_ds18b20(void)
- {
- uchar n;
- DQ=1;
- delay1(8);
- DQ=0;
- delay1(80); //初始化函數(shù)
- DQ=1;
- delay1(8);
- n=DQ;
- delay(25);
- }
- void write_byte(uchar dat)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- DQ=0; //寫函數(shù)
- DQ=dat&0x01;
- delay(4);
- DQ=1;
- dat>>=1; //移一位
-
- }
- delay(4);
- }
- uchar read_byte(void)
- {
- uchar i,value;
- for(i=0;i<8;i++)
- {
- DQ=0; //讀數(shù)據(jù)函數(shù)
- value>>=1; //移1位
- DQ=1;
- if(DQ)
- value|=0x80;
- delay(4);
- }
- return value;
- }
- uchar readtemperature(void)//一次性讀出溫度
- {
- uchar a,b;
- init_ds18b20();
- write_byte(0xcc);//跳過(guò)ROM
- write_byte(0x44);//啟動(dòng)溫度測(cè)量
- delay1(300);
- init_ds18b20(); //初始化
-
- write_byte(0xcc);
- write_byte(0xbe);//讀取溫度
- a=read_byte();//高8位
- b=read_byte();//
-
- b<<=4; //因不用小數(shù)部分所以移4位
- b+=(a&0xf0)>>4; //將存放低8位的個(gè)位和高8位的十位合到一塊
- return b;
- }
- void xianshi(void)
- {
- uchar temp,k,f;
- temp=readtemperature();//將溫度保存到temp中
- f=temp/10; //分離出十位跟個(gè)位
- k=temp%10;
- write_com(0x80+0x40+10);//溫度顯示的位置
- write_dat(f+0x30); //
- write_dat(k+0x30);
-
-
- }
- uchar tab1[]="20 - - week "; //屏上要固定顯示的字符
- uchar tab2[]=" : : ";
- void delay(uint x)
- {
- uint a,b;
- for(a=x;a--;a>0) //延時(shí)函數(shù)
- for(b=110;b>0;b--);
- }
- void write_com(uchar com)
- {
- rs=0;
- rw=0; //寫數(shù)據(jù)指令函數(shù)
- P2=com;
- delay(4);
- en=1;
- delay(4);
- en=0;
- }
- void write_dat(uchar dat)
- {
- rs=1;
- rw=0;
- P2=dat;
- delay(4); //寫數(shù)據(jù)函數(shù)
- en=1;
- delay(4);
- en=0;
-
- }
- void init(void)
- {
- write_com(0x38);
- write_com(0x0c);// //1602初始化函數(shù)
- write_com(0x06);
- write_com(0x01);
- write_com(0x80);
- write_com(0x80); //第一行顯示的位置地址
- for(tou=0;tou<16;tou++)
- {
- write_dat(tab1[tou]); //顯示固定字符
- }
- write_com(0x80+0x40); //第二行顯示的位置地址
- for(tou=0;tou<8;tou++)
- {
- write_dat(tab2[tou]);
-
- }
- write_com(0x80+0x40+12);
- write_dat(0xdf);//顯示溫度的小圓圈符號(hào),0xdf是液晶屏字符庫(kù)的該符號(hào)地址碼
- write_dat(0x43); //顯示"C"符號(hào),0x43是液晶屏字符庫(kù)里大寫C的地址碼
- }
- main()
- {
- init();//初始化顯示屏
- set_rtc(); //設(shè)置ds1302時(shí)鐘芯片時(shí)間
- while(1)
- {
- ds1302_init();//初始化ds1302時(shí)鐘芯片
- xianshi(); //溫度顯示函數(shù)
-
- }
-
-
- }
- 通過(guò)這次的制作讓我全面的了解單片機(jī)相關(guān)產(chǎn)品的開(kāi)發(fā)流程,及一些常用芯片驅(qū)動(dòng)程序的編寫。始我在單片機(jī)上的學(xué)習(xí)更上一層樓!
復(fù)制代碼
|
|