找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3951|回复: 3
收起左侧

单片机+LCD1602实物显示不正常,但是Proteus仿真成功

[复制链接]
ID:511955 发表于 2019-6-1 16:37 | 显示全部楼层 |阅读模式
LCD1602程序仿真正常,实物上显示不正常,程序在附件里面
TIM截图20190601163408.png IMG_20190601_163436.jpg

单片机源程序如下:
  1. #include <reg51.h>                            //调用含有51专用寄存器的头文件
  2. #include<intrins.h>
  3. #define uchar unsigned char            //用uchar代替unsigned char
  4. #define uint unsigned int                //用uint代替unsigned int

  5. #define yh 0x80       //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)
  6. #define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)

  7. char a,sec,min,hour,day,mouth,temp,n;                 //定义变量


  8. sbit rs=P3^0;                 //液晶指令/数据输入控制
  9. sbit en=P3^2;                 //液晶使能端

  10. sbit Data=P3^6;   //定义数据线
  11. uchar rec_dat[14];   //用于显示的接收数据数组

  12. sbit IO=P3^5;             //数据线
  13. sbit SCLK=P3^4;             //时钟线
  14. sbit RST=P3^3;             //使能

  15. sbit mode=P1^0;      //设置键
  16. sbit s1  =P1^1;      //加键
  17. sbit s2  =P1^2;      //减键
  18. sbit yes =P1^3;             //调整确认键

  19. sbit ACC0=ACC^0;         //累加器A低位
  20. sbit ACC7=ACC^7;         //累加器A高位

  21. uchar code tab1[]={"Tem:   Hum:  %"};       //时间显示的固定字符
  22. uchar code tab2[]={"  -     :  :  "};       //时间显示的固定字符

  23. /***********************延时子程序********************/
  24. void delay(uint xms)
  25. {
  26.         uint x,y;
  27.         for(x=xms;x>0;x--)
  28.          for(y=110;y>0;y--);
  29. }

  30. /****************液晶写入指令函数*******************/
  31. void write_1602com(uchar com)
  32. {
  33.         rs=0;                //数据/指令选择置为指令
  34.         P2=com;              //送入数据
  35.         delay(1);            //看时序图,可以得出,写程序需要时间
  36.         en=1;                //拉高使能端,为制造有效的下降沿做准备
  37.         delay(1);
  38.         en=0;                //en由高变低,产生下降沿,液晶执行命令
  39. }

  40. /********************液晶写入数据函数***************/
  41. void write_1602dat(uchar dat)
  42. {
  43.         rs=1;               //数据/指令选择置为数据
  44.         P2=dat;             //送入数据
  45.         delay(1);
  46.         en=1;               //en置高电平,为制造下降沿做准备
  47.         delay(1);
  48.         en=0;               //en由高变低,产生下降沿,液晶执行命令
  49. }

  50. /**************液晶初始化函数**********************/
  51. void lcd_init()
  52. {
  53.         write_1602com(0x38);         //设置液晶工作模式,
  54.         write_1602com(0x0c);         //开显示不显示光标
  55.         write_1602com(0x06);         //整屏不移动,光标自动右移
  56.         write_1602com(0x01);         //清显示

  57.         write_1602com(yh+1);         //日历显示固定符号从第一行第1个位置之后开始显示
  58.         for(a=0;a<14;a++)
  59.         {
  60.         write_1602dat(tab1[a]);      //向液晶屏写日历显示的固定符号部分
  61.         }
  62.         write_1602com(er+1);         //时间显示固定符号写入位置,从第2个位置后开始显示
  63.         for(a=0;a<14;a++)
  64.         {
  65.         write_1602dat(tab2[a]);      //写显示时间固定符号,两个冒号
  66.         }

  67. }

  68. /***************写数据********************/
  69. void write_byte(uchar dat)
  70. {
  71.         ACC=dat;
  72.         RST=1;
  73.         for(a=8;a>0;a--)
  74.         {
  75.          IO=ACC0;
  76.          SCLK=0;
  77.          SCLK=1;
  78.          ACC=ACC>>1;
  79.         }
  80. }

  81. /******************读数据********************/
  82. uchar read_byte()
  83. {
  84.         RST=1;
  85.         for(a=8;a>0;a--)
  86.         {
  87.          ACC7=IO;
  88.          SCLK=1;
  89.          SCLK=0;
  90.          ACC=ACC>>1;
  91.         }
  92.         return (ACC);
  93. }

  94. /*********向1302芯片写函数,指定写入地址,数据*********/
  95. void write_1302(uchar add,uchar dat)
  96. {
  97.         RST=0;
  98.         SCLK=0;
  99.         RST=1;
  100.         write_byte(add);
  101.         write_byte(dat);
  102.         SCLK=1;
  103.         RST=0;
  104. }

  105. /*********从1302读数据函数,指定读取数据来源地址*******/
  106. uchar read_1302(uchar add)
  107. {
  108.         uchar temp;
  109.         RST=0;
  110.         SCLK=0;
  111.         RST=1;
  112.         write_byte(add);
  113.         temp=read_byte();
  114.         SCLK=1;
  115.         RST=0;
  116.         return(temp);
  117. }

  118. /****************BCD码转十进制函数,输入BCD,返回十进制*******/
  119. uchar BCD(uchar m)
  120. {
  121. uchar x;
  122. x=m>>4;
  123. return(x=x*10+(m&=0x0f));
  124. }

  125. /********1302芯片初始化子函数(2019-05-19,16:36:00,week7)********/
  126. void ds1302_init()
  127. {
  128. RST=0;
  129. SCLK=0;
  130. write_1302(0x8e,0x00); //允许写,禁止写保护


  131. write_1302(0x8e,0x80); //打开写保护
  132. }

  133. /*****************************月日时分秒显示子函数*******************************/
  134. void write_time(uchar add,uchar dat)//向LCD写时分秒,有显示位置加、现示数据,两个参数
  135. {
  136.         uchar gw,sw;
  137.         gw=dat%10;                   //取得个位数字
  138.         sw=dat/10;                   //取得十位数字
  139.         write_1602com(er+add);       //er是头文件写的值0x80+0x40
  140.         write_1602dat(0x30+sw);      //数字+30得到该数字的LCD1602显示码
  141.         write_1602dat(0x30+gw);      //数字+30得到该数字的LCD1602显示码                               
  142. }






  143. /***********************按键处理函数**********************/
  144. void key()                             
  145. {
  146. if(mode==0)                           //第一次判断"模式"按键按下
  147. {
  148.   delay(5);                            //延时消抖
  149.   if(mode==0){TR0=0;n++;}while(!mode);}                                                          
  150.   if(n>5) {TR0=1;n=0;}                           //如果第四次按下mode键则继续计时,并且重新记录按下的按键次数

  151. /**********************调整+********************************/                
  152.   if(n!=0)                             //当mode按下以后。再按以下键才有效(按键次数不等于零)
  153. {
  154.   if(s1==0)                            //调整+键
  155. {
  156.         delay(30);
  157. if(s1==0)
  158. {
  159.   TR0=0;
  160.    switch(n)
  161. {
  162.         case 1:sec++;                          //设置键按动1次,调秒
  163.                    if(sec==60)        sec=0;                   //秒超过59,再加1,就归零               
  164.                     write_time(13,sec);           //令LCD在正确位置显示"加"设定好的秒数
  165.                    temp=(sec)/10*16+(sec)%10;      //十进制转换成DS1302要求的DCB码
  166.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  167.                    write_1302(0x80,temp);          //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码
  168.                    write_1302(0x8e,0x80);          //打开写保护
  169.                    write_1602com(er+14);         //因为设置液晶的模式是写入数据后,指针自动+1,需要光标回位
  170.                    break;
  171.         case 2:min++;                                                   //设置键按动2次,调分
  172.                    if(min==60)        min=0;                           //分数据加到60时自动变成0
  173.                    write_time(10,min);           //令LCD在正确位置显示"加"设定好的分数据
  174.                    temp=(min)/10*16+(min)%10;      //十进制转换成DS1302要求的DCB码
  175.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  176.                    write_1302(0x82,temp);          //向DS1302内写分寄存器82H写入调整后的分数据BCD码
  177.                    write_1302(0x8e,0x80);          //打开写保护
  178.                    write_1602com(er+11);
  179.                    break;
  180.         case 3:hour++;
  181.                    if(hour==24) hour=0;                           //时数据加到24时自动变成0
  182.                    write_time(7,hour);             //令LCD在正确的位置显示"加"设定好的小时数据
  183.                    temp=(hour)/10*16+(hour)%10;    //十进制转换成DS1302要求的DCB码
  184.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  185.                    write_1302(0x84,temp);          //向DS1302内写小时寄存器84H写入调整后的小时数据BCD码
  186.                    write_1302(0x8e,0x80);          //打开写保护
  187.                write_1602com(er+8);
  188.                       break;

  189.         case 4:day++;                                                   //设置键按动5次,调天
  190.                    if(day==32)        day=1;                           //天数据加到32时自动变成1
  191.                      write_time(4,day);             //令LCD在正确的位置显示"加"设定好的日期数据
  192.                    temp=(day)/10*16+(day)%10;      //十进制转换成DS1302要求的DCB码
  193.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  194.                    write_1302(0x86,temp);          //向DS1302内写日期寄存器86H写入调整后的日期数据BCD码
  195.                    write_1302(0x8e,0x80);          //打开写保护
  196.                    write_1602com(er+5);
  197.                         break;
  198.         case 5:mouth++;                                                   //设置键按动6次,调月
  199.                    if(mouth>=13)        mouth=1;           //月数据加到12时自动变成1
  200.                    write_time(1,mouth);           //令LCD在正确的位置显示"加"设定好的月份数据
  201.                    temp=(mouth)/10*16+(mouth)%10;  //十进制转换成DS1302要求的DCB码
  202.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  203.                    write_1302(0x88,temp);          //向DS1302内写月份寄存器88H写入调整后的月份数据BCD码
  204.                    write_1302(0x8e,0x80);          //打开写保护
  205.                    write_1602com(er+2);
  206.                    break;

  207. }
  208.   }
  209.   while(!s1);
  210.    }
  211. }

  212. /**********************调整-********************************/                
  213.   if(n!=0)           //当mode按下以后,再按以下键才有效
  214. {
  215.   if(s2==0)          //调整-键
  216. {
  217.         delay(30);
  218. if(s2==0)
  219. {
  220.    TR0=0;                         //关闭中断
  221.    switch(n)
  222. {
  223.         case 1:sec--;                         //设置键按动1次,调秒
  224.                    if(sec==-1)        sec=59;                  //秒数据减到-1时自动变成59       
  225.                     write_time(13,sec);          //令LCD在正确位置显示"加"设定好的秒数
  226.                    temp=(sec)/10*16+(sec)%10;     //十进制转换成DS1302要求的DCB码
  227.                    write_1302(0x8e,0x00);         //允许写,禁止写保护
  228.                    write_1302(0x80,temp);         //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码
  229.                    write_1302(0x8e,0x80);         //打开写保护
  230.                    write_1602com(er+14);                  //因为设置液晶的模式是写入数据后,指针自动+1,需要光标回位
  231.                         break;
  232.         case 2:min--;
  233.                    if(min==-1)        min=59;                          //分数据减到-1时自动变成59
  234.                    write_time(10,min);          //令LCD在正确位置显示"加"设定好的分数据
  235.                    temp=(min)/10*16+(min)%10;     //十进制转换成DS1302要求的DCB码
  236.                    write_1302(0x8e,0x00);         //允许写,禁止写保护
  237.                    write_1302(0x82,temp);         //向DS1302内写分寄存器82H写入调整后的分数据BCD码
  238.                    write_1302(0x8e,0x80);         //打开写保护
  239.                    write_1602com(er+11);
  240.                    break;
  241.         case 3:hour--;
  242.                    if(hour==-1) hour=23;                   //时数据减到-1时自动变成23
  243.                    write_time(7,hour);             //令LCD在正确的位置显示"加"设定好的小时数据
  244.                    temp=(hour)/10*16+(hour)%10;    //十进制转换成DS1302要求的DCB码
  245.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  246.                    write_1302(0x84,temp);          //向DS1302内写小时寄存器84H写入调整后的小时数据BCD码
  247.                    write_1302(0x8e,0x80);          //打开写保护
  248.                write_1602com(er+8);           
  249.                       break;

  250.         case 4:day--;
  251.                    if(day==-1)        day=31;                           //天数据减到-1时自动变成31
  252.                      write_time(4,day);             //令LCD在正确的位置显示"加"设定好的日期数据
  253.                    temp=(day)/10*16+(day)%10;      //十进制转换成DS1302要求的DCB码
  254.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  255.                    write_1302(0x86,temp);          //向DS1302内写日期寄存器86H写入调整后的日期数据BCD码
  256.                    write_1302(0x8e,0x80);          //打开写保护
  257.                    write_1602com(er+5);
  258.                    break;
  259.         case 5:mouth--;
  260.                    if(mouth==-1)        mouth=12;           //月数据减到-1时自动变成12
  261.                    write_time(1,mouth);           
  262.                    temp=(mouth)/10*16+(mouth)%10;  //十进制转换成DS1302要求的DCB码
  263.                    write_1302(0x8e,0x00);          //允许写,禁止写保护
  264.                    write_1302(0x88,temp);          //向DS1302内写月份寄存器88H写入调整后的月份数据BCD码
  265.                    write_1302(0x8e,0x80);          //打开写保护
  266.                    write_1602com(er+2);         
  267.                    break;

  268. }
  269.   }
  270.   while(!s2);                                                           //按键松开检测
  271.    }
  272. }

  273. if(n!=0)
  274. {
  275.   if(yes==0)                        //调整值确认键按下,保存设置的参数,直接退出调整状态,进入走时。
  276. {
  277.         delay(30);
  278.   if(yes==0)
  279.   {
  280.         n=0,
  281.         write_1602com(0x0c);        //设置光标不闪烁
  282.         TR0=1;                      //打开定时器
  283.         temp=(sec)/10*16+(sec)%10;
  284.         write_1302(0x8e,0x00);
  285.         write_1302(0x80,0x00|temp); //秒数据写入DS1302
  286.         write_1302(0x8e,0x80);                
  287.   }
  288.   while(!yes);                                   //松开按键检测
  289. }
  290. }

  291. }

  292. //*********************DHT11************************
  293. void DHT11_delay_us(uchar n)
  294. {
  295.     while(--n);
  296. }

  297. void DHT11_delay_ms(uint z)
  298. {
  299.    uint i,j;
  300.    for(i=z;i>0;i--)
  301.       for(j=110;j>0;j--);
  302. }

  303. void DHT11_start()
  304. {
  305.    Data=1;
  306.    DHT11_delay_us(2);
  307.    Data=0;
  308.    DHT11_delay_ms(30);   //延时18ms以上
  309.    Data=1;
  310.    DHT11_delay_us(30);
  311. }

  312. uchar DHT11_rec_byte()      //接收一个字节
  313. {
  314.    uchar i,dat=0;
  315.   for(i=0;i<8;i++)    //从高到低依次接收8位数据
  316.    {         
  317.       while(!Data);   ////等待50us低电平过去
  318.       DHT11_delay_us(8);     //延时60us,如果还为高则数据为1,否则为0
  319.       dat<<=1;           //移位使正确接收8位数据,数据为0时直接移位
  320.       if(Data==1)    //数据为1时,使dat加1来接收数据1
  321.          dat+=1;
  322.       while(Data);  //等待数据线拉低   
  323.     }  
  324.     return dat;
  325. }

  326. void DHT11_receive()      //接收40位的数据
  327. {
  328.     uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise;
  329.     DHT11_start();
  330.     if(Data==0)
  331.     {
  332.         while(Data==0);   //等待拉高     
  333.         DHT11_delay_us(40);  //拉高后延时80us
  334.         R_H=DHT11_rec_byte();    //接收湿度高八位  
  335.         R_L=DHT11_rec_byte();    //接收湿度低八位  
  336.         T_H=DHT11_rec_byte();    //接收温度高八位  
  337.         T_L=DHT11_rec_byte();    //接收温度低八位
  338.         revise=DHT11_rec_byte(); //接收校正位

  339.         DHT11_delay_us(25);    //结束

  340.         if((R_H+R_L+T_H+T_L)==revise)      //校正
  341.         {
  342.             RH=R_H;
  343.             RL=R_L;
  344.             TH=T_H;
  345.             TL=T_L;
  346.         }
  347.         /*数据处理,方便显示*/
  348.         rec_dat[0]='T';
  349.         rec_dat[1]='e';
  350.         rec_dat[2]='m';
  351.         rec_dat[3]=':';
  352.         rec_dat[4]='0'+(TH/10);
  353.         rec_dat[5]='0'+(TH%10);
  354.         rec_dat[6]=' ';
  355.         rec_dat[7]='H';
  356.         rec_dat[8]='u';
  357.                 rec_dat[9]='m';
  358.         rec_dat[10]=':';
  359.         rec_dat[11]='0'+(RH/10);
  360.         rec_dat[12]='0'+(RH%10);
  361.         rec_dat[13]='%';


  362.     }
  363. }
  364. /****************************主函数**********************/
  365. void main()
  366. {
  367.         uchar i;
  368.     TMOD=0x11;       //指定定时/计数器的工作方式为3
  369.         TH0=0;           //定时器T0的高四位=0
  370.         TL0=0;           //定时器T0的低四位=0
  371.         EA=1;            //开总中断
  372.         ET0=1;           //允许T0中断
  373.         TR0=1;           //开启中断,启动定时器
  374.     lcd_init();      //调用液晶屏初始化子函数
  375.         ds1302_init();   //调用DS1302时钟的初始化子函数
  376.                    DHT11_delay_ms(100);    //DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令
  377.        DHT11_receive();
  378.        write_1602com(yh+1);   //从lcd1602第一行第一个位置开始显示
  379.        for(i=0;i<14;i++)
  380.        write_1602dat(rec_dat[i]);   //显示数据
  381.        
  382.   while(1)
  383. {
  384.          key();  
  385. }

  386. }

  387. void timer0() interrupt 1  //取得并显示日历和时间
  388. {          
  389. /***************************读取秒时分周日月年七个数据***********************/
  390.   sec  = BCD(read_1302(0x81));
  391.   min  = BCD(read_1302(0x83));
  392.   hour = BCD(read_1302(0x85));
  393.   day  = BCD(read_1302(0x87));
  394.   mouth= BCD(read_1302(0x89));


  395. /**************************显示温度、秒、时、分数据***************************/
  396.   write_time(13,sec);     //秒,从第二行第8个字后开始显示(调用时分秒显示子函数)
  397.   write_time(10,min);     //分,从第二行第5个字符后开始显示
  398.   write_time(7,hour);    //小时,从第二行第2个字符后开始显示
  399.   write_time(4,day);    //日期,从第二行第9个字符后开始显示
  400.   write_time(1,mouth);  //月份,从第二行第6个字符后开始显示

  401. }
复制代码

1302时钟.zip

4.24 KB, 下载次数: 16

回复

使用道具 举报

ID:552570 发表于 2019-6-1 17:20 | 显示全部楼层
线连接的都对吗?
回复

使用道具 举报

ID:96682 发表于 2019-6-1 17:45 | 显示全部楼层
源程序与仿真图有出入,这仿真图多处电路有误如用于实物上肯定不妥
回复

使用道具 举报

ID:511890 发表于 2019-6-2 02:37 | 显示全部楼层
lcd_init()中的 write_1602com(0x01);  后面加个延时。然后显示要么放到while中,要么放到一个中断中。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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