|
|
- 我在上一篇文章中焊接了單片機(jī)最小系統(tǒng)板,并且成功驅(qū)動(dòng)了LCD1602,我沒(méi)有在最后展示LCD顯示部分,就放到這篇文章在外接DS12C887的情況下和大家分享一下。
- 需要準(zhǔn)備的模塊如下:
- 1.單片機(jī)的最小系統(tǒng)板(最好有復(fù)位電路)另外20引腳(地)和40引腳vcc要多引出來(lái)6個(gè)(后面接杜邦線(xiàn)很多地方要用)
- 2.DS12C887時(shí)鐘芯片(24腳的)
- 3.LCD1602模塊
這里的DS12C887買(mǎi)回不能直接用,得像51芯片一樣焊接個(gè)底座出來(lái),旁邊兩列焊接兩列排針,作為芯片的引腳。焊接好的效果圖如下
因?yàn)橐?qū)動(dòng)LCD1602,電位器也是必不可少的,我把電位器單獨(dú)焊接在了另外一塊板子上,這個(gè)焊接地方?jīng)]有要求,合理安排空間即可,焊接電位器也要利用排針引出三個(gè)角,對(duì)于3296型電位器的各引腳說(shuō)明如下1腳VCC,3腳GND,2腳接輸出。電位器的大小選擇位10k,如圖
還需要準(zhǔn)備4個(gè)輕觸按鍵,因?yàn)樵O(shè)置時(shí)鐘時(shí),需要選擇功能、增大鍵、減小鍵、鬧鐘查看鍵(我的板子上沒(méi)有焊接蜂鳴器,所以鬧鐘到點(diǎn)后,不會(huì)響,蜂鳴器是一個(gè)比較簡(jiǎn)單的模塊,代碼里面都有定義,我在焊接的時(shí)候把他先忽視了,需要的話(huà),外加上蜂鳴器模塊,看一下程序里的引腳定義就可以)
4個(gè)輕觸按鍵的接法從上到下排列,分別為功能選擇、增大、減小、鬧鐘查看。此處的焊接為選擇每個(gè)按鍵的兩個(gè)對(duì)角引腳,每個(gè)按鍵選擇的兩個(gè)引腳要相同,從上到下在板子上安插好,
按鍵圖.png (57.77 KB, 下載次數(shù): 76)
下載附件
2021-6-15 14:44 上傳
按鍵原理圖.png (10.43 KB, 下載次數(shù): 85)
下載附件
2021-6-15 14:44 上傳
原理圖和實(shí)物圖引腳一一對(duì)應(yīng),我們可以選擇1腳輸出,4腳接地(對(duì)角接通)4個(gè)按鍵的4號(hào)腳連接在一起并且引出一個(gè)插針到時(shí)候直接接單片機(jī)的GND完成接地,再把每個(gè)按鍵的1號(hào)腳用插針引出來(lái),接代碼里定義的按鍵引腳。
在這里我給大家看一下DS12C887的芯片接法!
DS12C887實(shí)物圖.png (156.92 KB, 下載次數(shù): 92)
下載附件
2021-6-15 14:44 上傳
DS12C887引腳圖.png (98.77 KB, 下載次數(shù): 79)
下載附件
2021-6-15 14:44 上傳
我從左邊最上邊開(kāi)始逆時(shí)針轉(zhuǎn)一圈來(lái)說(shuō)明各引腳的接法
從第四引腳開(kāi)始接4-11為數(shù)據(jù)傳輸,接單片機(jī)的P0口,12腳接單片機(jī)20腳的GND。
13腳cs接P1^4
14腳as接P1^5
15腳rw接P1^6
17腳ds接P1^7
18腳RESET接VCC
19腳IRQ接P3^3
24腳接VCC
現(xiàn)在DS12C887模塊的準(zhǔn)備工作都完成了。只剩下LCD1602的接線(xiàn)部分,原理圖如下
1602接口.png (90.2 KB, 下載次數(shù): 81)
下載附件
2021-6-15 14:44 上傳
1602液晶上都有每個(gè)管腳的名稱(chēng),可以對(duì)照著原理圖來(lái)接線(xiàn)
1602實(shí)物圖.JPG (1.85 MB, 下載次數(shù): 72)
下載附件
2021-6-15 14:44 上傳
從左向右,1腳接地,2腳接vcc,3腳接電位器的第二腳,rs接單片機(jī)的P3^5,rw接地,E接單片機(jī)的P3*4,D0-D7接單片機(jī)的P2口,A、K為背光電源,A接vcc,K接gnd。至此所有外接模塊安裝包括接口對(duì)應(yīng)引腳都完成了。
```c
/*總體要求*/
/*在1602上顯示年月日星期時(shí)分秒,并且按照秒來(lái)實(shí)時(shí)更新顯示
可以鬧鐘設(shè)定,到點(diǎn)報(bào)警功能,報(bào)警響起時(shí),任意鍵可以取消報(bào)警
四個(gè)按鍵,根據(jù)功能可以調(diào)節(jié)參數(shù),分別為功能鍵,數(shù)值增大鍵,數(shù)值減少鍵,鬧鐘查看鍵,
每次按鍵按下,蜂鳴器都會(huì)滴一聲,
利用DS12C887實(shí)現(xiàn)斷電后,再次上電,時(shí)間仍可以準(zhǔn)確顯示 */
/*另外這個(gè)程序中文部分是學(xué)習(xí)了一個(gè)半月C語(yǔ)言的人的理解,難免有錯(cuò)誤的地方
如果你想移植程序,除了開(kāi)頭的各種腳需要修改,程序里面1602和DS12C887的寫(xiě)指令寫(xiě)數(shù)據(jù),讀指令讀數(shù)據(jù)的IO口也要修改
應(yīng)該是有4~6處,一定要注意,不然你的程序不會(huì)亮起來(lái),然后初始化部分,記得初始化后去掉,但是仿真的時(shí)候不要去掉,去掉沒(méi)法顯示*/
/*非常非常非常重要的一個(gè)細(xì)節(jié),總線(xiàn)上要加 AD[0..7] 這個(gè)名字,如果沒(méi)有永遠(yuǎn)也仿真不起來(lái)*/
#include<reg52.h> //52系列單片機(jī)機(jī)頭文件
#define uchar unsigned char //宏定義 定義一個(gè)無(wú)符號(hào)字符型數(shù)據(jù)
#define uint unsigned int //宏定義 定義一個(gè)無(wú)符號(hào)整型數(shù)據(jù)
sbit lcdrs=P3^5; //自定義數(shù)據(jù)/命令選擇端口
sbit lcden=P3^4; //自定義使能信號(hào)
//sbit dula=P2^6;
//sbit wela=P2^7; /*P0口接液晶1602和時(shí)鐘芯片DS12C887的AD0-AD7*/
sbit beep=P2^3; //蜂鳴器。有的按鍵接rd為低電平,就需要也定義一下rd,我這里面四個(gè)按鍵采用的是接地的結(jié)構(gòu)!
sbit dscs=P1^4; //定義地址選通輸入端 (讀到那里去)
sbit dsas=P1^5; //定義芯片片選端 (讀哪個(gè)芯片)
sbit dsrw=P1^6; //定義讀數(shù)據(jù)允許輸入腳,這里mot接地 (讓不讓讀的開(kāi)關(guān))
sbit dsds=P1^7; //定義中斷請(qǐng)求輸出
sbit dsirq=P3^3; //定義讀允許輸入 (讓讀以后,我來(lái)輸入數(shù)據(jù))
sbit lcdrd=P3^7;
sbit s1=P1^0; //功能鍵
sbit s2=P1^1; //數(shù)值增大鍵
sbit s3=P1^2; //數(shù)值減少鍵
sbit s4=P1^3; //鬧鐘查看鍵
//因?yàn)楣δ苕I要8次才能推出,這里可以加一個(gè)直接退出按鍵,可以放在外部中斷上
bit flag1, flag_ri; //定義兩個(gè)位變量
uchar count,s1num,flag,t0_num; //定義幾個(gè)無(wú)符號(hào)字符型數(shù)據(jù),用到時(shí)再解釋定義干啥用的
char miao,shi,fen,year,month,day,week,amiao,afen,ashi; //定義幾個(gè)字符型數(shù)據(jù),這個(gè)基本上都能理解。
uchar code table[]=" 20 - - "; //讓液晶固定顯示的內(nèi)容
uchar code table1[]=" : : "; //讓液晶固定顯示的內(nèi)容
void write_ds(uchar, uchar); //函數(shù)申明 寄存器初始化
void set_alarm(uchar, uchar, uchar); //函數(shù)申明 設(shè)定鬧鐘
void read_alarm(); //函數(shù)申明 讀報(bào)警器
void set_time(); //函數(shù)申明 寄存器初始化
void delay(uint z) //延時(shí)函數(shù)
{
uint x,y; //定義兩個(gè)無(wú)符號(hào)整形數(shù)
for(x=z;x>0;x--) //如果x>0,則y執(zhí)行110次
for(y=110;y>0;y--); //本小段為單位是1ms的延時(shí)
}
void di() //蜂鳴器報(bào)警
{
beep=0; //低電平有效,蜂鳴器開(kāi)始蜂鳴
delay(100); //延時(shí)100毫秒,響0.1秒
beep=1; //蜂鳴器停止鳴叫
}
void write_com(uchar com) //寫(xiě)液晶命令函數(shù)
{
lcdrs=0; //rs低電平,表示要寫(xiě)命令
lcden=0; //en低電平,表示為了下面送入數(shù)據(jù),防止此時(shí)還是高電平,無(wú)法制造高脈沖
P2=com; //D0-D7我接的是P0上面,數(shù)據(jù)送給它
delay(3); //延時(shí)3ms
lcden=1; //en高電平,延時(shí)三秒 再變成低電平,完成一次高脈沖,使數(shù)據(jù)送入液晶顯示屏
delay(3); //表示接下來(lái),液晶顯示屏可以過(guò)來(lái)讀數(shù)據(jù)了
lcden=0;
}
void write_date(uchar date) //寫(xiě)液晶數(shù)據(jù)函數(shù)
{
lcdrs=1; //高電平表示要寫(xiě)數(shù)據(jù)
lcden=0; //en低電平,表示為了下面送入數(shù)據(jù),防止此時(shí)還是高電平,無(wú)法制造高脈沖
P2=date; //D0-D7我接的是P0上面,數(shù)據(jù)送給它
delay(3); //延時(shí)3ms
lcden=1; //en高電平,延時(shí)三秒 再變成低電平,完成一次高脈沖,使數(shù)據(jù)送入液晶顯示屏
delay(3); //表示接下來(lái),液晶顯示屏可以過(guò)來(lái)讀數(shù)據(jù)了
lcden=0;
}
void init() //液晶初始化
{
uchar num; //定義一個(gè)字符
EA=1; //打開(kāi)全局中斷控制
EX1=1; //打開(kāi)外部中斷1中斷
IT1=1; //設(shè)置負(fù)跳變沿觸發(fā)中斷
flag=0; // 自定義字符全部歸零,為了方便實(shí)用
flag1=0;
s1num=0; //鍵盤(pán)按下的次數(shù)
week=1; //星期顯示最低也是周一的一
lcden=0; //使能信號(hào)定義為零,表示還沒(méi)有數(shù)據(jù)
lcdrd=0;
// dula=0;//關(guān)閉數(shù)碼管顯示
// wela=0;
write_ds(0x0A,0x20); //首次使用ds12c887時(shí)使用,以后不必在寫(xiě)。打開(kāi)振蕩器
write_ds(0x0B,0x26); // 設(shè)置24小時(shí)模式,數(shù)據(jù)二進(jìn)制格式,開(kāi)啟鬧鐘中斷。
//0A,0B表示地址,20,26翻譯成二進(jìn)制是00100000,00100110對(duì)應(yīng)著對(duì)著寄存器A和B從D7-D0
set_time(); //設(shè)置默認(rèn)上電時(shí)間
write_com(0x38); //設(shè)置16x2顯示,5x7點(diǎn)陣,8位數(shù)據(jù)接口
write_com(0x0c); //設(shè)置開(kāi)顯示,不顯示光標(biāo)
write_com(0x06); //寫(xiě)一個(gè)字符后,地址指針自動(dòng)加1
write_com(0x01); //顯示清0,數(shù)據(jù)指針清0
write_com(0x80); //設(shè)置數(shù)據(jù)指針位置,此處時(shí)數(shù)據(jù)指針第一行,第一處
for(num=0;num<15;num++) //<15原因是第一行顯示的數(shù)字或者空格一共14個(gè)
{
write_date(table[num]); //把要顯示的數(shù)據(jù)送入到液晶的第一行
delay(1); //延遲一毫秒
}
write_com(0x80+0x40); //設(shè)置數(shù)據(jù)指針位置,此處時(shí)數(shù)據(jù)指針第二行,第一處
for(num=0;num<11;num++) //<11原因是第二行顯示的數(shù)字或者空格一共10個(gè)
{
write_date(table1[num]); //把要顯示的數(shù)據(jù)送入到液晶的第二行
delay(1); //延遲一毫秒
}
}
void write_sfm(uchar add,char date) //1602液晶刷新時(shí)分秒函數(shù)4為時(shí),7為分,10為秒 ,4.7.10均是顯示位置
{
char shi,ge; //定義兩個(gè)數(shù),來(lái)表示十位數(shù)和個(gè)位數(shù)
shi=date/10; // 要送去顯示的十位
ge=date%10; //要送去顯示的個(gè)位
write_com(0x80+0x40+add); //時(shí)間是在第二行顯示,所以是加0X40,在add處顯示
write_date(0x30+shi); //shi和ge都是整形數(shù)值,但是液晶1602是內(nèi)置ASCII表格,0在第048位
write_date(0x30+ge); //轉(zhuǎn)成十六進(jìn)制就是0x30,
}
/*這個(gè)地方可能會(huì)有人迷糊,設(shè)置時(shí)分秒,怎么只設(shè)置十位和個(gè),好像給人的感覺(jué)就是只設(shè)置時(shí)位,和分位,秒位怎么不設(shè)置,
實(shí)際上是,這里寫(xiě)入并顯示的是 把時(shí)的十位和個(gè)位,分的十位和個(gè)位,秒的十位和個(gè)位,分別送去進(jìn)行運(yùn)算 ,然后先寫(xiě)命令確定位置,
再寫(xiě)數(shù)據(jù),用來(lái)顯示,下面一個(gè)子函數(shù)也是同樣的道理*/
void write_nyr(uchar add,char date) //1602液晶刷新年月日函數(shù),3為年,6為月9為天 ,369也分別是位置
{
char shi,ge; //定義兩個(gè)數(shù),來(lái)表示十位數(shù)和個(gè)位數(shù)
shi=date/10; // 要送去顯示的十位
ge=date%10; //要送去顯示的個(gè)位
write_com(0x80+add); //時(shí)間是在第二行顯示,所以是加0X40,在add處顯示
write_date(0x30+shi); //shi和ge都是整形數(shù)值,但是液晶1602是內(nèi)置ASCII表格,0在第048位
write_date(0x30+ge); //轉(zhuǎn)成十六進(jìn)制就是0x30,
} /*實(shí)際上到了主函數(shù),時(shí)分秒,年月日會(huì)有六個(gè)子函數(shù)進(jìn)行分別調(diào)用,這里用兩個(gè)子函數(shù)來(lái)表示,不能用一個(gè)的原因是顯示的內(nèi)容不在一行,
主要是寫(xiě)入命令的位置不一樣,大家可以觀察一下*/
void write_week(char we) //寫(xiě)液晶1602星期顯示函數(shù)
{
write_com(0x80+12); //讓we在0x80+12這個(gè)位置顯示
switch(we) //多分支結(jié)構(gòu)的條件選擇語(yǔ)句,we等于幾就去執(zhí)行幾號(hào)分支
{
case 1:write_date('M'); //寫(xiě)入M。整個(gè)的意思是如果we等于1,則顯示MON,即星期一
delay(5); //延時(shí)5毫秒后寫(xiě)入O
write_date('O'); //寫(xiě)入O
delay(5); //延時(shí)5毫秒后寫(xiě)入N
write_date('N'); //寫(xiě)入N
break; //間斷,為了和后面分開(kāi)
case 2:write_date('T'); //寫(xiě)入T。整個(gè)的意思是如果we等于2,則顯示TUE,即星期二
delay(5); //延時(shí)5毫秒后寫(xiě)入U(xiǎn)
write_date('U'); //寫(xiě)入U(xiǎn)
delay(5); //延時(shí)5毫秒后寫(xiě)入E
write_date('E'); //寫(xiě)入E
break; // 間斷,為了和后面分開(kāi)
case 3:write_date('W'); //寫(xiě)入W。整個(gè)的意思是如果we等于3,則顯示W(wǎng)ED,即星期三
delay(5); //延時(shí)5毫秒后寫(xiě)入E
write_date('E'); //寫(xiě)入E
delay(5); //延時(shí)5毫秒后寫(xiě)入D
write_date('D'); //寫(xiě)入D
break; //間斷,為了和后面分開(kāi)
case 4:write_date('T'); //寫(xiě)入T。整個(gè)的意思是如果we等于4,則顯示THU,即星期四
delay(5); //延時(shí)5毫秒后寫(xiě)入H
write_date('H'); //寫(xiě)入H
delay(5); //延時(shí)5毫秒后寫(xiě)入U(xiǎn)
write_date('U'); //寫(xiě)入U(xiǎn)
break; //間斷,為了和后面分開(kāi)
case 5:write_date('F'); //寫(xiě)入F。整個(gè)的意思是如果we等于5,則顯示FRI,即星期五
delay(5); //延時(shí)5毫秒后寫(xiě)入R
write_date('R'); //寫(xiě)入R
delay(5); //延時(shí)5毫秒后寫(xiě)入I
write_date('I'); //寫(xiě)入I
break; //間斷,為了和后面分開(kāi)
case 6:write_date('S'); //寫(xiě)入S。整個(gè)的意思是如果we等于6,則顯示SAT,即星期六
delay(5); //延時(shí)5毫秒后寫(xiě)入A
write_date('A'); //寫(xiě)入A
delay(5); //延時(shí)5毫秒后寫(xiě)入T
write_date('T'); //寫(xiě)入T
break; //間斷,為了和后面分開(kāi)
case 7:write_date('S'); //寫(xiě)入S。整個(gè)的意思是如果we等于7,則顯示SUN,即星期日
delay(5); //延時(shí)5毫秒后寫(xiě)入U(xiǎn)
write_date('U'); //寫(xiě)入U(xiǎn)
delay(5); //延時(shí)5毫秒后寫(xiě)入N
write_date('N'); //寫(xiě)入N
break; //間斷,為了和后面分開(kāi)
}
}
void keyscan() //數(shù)字時(shí)鐘按鍵掃描函數(shù)
{
if(flag_ri==1) //如果標(biāo)志位,鬧鐘等于1,則蜂鳴器會(huì)響 ,這一句和按鍵掃描沒(méi)有關(guān)系,主要是為了任意鍵可以消除
//鬧鐘的報(bào)警,可以理解為,為鬧鐘取消而增加的一個(gè)掃描小程序。
{
if((s1==0)||(s2==0)||(s3==0)||(s4==0)) //如果s1-s4有一個(gè)為零,低電平 ||這個(gè)符號(hào)是關(guān)系運(yùn)算符, 或的意思,有一個(gè)是低電平,則進(jìn)行下一步。
{
delay(5); //延時(shí)去抖動(dòng)
if((s1==0)||(s2==0)||(s3==0)||(s4==0)) //再次確認(rèn),如果s1-s4有一個(gè)為零,低電平
{
while(!(s1&&s2&&s3&&s4)); /*/如果他們運(yùn)算的結(jié)果為0 ,當(dāng)鬧鐘響起,就會(huì)進(jìn)入這個(gè)按鍵掃描程序,這沒(méi)有按下鍵盤(pán)的時(shí)候,
就會(huì)運(yùn)行到這里,進(jìn)行判斷循環(huán),一直等在,四個(gè)按鍵,有一個(gè)為0,這個(gè)語(yǔ)句就會(huì)判斷為假,進(jìn)行下一步運(yùn)算,&&這個(gè)符號(hào)是關(guān)系運(yùn)算的 與,
一個(gè)值為零,則整體結(jié)果運(yùn)算為0*/
di(); //則蜂鳴器會(huì)響,鬧鐘有自己的蜂鳴程序,這里有個(gè)DI主要原因是,每次按鍵 都會(huì)響,這是事先規(guī)定號(hào)的
flag_ri=0; //清除報(bào)警標(biāo)志
}
}
}
if(s1==0) //檢測(cè)按鍵s1
{
delay(5); //延時(shí)5毫秒,也可叫延時(shí)去抖動(dòng)。
if(s1==0) //再次檢測(cè)按鍵s1
{
s1num++; //定義為鍵盤(pán)按下的次數(shù)
if(flag1 == 1) //這個(gè)是用來(lái)鬧鐘的,如果等予1,說(shuō)明現(xiàn)在是在設(shè)置鬧鐘值,從下面來(lái)看這個(gè)只能調(diào)節(jié)每天的鬧鐘,不能調(diào)節(jié)年月
if(s1num == 4) //因?yàn)橹荒苷{(diào)節(jié)時(shí)分秒,讓他們?cè)诶锩嫜h(huán)
s1num=1; //這個(gè)地方我卡了幾天,大家要綜合前后文,明白flag1是鬧鐘被按下了,flag是為了跳出主程序循環(huán),為了設(shè)置時(shí)間
flag=1; //按鍵計(jì)數(shù)以后,則這個(gè)位變量變成1,
while(!s1); /*!s1 的意思是取s1相反的數(shù),是用來(lái)測(cè)試判斷按鍵按下后有沒(méi)有松開(kāi),松開(kāi)則計(jì)數(shù)一次后,電平
變成高電平,說(shuō)明此時(shí)已經(jīng)松開(kāi),也確定了s1num的具體數(shù)值,也就是按了幾下*/
di(); //每按下一次則響一聲
switch(s1num) //判斷是按了幾下,則選擇什么位置光標(biāo)點(diǎn)閃爍。
{
case 1:write_com(0x80+0x40+10); //很明顯這是顯示屏第二行的顯示指令,10 說(shuō)明光標(biāo)調(diào)節(jié)的是秒
write_com(0x0f); /*/不管你按的再快,光標(biāo)也會(huì)從第一步開(kāi)始,所以把 開(kāi)顯示,顯示光標(biāo),光標(biāo)閃爍 這個(gè)lcd的這個(gè)
指令設(shè)置放在這里 */
break; //會(huì)不停的跳出,再去問(wèn)現(xiàn)在是按了幾下了,按了幾下,就會(huì)進(jìn)入對(duì)應(yīng)的里面,下面都是一樣的不解釋了。
case 2:write_com(0x80+0x40+7); /*這個(gè)就是光標(biāo)在分鐘上閃爍,(不光時(shí)分秒都是在他們的十位閃爍,
如果送的是兩位數(shù),LCD的指針可以自動(dòng)加一,把個(gè)位也給顯示了)*/
break;
case 3:write_com(0x80+0x40+4); //這個(gè)是在小時(shí)的位置顯示閃爍
break;
case 4:write_com(0x80+12); //這就是進(jìn)入顯示屏第一行了,在顯示星期的位置,第十位,最右邊,是調(diào)節(jié)星期的位置。
break;
case 5:write_com(0x80+9); //日
break;
case 6:write_com(0x80+6); //月
break;
case 7:write_com(0x80+3); //年
break;
case 8:s1num=0; //把按鍵數(shù)置零,等這個(gè)小程序運(yùn)行完,則光標(biāo)不在閃縮,一切正常運(yùn)行。相當(dāng)于不選擇任何位置。
write_com(0x0c); //設(shè)置開(kāi)顯示,不顯示光標(biāo)
flag=0; //等于0就是回到主程序的正常運(yùn)行(可以參看以下主程序,更能方便理解)
/*下面的幾句基本一樣,明白一個(gè)就全明白了,這個(gè)地方主要是查表,查寄存器A,功能列表有時(shí)分秒,鬧鐘的也有時(shí)分秒,年月日他們分別
對(duì)應(yīng)的寄存器地址,比如秒對(duì)應(yīng)的是00H,分鐘對(duì)應(yīng)的是02H,所以0,2,4,6,7,8,9都是地址,往這個(gè)里面寫(xiě),就是寫(xiě)的時(shí)分秒,
可能有人問(wèn),既然是00H,02H,為什么寫(xiě)成0,2等等,其實(shí)是因?yàn)槭M(jìn)制和十進(jìn)制在0~9,書(shū)寫(xiě)雖然有區(qū)別,但是結(jié)果都一樣*/
write_ds(0,miao);
write_ds(2,fen);
write_ds(4,shi);
write_ds(6,week);
write_ds(7,day);
write_ds(8,month);
write_ds(9,year);
break; //跳出
}
}
}
if(s1num!=0) //測(cè)試不等于 0,也就是只有當(dāng)s1按下時(shí)才能檢測(cè)和用來(lái)啟動(dòng)s2和s3.
{
if(s2==0) //問(wèn)S2按鍵有沒(méi)有按下
{
delay(1); //延時(shí)1毫秒
if(s2==0) //再次來(lái)檢測(cè)
{
while(!s2); //給s2取反
di(); //滴一聲
switch(s1num) //根據(jù)s1按下的次數(shù),來(lái)確定調(diào)節(jié)哪個(gè)位置
{ //下面給大家解釋一組,應(yīng)該可以全部明白
case 1:miao++; //按鍵s2按一下,這里就會(huì)加一 設(shè)置秒鐘
if(miao==60) //如果加到了60 ,秒就會(huì)變成0
miao=0;
write_sfm(10,miao); //把秒的值經(jīng)過(guò)運(yùn)算,送到LCD相應(yīng)的位置去顯示
write_com(0x80+0x40+10); /*這一句是調(diào)用寫(xiě)指令,因?yàn)橹羔槹衙腼@示完畢后,光標(biāo)就會(huì)在秒的個(gè)位,
所以這一句是把光標(biāo)在拉回來(lái),因?yàn)椴荒苷靡幌伦泳桶衙氲闹翟O(shè)置的正好*/
break; //然后跳出,等待按鍵再次按下
case 2:fen++; //設(shè)置分鐘
if(fen==60) //分,秒都用到60,生活中并沒(méi)有60,這里也不能設(shè)置成59,但是可以改程序?yàn)?gt;59.道理是一樣的
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+7);
break;
case 3:shi++; //設(shè)置時(shí)鐘
if(shi==24) //和上面一樣的道理
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+4);
break;
case 4:week++; //設(shè)置星期
if(week ==8) //當(dāng)按下第八次的時(shí)候,則8就會(huì)變成1
week=1;
write_week(week);
write_com(0x80+12);
break;
case 5:day++; //設(shè)置天數(shù)
if(day==32)
day=1;
write_nyr(9,day);
write_com(0x80+9);
break;
case 6:month++; //設(shè)置月數(shù)
if(month==13)
month=1;
write_nyr(6,month);
write_com(0x80+6);
break;
case 7:year++; //設(shè)置年
if(year==100)
year=0;
write_nyr(3,year);
write_com(0x80+3);
break;
}
}
}
if(s3==0) //上面是增大鍵,下面就是減少鍵
{
delay(1); //延遲1毫秒
if(s3==0) //再次判斷有沒(méi)有按下
{
while(!s3); //取相反數(shù),看看是不是為真
di();
switch(s1num) //根據(jù)按鍵1,就可以確定光標(biāo)在什么位置,下面介紹和上面基本上一樣,
{ //只不過(guò)沒(méi)有60了,反而有59,可以好好理解一下,其實(shí)很簡(jiǎn)單這個(gè)地方,就不解釋了
case 1:miao--; //設(shè)置秒鐘
if(miao==-1)
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+10);
break;
case 2:fen--; //設(shè)置分鐘
if(fen==-1)
fen=59;
write_sfm(7,fen);
write_com(0x80+0x40+7);
break;
case 3:shi--; //設(shè)置小時(shí)
if(shi==-1)
shi=23;
write_sfm(4,shi);
write_com(0x80+0x40+4);
break;
case 4:week--; //設(shè)置星期
if(week==-0)
week=7;
write_week(week);
write_com(0x80+12);
break;
case 5:day--; //設(shè)置天數(shù)
if(day==0)
day=31;
write_nyr(9,day);
write_com(0x80+9);
break;
case 6:month--; //設(shè)置月數(shù)
if(month==0)
month=12;
write_nyr(6,month);
write_com(0x80+6);
break;
case 7:year--; //設(shè)置年
if(year==-1)
year=99;
write_nyr(3,year);
write_com(0x80+3);
break;
}
}
}
}
if(s4==0) //這個(gè)地方是鬧鐘設(shè)置鍵
{
delay(5); //延時(shí)5毫秒
if(s4==0) //再次判斷是否按下
{
flag1=~flag1; //如果按下,則按鍵1程序,進(jìn)入時(shí)分秒的循環(huán),這里的講解和前面相呼應(yīng)。
while(!s4); //取反是不是為真
di(); //為真說(shuō)明,有按鍵按下,響一聲,
s1num=0;
/*調(diào)試仿真時(shí)發(fā)現(xiàn)如果按下了按鍵一 在按鬧鐘,然后取消鬧鐘,在按按鍵一,會(huì)不出現(xiàn)光標(biāo),為了讓鬧鐘和按鍵一不沖突,我添加這一句
每當(dāng)我按下按鍵一,不管按幾次,只要按下按鍵4,都會(huì)讓光標(biāo)變成0位 */
if(flag1==0) //如果等于0,說(shuō)明按得第二下,屬于退出鬧鐘設(shè)置。
{
flag=0; //程序運(yùn)行到這一步,說(shuō)明運(yùn)行完這個(gè)程序,就要回到主程序了,
//把按鍵1標(biāo)志指令以后,本程序結(jié)束,可以進(jìn)入主程序,否則還要在去按鍵1,按幾下
write_com(0x80+0x40); //把指針選擇第二行,第一位,
write_date(' '); //寫(xiě)入兩個(gè)空的符號(hào),主要是為了區(qū)別狀態(tài),是調(diào)整時(shí)間還是設(shè)置鬧鐘
write_date(' ');
write_com(0x0c); //關(guān)閉光標(biāo)閃爍
write_ds(1,miao); //把時(shí)分秒送到DS12C887,程序正常運(yùn)行
write_ds(3,fen); //這個(gè)時(shí)候的135要注意,可以看出是新設(shè)置鬧鐘值
write_ds(5,shi);
}
else //如果flag不等于0,則進(jìn)入這個(gè)程序,實(shí)際上程序都是先運(yùn)行這個(gè)
{ //進(jìn)入鬧鐘設(shè)置
read_alarm(); //讀鬧鐘原來(lái)的數(shù)據(jù)
miao=amiao; //分別送入時(shí)分秒
fen=afen;
shi=ashi;
write_com(0x80+0x40); //寫(xiě)指令,把指針,也就是光標(biāo)位置放在第二排第一位
write_date('R'); //分別送入R I送去顯示,可以區(qū)分現(xiàn)在是在調(diào)整時(shí)間,還是修改鬧鐘
write_date('I');
write_com(0x80+0x40+3); /*這個(gè)地方還有一個(gè)指針,就會(huì)讓很多人不理解,其實(shí)這個(gè)地方設(shè)計(jì)很巧妙
3號(hào)位置,正好是時(shí)鐘前面一位,然后再那邊閃爍,接著等待按鍵1,來(lái)選擇調(diào)整時(shí)分秒,
按一下變換一個(gè)位置,在3號(hào)位閃爍還不影響開(kāi)始時(shí)的鬧鐘值*/
write_sfm(4,ashi); //送到液晶去顯示
write_sfm(7,afen);
write_sfm(10,amiao);
}
}
}
}
void write_ds(uchar add,uchar date) //寫(xiě)DS12C887函數(shù)
{
dscs=0; //根據(jù)時(shí)序圖,把相應(yīng)的腳變化高低,片選端,低電平有效
dsas=1; //地址選通輸入端
dsds=1; //讀允許輸入腳
dsrw=1; //寫(xiě)輸入腳
P0=add; //寫(xiě)地址
dsas=0;
dsrw=0;
P0=date; //寫(xiě)命令
dsrw=1;
dsas=1;
dscs=1;
}
uchar read_ds(uchar add) //讀DS12C887函數(shù) ,這里沒(méi)有用void要注意
{
uchar ds_date; //定義一個(gè)無(wú)符號(hào)函數(shù)
dsas=1; //根據(jù)時(shí)序圖,進(jìn)行高低電平設(shè)置
dsds=1;
dsrw=1;
dscs=0;
P0=add; //寫(xiě)地址,確定要讀什么位置的值
dsas=0;
dsds=0;
P0=0xff; //先把P1進(jìn)行置高,清理數(shù)據(jù)
ds_date=P0; //把新的得到了 12c887里面的數(shù)值,賦值給ds_date
dsds=1; //根據(jù)時(shí)序圖繼續(xù)設(shè)置電平
dsas=1;
dscs=1;
return ds_date; //誰(shuí)調(diào)用它,什么位置調(diào)用的,就會(huì)把這個(gè)新得到的值在返回給他,
//看得出來(lái)只有讀鬧鐘值是調(diào)用了。
}
void set_time() //首次操作12c887時(shí)給寄存器初始化,完成后,要把這一段用 給屏蔽起來(lái)
{
write_ds(0,0); //根據(jù)寄存器A,相當(dāng)于 所有的位置,全部顯示00。
write_ds(1,0);
write_ds(2,0);
write_ds(3,0);
write_ds(4,0);
write_ds(5,0);
write_ds(6,0);
write_ds(7,0);
write_ds(8,0);
write_ds(9,0);
}
void read_alarm() //讀取鬧鐘值
{
amiao=read_ds(1); //根據(jù)寄存器A,分別把鬧鐘值讀出來(lái),并且賦值給時(shí)分秒
afen=read_ds(3);
ashi=read_ds(5);
}
void main() //主程序
{
init(); //調(diào)用初始化函數(shù)
while(1) //為真不斷循環(huán),等待鬧鐘中斷
{
keyscan(); //按鍵子程序,不斷地掃描
if(flag_ri==1) //如果有鬧鐘,則進(jìn)入這里
{
di();
delay(100); //一直響 滴滴
di();
delay(500);
}
if((flag==0) && (flag1==0)) //如果按鍵標(biāo)志位和鬧鐘標(biāo)志位都為0,則繼續(xù)
{
keyscan(); //按鍵繼續(xù)掃描
year=read_ds(9); //把DS12C887里面的數(shù)值不斷讀取
month=read_ds(8);
day=read_ds(7);
week=read_ds(6);
shi=read_ds(4);
fen=read_ds(2);
miao=read_ds(0);
write_sfm(10,miao); //這里把DS12c887的值不斷地寫(xiě)入到lcd1602
write_sfm(7,fen);
write_sfm(4,shi);
write_week(week);
write_nyr(3,year);
write_nyr(6,month);
write_nyr(9,day);
}
}
}
void exter()interrupt 0 //中斷1程序
{
uchar c; //定義一個(gè)無(wú)符號(hào)數(shù)值
flag_ri=1; //鬧鐘中斷時(shí)間到了
c=read_ds(0x0c); //讀取c寄存器的值,表示響應(yīng)了中斷
}
在這里插入代碼片
|
評(píng)分
-
查看全部評(píng)分
|