欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
注釋很詳細的51單片機簡易的電子鐘程序+Proteus仿真電路
[打印本頁]
作者:
xgy333777
時間:
2019-11-23 22:15
標題:
注釋很詳細的51單片機簡易的電子鐘程序+Proteus仿真電路
有需要自己借鑒
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei截圖20191123221417.png
(55.77 KB, 下載次數: 70)
下載附件
2019-11-23 22:14 上傳
單片機源程序如下:
/*------------------------------------------------------------------------------------------------
程序功能:采用LCD1602液晶顯示,顯示項目有:年月日、星期、時分秒,帶按鍵調整功能。
按鍵操作說明:
1、S3按鍵:是調整時間日期鍵,該按鍵選擇對秒、分、時、星期、日、月、年選中操作,
當其中一個被選中的時候,可以進行時間調整和日期的調整。每按一次調整一個時間或日期,直到"年"再按一次退出設置界面。
2、S1按鍵:是時間、日期增加操作。
3、S2按鍵:是時間、日期減少操作。
------------------------------------------------------------------------------------------------*/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit ds1302_sclk= P1^4; //DS1302的Sclk時鐘線位定義
sbit ds1302_io = P1^5; //DS1302的i/o數據線位定義
sbit ds1302_ce = P1^6; //DS1302的ce片選線位定義
sbit rd=P3^7;
sbit lcd1602_rs = P1^2; //位定義1602液晶數據命令選擇端
sbit lcd1602_rw = P1^1; //位定義1602液晶讀寫選擇端
sbit lcd1602_en = P1^0; //位定義1602液晶使能端
sbit set = P3^4; //定義S9按鍵_時間設置選擇鍵
sbit up = P3^2; //定義S13按鍵_增加鍵
sbit down= P3^3; //定義S17按鍵_減小鍵
uchar time_data[]={19,6,11,23,13,14,0}; //設置時間初值(年、周、月、日、時、分、秒)
uchar write_add[]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80}; //年、周、月、日、時、分、秒的寄存器寫入地址
uchar code table1[]={"20 - - Week"}; //液晶一直顯示的字符
uchar code table2[]={" : : "}; //用空格補齊16位
uchar miao,fen,shi,nian,yue,ri,week;
uchar flag=1,count=0,flag_up=0,flag_down=0,done=0;
void delay(uchar x) //延時函數
{
uchar y,z;
for(z=x;z>0;z--)
for(y=110;y>0;y--);
}
/*****************************與ds1302相關函數*********************************/
void write_ds1302_byte(uchar dat) //ds1302寫一字節
{
uchar i;
for(i=0;i<8;i++) //分8次循環,把(add)一位一位的寫入
{
ds1302_sclk=0;
ds1302_io =dat&0x01; //dat和0x01進行按位與,保留最低位。即從低位開始寫入
dat=dat>>1; //add右移一位
ds1302_sclk=1;
}
}
void ds1302_write(uchar add,uchar date) //單字節寫操作函數(包含地址和數據)
{
ds1302_ce=0;
ds1302_sclk=0;
ds1302_ce=1; //ce變為高電平,允許單片機向DS1302中的寄存器寫入地址命令和數據
_nop_();
write_ds1302_byte(add); //寫入控制命令(指明寫入的寄存器地址及后續的操作為寫操作)
write_ds1302_byte(date); //寫入一個字節數據
ds1302_ce=0; //地址命令和數據寫完之后,把ce拉低,防止對寫入的數據進行誤操作
_nop_();
ds1302_io =1; //釋放IO數據線
ds1302_sclk=1; //釋放sclk時鐘線
}
uchar ds1302_read(uchar add) //單字節讀操作函數
{
uchar i,value;
ds1302_ce=0;
ds1302_sclk=0;
ds1302_ce=1; //ce變為高電平,單片機向DS1302中的寄存器寫入地址命令,并讀出數據
_nop_(); //稍微延時(一個機器周期)
write_ds1302_byte(add); //寫入控制命令,(指明要讀取的寄存器地址及后續的操作為讀操作)
for(i=0;i<8;i++) //分8次循環,把數據一位一位的讀出
{
value=value>>1; //value右移一位
ds1302_sclk=0; //把sclk時鐘置為低電平,開始讀取數據
if(ds1302_io)
{
value=value|0x80; //把I0讀到的值,放到value 的最高位
}
ds1302_sclk=1;
}
ds1302_ce=0; //一個字節的數據讀完之后,把ce拉低
_nop_();
ds1302_sclk=0; //釋放sclk時鐘線
_nop_();
ds1302_sclk=1;
ds1302_io=1; //釋放io數據線
return value; //把 value值返回
}
void set_rtc() //設置時間初值函數
{
uchar i,j,k;
for(i=0;i<7;i++) //把數組time_data[]中的7個十進制數轉換成BCD碼
{
j=time_data[i]/10;
k=time_data[i]%10;
time_data[i]=k+j*16;
}
ds1302_write(0x8e,0x00); //在往寄存器寫之前,要去除寫保護(8e為寫保護寄存器的地址)
for(i=0;i<7;i++) //分7次循環,向年、周、月、日、時、分、秒的寄存器寫入時間數據
{
ds1302_write(write_add[i],time_data[i]);
}
ds1302_write(0x8e,0x80); //加寫保護
}
/***************************與lcd1602相關函數***************************/
void lcd_write_com(uchar com) //寫命令函數
{
lcd1602_rs=0; //數據命令選擇端,寫命令時設為0
lcd1602_rw=0; //讀寫選擇端,寫時設為0
lcd1602_en=0;
P0=com; //將要寫的命令送到數據總線上
lcd1602_en=1; //使能端電平變換,形成一個高脈沖將命令寫入到液晶控制器
delay(5); //延時
lcd1602_en=0;
}
void lcd_write_date(uchar date) //寫數據函數
{
lcd1602_rs=1; //數據命令選擇端,寫數據時設為1
lcd1602_rw=0; //讀寫選擇端,寫時設為0
lcd1602_en=0;
P0=date; //將要寫的數據送到數據總線上
lcd1602_en=1; //使能端電平變換,形成一個高脈沖將命令寫入到液晶控制器
delay(5); //延時
lcd1602_en=0;
}
void lcd1602_init() //LCD1602初始化函數
{
uchar lcdnum;
lcd_write_com(0x38);
lcd_write_com(0x0c);
lcd_write_com(0x06);
lcd_write_com(0x01);
lcd_write_com(0x80); //寫第一行數據
for(lcdnum=0;lcdnum<16;lcdnum++)
{
lcd_write_date(table1[lcdnum]);
delay(2);
}
lcd_write_com(0x80+0x40); //寫入第二行數據
for(lcdnum=0;lcdnum<16;lcdnum++)
{
lcd_write_date(table2[lcdnum]);
delay(2);
}
}
/***********************************顯示部分********************************/
void write_time1(uchar add,uchar date) //日期送顯示
{
uchar shi,ge;
shi=date/10;
ge=date%10;
lcd_write_com(0x80+add);
lcd_write_date(0x30+shi);
lcd_write_date(0x30+ge);
}
void write_time2(uchar add,uchar date) //時間送顯示
{
uchar shi,ge;
shi=date/10;
ge=date%10;
lcd_write_com(0x80+0x44+add);
lcd_write_date(0x30+shi);
lcd_write_date(0x30+ge);
}
uchar bcd_decimal(uchar bcd) //bcd轉換十進制
{
uchar decimal;
decimal=bcd>>4;
decimal=decimal*10+(bcd&=0x0f);
return decimal;
}
void write_week(uchar we) //星期送顯示
{
lcd_write_com(0x80+0x0f);
switch(we)
{
case 1: lcd_write_date('1');
break;
case 2: lcd_write_date('2');
break;
case 3: lcd_write_date('3');
break;
case 4: lcd_write_date('4');
break;
case 5: lcd_write_date('5');
break;
case 6: lcd_write_date('6');
break;
case 7: lcd_write_date('7');
break;
}
}
/******************************按鍵處理******************************/
uchar key_bcd(uchar key_decimal) //轉成ds1302所需的BCD碼
{
uchar temp;
temp=(((key_decimal/10)&0x0f)<<4)|(key_decimal%10);
return temp;
}
void key_up_down() //加減鍵處理函數
{
if(up==0) //加鍵處理
{
delay(50);
flag_up=1; //"加"更新標志
while(!up);
switch(count)
{
case 1:
miao++;
if(miao>59)
miao=0;
break;
case 2:
fen++;
if(fen>59)
fen=0;
break;
case 3:
shi++;
if(shi>23)
shi=0;
break;
case 4:
week++;
if(week>7)
week=1;
break;
case 5:
ri++;
if(ri>31)
ri=1;
break;
case 6:
yue++;
if(yue>12)
yue=1;
break;
case 7:
nian++;
if(nian>99)
nian=0;
break;
}
}
if(down==0) //減鍵處理
{
delay(50);
flag_down=1; //"減"更新標志
while(!down);
switch(count)
{
case 1:
miao--;
if(miao==255)
miao=59;
break;
case 2:
fen--;
if(fen==255)
fen=59;
break;
case 3:
shi--;
if(miao==255)
shi=23;
break;
case 4:
week--;
if(week<1)
week=7;
break;
case 5:
ri--;
if(ri<1)
ri=31;
break;
case 6:
yue--;
if(yue<1)
yue=12;
break;
case 7:
nian--;
if(nian==255)
nian=99;
break;
}
}
}
void key_set() //ste鍵掃描函數
{
if(set==0 )
{
delay(50);
if(set==0)
{
while(!set); //等待set釋放
count++; //按set一下,count加1,進入時間調速掃描程序
lcd_write_com(0x0f); //把1602液晶顯示光標并閃爍
if(flag==1)
{
done=1;
flag=0;
ds1302_write(0x8e,0x00); //寫允許
ds1302_write(0x80,key_bcd(miao)|0x80); //BIT7為1,晶振停止工作
ds1302_write(0x8e,0x80); //寫保護
}
}
}
}
void keyjpress() //按鍵處理
{
key_set();
if(count!=0) //count不為0,進入時間調整掃描
{
switch(count)
{
case 1:do
{
lcd_write_com(0x80+0x40+11); //調整秒
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x80,key_bcd(miao) | 0x80);
ds1302_write(0x8e,0x80);
write_time2(6,miao);
lcd_write_com(0x80+0x40+7); //液晶寫字符后光標自動
//向右移動一位,把光標
//左移一位
}
}
while(count==2);
break;
case 2:do
{
lcd_write_com(0x80+0x40+8); //調整分
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x82,key_bcd(fen));
ds1302_write(0x8e,0x80);
write_time2(3,fen);
lcd_write_com(0x80+0x40+4);
}
}
while(count==3);
break;
case 3:do
{
lcd_write_com(0x80+0x40+5); //調整時
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x84,key_bcd(shi));
ds1302_write(0x8e,0x80);
write_time2(0,shi);
lcd_write_com(0x80+0x40+1);
}
}
while(count==4);
break;
case 4: do
{
lcd_write_com(0x80+0x0f); //調整星期
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x8a,key_bcd(week));
ds1302_write(0x8e,0x80);
write_week(week);
lcd_write_com(0x80+0x0e);
}
}
while(count==5);
break;
case 5:do
{
lcd_write_com(0x80+9); //調整日
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x86,key_bcd(ri));
ds1302_write(0x8e,0x80);
write_time1(8,ri);
lcd_write_com(0x80+9);
}
}
while(count==6);
break;
case 6:do
{
lcd_write_com(0x80+6); //調整月
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x88,key_bcd(yue));
ds1302_write(0x8e,0x80);
write_time1(5,yue);
lcd_write_com(0x80+6);
}
}
while(count==7);
break;
case 7:
lcd_write_com(0x80+3); //調整年
key_up_down();
if(flag_up || flag_down)
{
flag_up=0;
flag_down=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x8c,key_bcd(nian));
ds1302_write(0x8e,0x80);
write_time1(2,nian);
lcd_write_com(0x80+3);
}
break;
case 8:
lcd_write_com(0x0c); //調整結束,關閉顯示光標
flag=1;
done=0;
count=0;
ds1302_write(0x8e,0x00);
ds1302_write(0x80,key_bcd(miao)&0x7f); //BIT7為0,晶振開始工作
ds1302_write(0x8e,0x80);
break;
default:break;
}
}
}
void xianshi() //1602液顯示函數
{
//讀秒分時,日月年,星期
miao=bcd_decimal(ds1302_read(0x81));
fen =bcd_decimal(ds1302_read(0x83));
shi =bcd_decimal(ds1302_read(0x85));
ri =bcd_decimal(ds1302_read(0x87));
yue =bcd_decimal(ds1302_read(0x89));
nian=bcd_decimal(ds1302_read(0x8d));
week=bcd_decimal(ds1302_read(0x8b));
//送液晶顯示
write_time2(6,miao);
write_time2(3,fen);
write_time2(0,shi);
write_time1(8,ri);
write_time1(5,yue);
write_time1(2,nian);
write_week(week);
}
main() //主函數
{
uchar ch;
lcd1602_en=0; //關閉1602液晶使能,防止1602數據端影響單片機P0口輸出
P0=0xff;
lcd1602_init(); //1602液晶初始化
ch=ds1302_read(0x81)>>7; //讀取DS1302時鐘的秒寄存器的值,并保留最高位
if(ch) //判斷:若ch為0,不設置初值;若ch為1,重新設置初值
{
set_rtc(); //對DS1302設置時間初值
}
while(1)
{
if(done==1)
{
keyjpress();
}
if(done==0)
{
xianshi(); //取得并顯示日歷、時間
key_set();
}
}
}
復制代碼
所有資料51hei提供下載:
time1.zip
(82.72 KB, 下載次數: 115)
2019-11-23 22:13 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
wulingqing
時間:
2019-11-24 10:05
這注釋真的非常這詳細,非常棒,謝謝分享!
作者:
xkeli
時間:
2019-12-18 16:11
這注釋真的非常這詳細,非常棒,謝謝分享!
作者:
wyk1237
時間:
2019-12-18 20:13
謝謝老師,好好學習
作者:
flyingpigLZ
時間:
2020-6-5 15:12
太強了
作者:
悠悠寸草心
時間:
2020-6-5 22:31
很詳細,非常感謝
作者:
2231750246
時間:
2020-6-7 09:51
大神厲害,我學到了
作者:
ashdshdash
時間:
2023-4-26 10:23
為什么我的搞完之后,數碼管顯示2005/5/05-05:05:05.ds1302顯示的年和日期反了
作者:
sonique0371
時間:
2023-4-27 13:48
為什么運行起來時間誤差很大呢?每分鐘誤差10秒。
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1