有需要自己借鑒
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
單片機源程序如下:
- /*------------------------------------------------------------------------------------------------
- 程序功能:采用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 上傳
點擊文件名下載附件
|