找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5909|回复: 4
打印 上一主题 下一主题
收起左侧

LCD数字时钟proteus仿真文件及程序详细注释

[复制链接]
跳转到指定楼层
楼主
希望能帮助到大家




  1. /***************************************************/
  2. #include<reg51.h>     //包含单片机寄存器的头文件
  3. #include<intrins.h>   //包含_nop_()函数定义的头文件
  4. #define uchar unsigned char
  5. #define uint  unsigned int
  6. uchar temp,count=0;
  7. /***********************************************************************
  8. 以下是DS1302芯片的操作程序
  9. ************************************************************************/
  10. uchar code digit[10]={"0123456789"};   //定义字符数组显示数字
  11. uchar *digit1[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"}; //周日,周一到周六
  12. sbit DATA=P3^7;   //位定义1302芯片的接口,数据输出端定义在P1.1引脚
  13. sbit RST=P3^5;    //位定义1302芯片的接口,复位端口定义在P1.1引脚
  14. sbit SCLK=P3^6;   //位定义1302芯片的接口,时钟输出端口定义在P1.1引脚
  15. sbit key1=P3^0;          //停止按钮
  16. sbit key2=P3^1;          //开始按钮
  17. sbit add=P2^4;          //加值
  18. sbit subtract=P2^5;//减值
  19. sbit tiaoshi=P3^4; //定位
  20. /*****************************************************
  21. 函数功能:延时若干微秒
  22. 入口参数:n
  23. ***************************************************/
  24. void delaynus(uchar n)
  25. {
  26. uchar i;
  27. for(i=0;i<n;i++)
  28.       ;
  29. }

  30. /*****************************************************
  31. 函数功能:向1302写一个字节数据
  32. 入口参数:x
  33. ***************************************************/
  34. void Write1302(uchar dat)
  35. {
  36.   uchar i;
  37.   SCLK=0;                            //拉低SCLK,为脉冲上升沿写入数据做好准备
  38.   delaynus(2);                       //稍微等待,使硬件做好准备
  39.   for(i=0;i<8;i++)              //连续写8个二进制位数据
  40.     {
  41.             DATA=dat&0x01;            //取出dat的第0位数据写入1302
  42.                 delaynus(2);        //稍微等待,使硬件做好准备
  43.                 SCLK=1;             //上升沿写入数据
  44.                 delaynus(2);              //稍微等待,使硬件做好准备
  45.                 SCLK=0;                   //重新拉低SCLK,形成脉冲
  46.                 dat>>=1;                  //将dat的各数据位右移1位,准备写入下一个数据位
  47.           }
  48.        
  49. }
  50. /*****************************************************
  51. 函数功能:根据命令字,向1302写一个字节数据
  52. 入口参数:Cmd,储存命令字;dat,储存待写的数据
  53. ***************************************************/
  54. void WriteSet1302(uchar Cmd,uchar dat)
  55. {
  56.     RST=0;           //禁止数据传递
  57.     SCLK=0;          //确保写数居前SCLK被拉低
  58.         RST=1;           //启动数据传输
  59.         delaynus(2);     //稍微等待,使硬件做好准备
  60.         Write1302(Cmd);  //写入命令字
  61.         Write1302(dat);  //写数据
  62.         SCLK=1;          //将时钟电平置于已知状态
  63.         RST=0;           //禁止数据传递
  64. }
  65. /*****************************************************
  66. 函数功能:从1302读一个字节数据
  67. 入口参数:x
  68. ***************************************************/
  69. uchar Read1302(void)
  70. {
  71.            uchar i,dat;
  72.         delaynus(2);       //稍微等待,使硬件做好准备
  73.         for(i=0;i<8;i++)   //连续读8个二进制位数据
  74.          {
  75.                    dat>>=1;       //将dat的各数据位右移1位,因为先读出的是字节的最低位
  76.                 if(DATA==1)    //如果读出的数据是1
  77.                  dat|=0x80;    //将1取出,写在dat的最高位
  78.                  SCLK=1;       //将SCLK置于高电平,为下降沿读出
  79.                  delaynus(2);  //稍微等待
  80.                  SCLK=0;       //拉低SCLK,形成脉冲下降沿
  81.                  delaynus(2);  //稍微等待
  82.           }         
  83.           return dat;        //将读出的数据返回
  84. }  
  85. /*****************************************************
  86. 函数功能:根据命令字,从1302读取一个字节数据
  87. 入口参数:Cmd
  88. ***************************************************/
  89. uchar  ReadSet1302(uchar Cmd)
  90. {
  91.   uchar dat;
  92.   RST=0;                 //拉低RST
  93.   SCLK=0;                //确保写数居前SCLK被拉低
  94.   RST=1;                 //启动数据传输
  95.   Write1302(Cmd);        //写入命令字
  96.   dat=Read1302();        //读出数据
  97.   SCLK=1;                //将时钟电平置于已知状态
  98.   RST=0;                 //禁止数据传递
  99.   return dat;            //将读出的数据返回
  100. }
  101. /*****************************************************
  102. 函数功能:设置ds1302是否写保护
  103. 入口参数:flag
  104. ***************************************************/
  105. void setprotect(bit flag)//设置保护
  106. {
  107. if(flag)
  108. WriteSet1302(0x8e,0x80);//写入保护指令
  109. else
  110. WriteSet1302(0x8e,0x00);//写入不保护指令
  111. }

  112. /*****************************************************
  113. 函数功能:设置ds1302是否工作
  114. 入口参数:flag
  115. ***************************************************/
  116. void stoptime(bit  flag) // 是否将时钟停止
  117. {
  118. uchar dat;
  119. dat=ReadSet1302(0x81);
  120. setprotect(0);
  121. if(flag)
  122. WriteSet1302(0x80, dat|0x80);
  123. else
  124.   WriteSet1302(0x80, dat&0x7f);
  125. }

  126. /*****************************************************
  127. 函数功能: 1302进行初始化设置
  128. ***************************************************/
  129. void Init_DS1302(void)
  130. {       
  131.     stoptime(0);                 //根据写状态寄存器命令字,写入不保护指令
  132.     WriteSet1302(0x80,((0/10)<<4|(0%10)));   //根据写秒寄存器命令字,写入秒的初始值
  133.         WriteSet1302(0x82,((0/10)<<4|(0%10)));   //根据写分寄存器命令字,写入分的初始值
  134.         WriteSet1302(0x84,((12/10)<<4|(12%10))); //根据写小时寄存器命令字,写入小时的初始值
  135.         WriteSet1302(0x86,((01/10)<<4|(01%10))); //根据写日寄存器命令字,写入日的初始值
  136.         WriteSet1302(0x88,((06/10)<<4|(06%10))); //根据写月寄存器命令字,写入月的初始值
  137.         WriteSet1302(0x8c,((10/10)<<4|(10%10)));   //根据写小时寄存器命令字,写入小时的初始值
  138.     WriteSet1302(0x8a,0x01);   //根据写小时寄存器命令字,写入小时的初始值
  139. }
  140. /*******************************************************************************
  141. 以下是对液晶模块的操作程序
  142. *******************************************************************************/
  143. sbit RS=P2^0;           //寄存器选择位,将RS位定义为P2.0引脚
  144. sbit RW=P2^1;           //读写选择位,将RW位定义为P2.1引脚
  145. sbit E=P2^2;            //使能信号位,将E位定义为P2.2引脚
  146. sbit BF=P1^7;           //忙碌标志位,,将BF位定义为P0.7引脚
  147. /*****************************************************
  148. 函数功能:延时1ms
  149. (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒
  150. ***************************************************/
  151. void delay1ms()
  152. {
  153.    unsigned char i,j;       
  154.          for(i=0;i<10;i++)
  155.           for(j=0;j<33;j++)
  156.            ;                 
  157. }
  158. /*****************************************************
  159. 函数功能:延时若干毫秒
  160. 入口参数:n
  161. ***************************************************/
  162. void delaynms(unsigned char n)
  163. {
  164.    unsigned char i;
  165.         for(i=0;i<n;i++)
  166.            delay1ms();
  167. }
  168. /*****************************************************
  169. 函数功能:判断液晶模块的忙碌状态
  170. 返回值:result。result=1,忙碌;result=0,不忙
  171. ***************************************************/
  172. bit BusyTest(void)
  173.   {
  174.     bit result;
  175.         RS=0;        //根据规定,RS为低电平,RW为高电平时,可以读状态
  176.     RW=1;
  177.     E=1;         //E=1,才允许读写
  178.     _nop_();     //空操作
  179.     _nop_();
  180.     _nop_();
  181.     _nop_();     //空操作四个机器周期,给硬件反应时间       
  182.     result=BF;   //将忙碌标志电平赋给result
  183.     E=0;         //将E恢复低电平
  184.     return result;
  185.   }
  186. /*****************************************************
  187. 函数功能:将模式设置指令或显示地址写入液晶模块
  188. 入口参数:dictate
  189. ***************************************************/
  190. void WriteInstruction (uchar dictate)
  191. {   
  192.      while(BusyTest()==1);   //如果忙就等待
  193.          RS=0;                   //根据规定,RS和R/W同时为低电平时,可以写入指令
  194.          RW=0;   
  195.          E=0;                    //E置低电平(根据表8-6,写指令时,E为高脉冲,
  196.                              // 就是让E从0到1发生正跳变,所以应先置"0"
  197.          _nop_();
  198.          _nop_();                //空操作两个机器周期,给硬件反应时间
  199.          P1=dictate;             //将数据送入P0口,即写入指令或地址
  200.          _nop_();
  201.          _nop_();
  202.          _nop_();
  203.          _nop_();                //空操作四个机器周期,给硬件反应时间
  204.          E=1;                    //E置高电平
  205.          _nop_();
  206.          _nop_();
  207.          _nop_();
  208.          _nop_();                //空操作四个机器周期,给硬件反应时间
  209.           E=0;                   //当E由高电平跳变成低电平时,液晶模块开始执行命令
  210. }
  211. /*****************************************************
  212. 函数功能:指定字符显示的实际地址
  213. 入口参数:x
  214. ***************************************************/
  215. void WriteAddress(uchar x)
  216. {
  217.      WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
  218. }
  219. /*****************************************************
  220. 函数功能:将数据(字符的标准ASCII码)写入液晶模块
  221. 入口参数:y(为字符常量)
  222. ***************************************************/
  223. void WriteData(uchar y)
  224. {
  225.       while(BusyTest()==1);  
  226.           RS=1;           //RS为高电平,RW为低电平时,可以写入数据
  227.           RW=0;
  228.           E=0;            //E置低电平(根据表8-6,写指令时,E为高脉冲,
  229.                       // 就是让E从0到1发生正跳变,所以应先置"0"
  230.           P1=y;           //将数据送入P0口,即将数据写入液晶模块
  231.           _nop_();
  232.           _nop_();
  233.           _nop_();
  234.       _nop_();        //空操作四个机器周期,给硬件反应时间
  235.           E=1;            //E置高电平
  236.           _nop_();
  237.           _nop_();
  238.           _nop_();
  239.           _nop_();        //空操作四个机器周期,给硬件反应时间
  240.           E=0;            //当E由高电平跳变成低电平时,液晶模块开始执行命令
  241. }
  242. /*****************************************************
  243. 函数功能:对LCD的显示模式进行初始化设置
  244. ***************************************************/
  245. void LcdInitiate(void)
  246. {
  247.     delaynms(15);               //延时15ms,首次写指令时应给LCD一段较长的反应时间
  248.     WriteInstruction(0x38);     //显示模式设置:16×2显示,5×7点阵,8位数据接口
  249.         delaynms(5);                //延时5ms ,给硬件一点反应时间
  250.     WriteInstruction(0x38);
  251.         delaynms(5);                //延时5ms ,给硬件一点反应时间
  252.         WriteInstruction(0x38);     //连续三次,确保初始化成功
  253.         delaynms(5);                //延时5ms ,给硬件一点反应时间
  254.         WriteInstruction(0x0c);     //显示模式设置:显示开,无光标,光标不闪烁
  255.         delaynms(5);                //延时5ms ,给硬件一点反应时间
  256.         WriteInstruction(0x06);     //显示模式设置:光标右移,字符不移
  257.         delaynms(5);                //延时5ms ,给硬件一点反应时间
  258.         WriteInstruction(0x01);     //清屏幕指令,将以前的显示内容清除
  259.         delaynms(5);                //延时5ms ,给硬件一点反应时间

  260. }
  261. /**************************************************************
  262. 以下是1302数据的显示程序
  263. **************************************************************/
  264. /*****************************************************
  265. 函数功能:显示秒
  266. 入口参数:x
  267. ***************************************************/
  268. void DisplaySecond(uchar x)
  269. {
  270.     uchar i,j;                      
  271.         i=x/10;                             //取十位
  272.         j=x%10;                                        //取个位     
  273.         WriteAddress(0x49);            //写显示地址,将在第2行第10列开始显示
  274.         WriteData(digit[i]);    //将十位数字的字符常量写入LCD
  275.         WriteData(digit[j]);    //将个位数字的字符常量写入LCD
  276.         delaynms(50);                 //延时1ms给硬件一点反应时间   
  277. }

  278. /*****************************************************
  279. 函数功能:显示分钟
  280. 入口参数:x
  281. ***************************************************/
  282. void DisplayMinute(uchar x)
  283. {
  284.         uchar i,j;                              
  285.         i=x/10;                                         //取十位
  286.         j=x%10;                                         //取个位     
  287.         WriteAddress(0x46);            //写显示地址,将在第2行第7列开始显示
  288.         WriteData(digit[i]);            //将十位数字的字符常量写入LCD
  289.         WriteData(digit[j]);            //将个位数字的字符常量写入LCD
  290.         delaynms(50);                 //延时1ms给硬件一点反应时间   
  291. }
  292. /*****************************************************
  293. 函数功能:显示小时
  294. 入口参数:x
  295. ***************************************************/
  296. void DisplayHour(unsigned char x)
  297. {
  298.         uchar i,j;                            
  299.         i=x/10;                                        //取十位
  300.         j=x%10;                                        //取个位     
  301.         WriteAddress(0x43);            //写显示地址,将在第2行第4列开始显示
  302.         WriteData(digit[i]);    //将十位数字的字符常量写入LCD
  303.         WriteData(digit[j]);    //将个位数字的字符常量写入LCD
  304.         delaynms(50);                 //延时1ms给硬件一点反应时间   
  305. }
  306. /*****************************************************
  307. 函数功能:显示日
  308. 入口参数:x
  309. ***************************************************/
  310. void DisplayDay(uchar x)
  311. {
  312.         uchar i,j;                   
  313.         i=x/10;                                   //取十位
  314.         j=x%10;                                   //取个位     
  315.         WriteAddress(0x09);    //写显示地址,将在第1行第10列开始显示
  316.         WriteData(digit[i]);   //将十位数字的字符常量写入LCD
  317.         WriteData(digit[j]);   //将个位数字的字符常量写入LCD
  318.         delaynms(50);          //延时1ms给硬件一点反应时间   
  319. }
  320. /*****************************************************
  321. 函数功能:显示星期
  322. 入口参数:x
  323. ***************************************************/
  324. void DisplayWeek(uchar x)
  325. {        uchar i;
  326.     WriteAddress(0x0c);    //写显示地址,将在第1行第13列开始显示
  327.         for(i=0;i<3;i++)
  328.         WriteData(digit1[x][i]);
  329.         delaynms(50);
  330. }

  331. /*****************************************************
  332. 函数功能:显示月
  333. 入口参数:x
  334. ***************************************************/
  335. void DisplayMonth(uchar x)
  336. {
  337.         uchar i,j;                   
  338.         i=x/10;                                         //取十位
  339.         j=x%10;                                         //取个位     
  340.         WriteAddress(0x06);             //写显示地址,将在第1行10第列开始显示
  341.         WriteData(digit[i]);     //将十位数字的字符常量写入LCD
  342.         WriteData(digit[j]);     //将个位数字的字符常量写入LCD
  343.         delaynms(50);            //延时1ms给硬件一点反应时间   
  344. }
  345. /*****************************************************
  346. 函数功能:显示年
  347. 入口参数:x
  348. ***************************************************/
  349. void DisplayYear(uchar x)
  350. {
  351.         uchar i,j;                             
  352.         i=x/10;                                          //取十位
  353.         j=x%10;                                          //取个位     
  354.         WriteAddress(0x01);       //写显示地址,将在第1行第7列开始显示
  355.         WriteData(digit[2]);
  356.         WriteData(digit[0]);
  357.         WriteData(digit[i]);      //将十位数字的字符常量写入LCD
  358.         WriteData(digit[j]);      //将个位数字的字符常量写入LCD
  359.         delaynms(50);             //延时1ms给硬件一点反应时间   
  360. }

  361. /*****************************************************
  362. 函数功能:液晶显示年月日以及时间
  363. ***************************************************/
  364. void displaytime()
  365. {
  366.   uchar second,minute,hour,day,month,year,week;      //分别储存苗、分、小时,日,月,年
  367.   uchar ReadValue;     //储存从1302读取的数据
  368.   WriteAddress(0x05);  //写年月分隔符的显示地址, 显示在第1行第9列
  369.   WriteData('-');      //将字符常量写入LCD
  370.   WriteAddress(0x08);  //写月日分隔符的显示地址, 显示在第1行第12列
  371.   WriteData('-');      //将字符常量写入LCD
  372.   WriteAddress(0x45);  //写小时与分钟分隔符的显示地址, 显示在第2行第6列
  373.   WriteData(':');      //将字符常量写入LCD
  374.   WriteAddress(0x48);  //写分钟与秒分隔符的显示地址, 显示在第2行第9列
  375.   WriteData(':');      //将字符常量写入LCD
  376.   while(1)
  377.     {

  378.           ReadValue = ReadSet1302(0x81);                                                           //从秒寄存器读数据
  379.       second    =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);        //将读出数据转化
  380.           DisplaySecond(second);                                                                  //显示秒
  381.           ReadValue = ReadSet1302(0x83);                                                           //从分寄存器读
  382.       minute    =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);         //将读出数据转化
  383.           DisplayMinute(minute);                                                                       //显示分
  384.       ReadValue = ReadSet1302(0x85);                                                          //从时寄存器读
  385.       hour      =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);         //将读出数据转化
  386.           DisplayHour(hour);                                                                     //显示小时
  387.       ReadValue = ReadSet1302(0x87);                                                          //从日寄存器读
  388.       day       =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);         //将读出数据转化
  389.           DisplayDay(day);                                                                        //显示日
  390.           ReadValue = ReadSet1302(0x8b);                                                          //从星期寄存器读
  391.           week      =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);         //将读出数据转化
  392.       DisplayWeek(week);                                                                                 //显示星期
  393.           ReadValue = ReadSet1302(0x89);                                                           //从月寄存器读
  394.       month     =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);         //将读出数据转化
  395.           DisplayMonth(month);                                                                    //显示月
  396.           ReadValue = ReadSet1302(0x8d);                                                          //从年寄存器读
  397.       year      =((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);         //将读出数据转化
  398.           DisplayYear(year);                                                                      //显示年
  399.          }
  400. }

  401. /*****************************************************
  402. 函数功能:主函数
  403. ***************************************************/
  404. void main(void)
  405. {

  406.   LcdInitiate();       //将液晶初始化
  407.   Init_DS1302();       //将1302初始化
  408.   IT0=1; //外部中断0
  409.   EX0=1;
  410.   IT1=1;
  411.   EX1=1;
  412.   EA=1;
  413.   displaytime();       //显示时间
  414. }
  415. /*****************************************************
  416. 函数功能:中断函数,实现时间的启停
  417. ***************************************************/
  418. void  int0()  interrupt  0   //外部中断0
  419. {
  420.    if(key1==0)  
  421.       {
  422.         stoptime(1);
  423.        }
  424.    else if(key2==0)  
  425.         {
  426.           stoptime(0);
  427.         }
  428. }

  429. /*****************************************************
  430. 函数功能:中断函数,实现时间参数的调整
  431. ***************************************************/
  432. void Setkey()  interrupt 2//外部中断1,调整时间
  433. {
  434. if(tiaoshi==0)
  435. {
  436. count=count+1;
  437. if(count==4)count=0;
  438. }


  439. else if(add==0)
  440. {
  441. switch(count)
  442. {  
  443. case 1:
  444. temp=ReadSet1302(0x85);
  445. temp=((temp&0x70)>>4)*10 + (temp&0x0F);
  446. temp=temp+1;
  447. if(temp>=24)temp=0;
  448. temp=(temp/10)<<4|temp%10;
  449. WriteSet1302(0x84,temp);
  450. break;
  451. case 2:
  452. temp=ReadSet1302(0x83);
  453. temp=((temp&0x70)>>4)*10 + (temp&0x0F);
  454. temp=temp+1;
  455. if(temp>=60)temp=0;
  456. temp=(temp/10)<<4|temp%10;
  457. WriteSet1302(0x82,temp);
  458. break;
  459. case 3:
  460. temp=ReadSet1302(0x81);
  461. temp=((temp&0x70)>>4)*10 + (temp&0x0F);
  462. temp=temp+1;
  463. if(temp>=0x60)temp=0;
  464. temp=(temp/10)<<4|temp%10;
  465. WriteSet1302(0x80,temp);
  466. }
  467. while (add==0);
  468. }
  469. else if(subtract==0)
  470. {
  471. switch(count)
  472. {  
  473. case 1:
  474. temp=ReadSet1302(0x85);
  475. temp=((temp&0x70)>>4)*10 + (temp&0x0F);
  476. temp=temp-1;
  477. if(temp<=0)temp=23;
  478. temp=(temp/10)<<4|temp%10;
  479. WriteSet1302(0x84,temp);
  480. break;
  481. case 2:
  482. temp=ReadSet1302(0x83);
  483. temp=((temp&0x70)>>4)*10 + (temp&0x0F);
  484. temp=temp-1;
  485. if(temp<=0)temp=59;
  486. temp=(temp/10)<<4|temp%10;
  487. WriteSet1302(0x82,temp);
  488. break;
  489. case 3:
  490. temp=ReadSet1302(0x81);
  491. temp=((temp&0x70)>>4)*10 + (temp&0x0F);
  492. temp=temp-1;
  493. if(temp<=0)temp=59;
  494. temp=(temp/10)<<4|temp%10;
  495. WriteSet1302(0x80,temp);
  496. }
  497. while (subtract==0);
  498. }
  499. }
复制代码



LCD数字时钟.zip

79.77 KB, 下载次数: 67, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:221692 发表于 2017-7-22 23:19 | 只看该作者
谢谢楼主的分享
回复

使用道具 举报

板凳
ID:339500 发表于 2018-5-28 10:20 | 只看该作者
十分感谢楼主的分享
回复

使用道具 举报

地板
ID:455959 发表于 2018-12-26 22:36 | 只看该作者
期末课设 这个很不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表