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