找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3023|回复: 9
收起左侧

关于单片机+LCD602频闪问题求分析

[复制链接]
ID:531175 发表于 2019-5-17 00:39 | 显示全部楼层 |阅读模式
同志们,我遇到了一些困难,我在做掉电走时的时钟,一块LCD1602,一块ds1302,当我烧进程序后,lcd可以实现掉电走时,但是会频闪,导致lcd显示的模糊,老师说是程序问题,不要一直判忙,不断清屏,说只要一秒传一次数据,并且lcd不清屏,只让数增加即可,但我还是有点不明白,希望大家可以指点迷津,下面的程序是lcd.c的,大家可以帮我改改吗

单片机源程序如下:
#include <reg52.h>
#define LCD1602_DB  P0
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_E  = P2^7;


void LcdWaitReady()
{
    unsigned char sta;
   
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
    delay(500);
        LCD1602_E = 1;
        sta = LCD1602_DB;
        LCD1602_E = 0;
   } while (sta & 0x80); //我觉得这个do while 可能要改
}

void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}

void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
   
    if (y == 0)  
        addr = 0x00 + x;
    else
        addr = 0x40 + x;  
    LcdWriteCmd(addr | 0x80);
}
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
    LcdSetCursor(x, y);
    while (*str != '\0')
    {
        LcdWriteDat(*str++);
    }
}
void InitLcd1602()
{
    LcdWriteCmd(0x38);  
    LcdWriteCmd(0x0C);  
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}



回复

使用道具 举报

ID:155507 发表于 2019-5-17 06:12 | 显示全部楼层
主程序呢?
你这个程序不完整,没法给你看是哪里出问题了!
回复

使用道具 举报

ID:149451 发表于 2019-5-17 06:50 | 显示全部楼层
把main.c放上来看看,如果没其它功能仅是时钟,建议不去判忙,适当引进延时,把程序处理”干净”
回复

使用道具 举报

ID:123289 发表于 2019-5-17 08:46 | 显示全部楼层
做个掉电标记,掉电后只走时,不做显示不就OK了吗。
回复

使用道具 举报

ID:7485 发表于 2019-5-17 09:18 | 显示全部楼层
看不见你的主函数。
回复

使用道具 举报

ID:531175 发表于 2019-5-17 13:53 | 显示全部楼层
这是main.c函数,我把1302函数写到了里面,大家帮我看看吧,非常感谢你们



  1. #include <reg52.h>

  2. sbit DS1302_CE = P1^7;
  3. sbit DS1302_CK = P3^5;
  4. sbit DS1302_IO = P3^4;

  5. bit flag200ms = 0;       //200ms定时标志
  6. unsigned char T0RH = 0;  //T0重载值的高字节
  7. unsigned char T0RL = 0;  //T0重载的低字节

  8. void ConfigTimer0(unsigned int ms);
  9. void InitDS1302();
  10. void DS1302BurstRead(unsigned char *dat);
  11. extern void InitLcd1602();
  12. extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

  13. void main()
  14. {
  15.     unsigned char psec=0xAA;//秒备份,初值AA确保首次读取时间后会刷新显示
  16.     unsigned char time[8];    //当前时间数组
  17.     unsigned char str[12];    //字符串转换缓冲区

  18.     EA = 1;           //开总中断
  19.     ConfigTimer0(1);  //T0定时1ms
  20.     InitDS1302();     //初始化实时时钟
  21.     InitLcd1602();    //初始化液晶
  22.    
  23.     while (1)
  24.     {
  25.         if (flag200ms)  //每200ms读取依次时间
  26.         {
  27.             flag200ms = 0;
  28.             DS1302BurstRead(time); //
  29. 读取DS1302当前时间
  30.             if (psec != time[0])   //检测到时间有变化时刷新显示
  31.             {
  32.                 str[0] = '2';  
  33.                 str[1] = '0';
  34.                 str[2] = (time[6] >> 4) + '0';  
  35.                 str[3] = (time[6]&0x0F) + '0';  
  36.                 str[4] = '-';
  37.                 str[5] = (time[4] >> 4) + '0';  
  38.                 str[6] = (time[4]&0x0F) + '0';
  39.                 str[7] = '-';
  40.                 str[8] = (time[3] >> 4) + '0';  
  41.                 str[9] = (time[3]&0x0F) + '0';
  42.                 str[10] = '\0';
  43.                 LcdShowStr(0, 0, str);
  44.                 //显示到液晶的第一行

  45.                 str[0] = (time[5]&0x0F) + '0';  
  46.                 str[1] = '\0';
  47.                 LcdShowStr(11, 0, "week");
  48.                 LcdShowStr(15, 0, str); //显示到液晶的第一行
  49.          
  50.                 str[0] = (time[2] >> 4) + '0';  
  51.                 str[1] = (time[2]&0x0F) + '0';
  52.                 str[2] = ':';
  53.                 str[3] = (time[1] >> 4) + '0';  
  54.                 str[4] = (time[1]&0x0F) + '0';
  55.                 str[5] = ':';
  56.                 str[6] = (time[0] >> 4) + '0';  
  57.                 str[7] = (time[0]&0x0F) + '0';
  58.                 str[8] = '\0';
  59.                 LcdShowStr(4, 1, str);  //显示到第二行
  60.                
  61.                 psec = time[0];  //用当前值更新上次秒数
  62.             }
  63.         }
  64.     }
  65. }

  66. /* 发送一个字节到DS1302通信总线上 */
  67. void DS1302ByteWrite(unsigned char dat)
  68. {
  69.     unsigned char mask;
  70.    
  71.     for (mask=0x01; mask!=0; mask<<=1)  //低位在前,逐位输出
  72.     {
  73.         if ((mask&dat) != 0) //首先输出该位数据
  74.             DS1302_IO = 1;
  75.         else
  76.             DS1302_IO = 0;
  77.         DS1302_CK = 1;       //拉高时钟
  78.         DS1302_CK = 0;       //拉低时钟,
  79.     }
  80.     DS1302_IO = 1;           //确保释放IO
  81. }
  82. /* 由DS1302读取一个字节*/
  83. unsigned char DS1302ByteRead()
  84. {
  85.     unsigned char mask;
  86.     unsigned char dat = 0;
  87.    
  88.     for (mask=0x01; mask!=0; mask<<=1) //低位在前,逐位输出
  89.     {
  90.         if (DS1302_IO != 0)  //读取IO引脚,并设置对应位
  91.         {
  92.             dat |= mask;
  93.         }
  94.         DS1302_CK = 1;       //拉高时钟
  95.         DS1302_CK = 0;       //拉低时钟,完成一个位
  96.     }
  97.     return dat;      
  98. }
  99. /* reg-寄存器地址,dat-待写入字节 */
  100. void DS1302SingleWrite(unsigned char reg, unsigned char dat)
  101. {
  102.     DS1302_CE = 1;                  
  103.     DS1302ByteWrite((reg<<1)|0x80);  
  104.     DS1302ByteWrite(dat);      
  105.     DS1302_CE = 0;           
  106. }
  107. /* reg-寄存器地址,返回值-读到的字节 */
  108. unsigned char DS1302SingleRead(unsigned char reg)
  109. {
  110.     unsigned char dat;
  111.    
  112.     DS1302_CE = 1;  
  113.     DS1302ByteWrite((reg<<1)|0x81);  
  114.     dat = DS1302ByteRead();   
  115.     DS1302_CE = 0;   
  116.     return dat;
  117. }
  118. void  DS1302BurstWrite(unsigned char *dat)
  119. {
  120.         unsigned char i;

  121.         DS1302_CE = 1;
  122.         DS1302ByteWrite(0xBE);
  123.         for(i=0; i<8; i++)
  124.         {
  125.                 DS1302ByteWrite(dat[i]);
  126.         }
  127.         DS1302_CE = 0;
  128. }

  129. void  DS1302BurstRead(unsigned char *dat)
  130. {
  131.         unsigned char i;

  132.         DS1302_CE = 1;
  133.         DS1302ByteWrite(0xBF);
  134.         for(i=0; i<8; i++)
  135.         {
  136.                 dat[i] = DS1302ByteRead();
  137.         }
  138.         DS1302_CE = 0;
  139. }
  140. /* DS1302初始化,掉电则重新设置初试时间*/
  141. void InitDS1302()
  142. {
  143.     unsigned char dat;
  144.     unsigned char code InitTime[] = {0x00,0x30,0x00, 0x16, 0x05, 0x04, 0x19};        //2019年5月16日 星期四12:30:00
  145.    
  146.     DS1302_CE = 0;
  147.     DS1302_CK = 0;
  148.     dat = DS1302SingleRead(0);
  149.     if ((dat & 0x80) != 0)      //秒寄存器最高位CH值判断DS1302是否已停止
  150.     {
  151.         DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据
  152.         DS1302BurstWrite(InitTime);  //设置DS1302为默认的初始时间
  153.     }
  154. }
  155. /* 配置并启动T0,ms-T0定时时间 */
  156. void ConfigTimer0(unsigned int ms)
  157. {
  158.     unsigned long tmp;  //临时变量
  159.    
  160.     tmp = 11059200 / 12;
  161.     tmp = (tmp * ms) /1000;
  162.     tmp = 65536 - tmp;
  163.     tmp = tmp + 12;           //补偿中断响应延时造成的误差
  164.     T0RH = (unsigned char)(tmp>>8);
  165.     T0RL = (unsigned char)tmp;
  166.     TMOD &= 0xF0;   //清零T0的控制位
  167.     TMOD |= 0x01;   
  168.     TH0 = T0RH;
  169.     TL0 = T0RL;
  170.     ET0 = 1;
  171.     TR0 = 1;   
  172. }
  173. /* T0中断服务函数,200ms定时*/
  174. void InterruptTimer0() interrupt 1
  175. {
  176.     static unsigned char tmr200ms = 0;
  177.    
  178.     TH0 = T0RH;  //重新加载重载值
  179.     TL0 = T0RL;
  180.     tmr200ms++;
  181.     if (tmr200ms >= 200)  //定时200ms
  182.     {
  183.         tmr200ms = 0;
  184.         flag200ms = 1;
  185.     }
  186. }
复制代码
回复

使用道具 举报

ID:531175 发表于 2019-5-18 13:57 | 显示全部楼层
w1179benp 发表于 2019-5-17 06:50
把main.c放上来看看,如果没其它功能仅是时钟,建议不去判忙,适当引进延时,把程序处理”干净”

您好,我把主函数放上来了,您帮我看看吧,非常感谢
回复

使用道具 举报

ID:531175 发表于 2019-5-18 13:58 | 显示全部楼层
angmall 发表于 2019-5-17 06:12
主程序呢?
你这个程序不完整,没法给你看是哪里出问题了!

您好,我把主函数放上来了,您帮我看看吧,非常感谢
回复

使用道具 举报

ID:213173 发表于 2019-5-18 18:52 | 显示全部楼层
迷迷惘惘 发表于 2019-5-17 13:53
这是main.c函数,我把1302函数写到了里面,大家帮我看看吧,非常感谢你们

楼主这个程序不完整,缺少按键调整程序。把一些抄写错误纠正后通过编译,仿真时没有发现楼主所言的频闪问题。 无标题.jpg


  1. #include <reg52.h>
  2. #define LCD1602_DB  P0
  3. sbit LCD1602_RS = P2^6;
  4. sbit LCD1602_RW = P2^5;
  5. sbit LCD1602_E  = P2^7;

  6. sbit DS1302_CE = P1^7;
  7. sbit DS1302_CK = P3^5;
  8. sbit DS1302_IO = P3^4;

  9. bit flag200ms = 0;       //200ms定时标志
  10. unsigned char T0RH = 0;  //T0重载值的高字节
  11. unsigned char T0RL = 0;  //T0重载的低字节

  12. void ConfigTimer0(unsigned int ms);
  13. void InitDS1302();
  14. void DS1302BurstRead(unsigned char *dat);
  15. void InitLcd1602();
  16. void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

  17. void delay(unsigned int t)
  18. {
  19.         while(--t);
  20. }

  21. void LcdWaitReady()
  22. {
  23.     unsigned char sta;
  24.    
  25.     LCD1602_DB = 0xFF;
  26.     LCD1602_RS = 0;
  27.     LCD1602_RW = 1;
  28.     do {
  29.     delay(500);
  30.         LCD1602_E = 1;
  31.         sta = LCD1602_DB;
  32.         LCD1602_E = 0;
  33.    } while (sta & 0x80); //我觉得这个do while 可能要改
  34. }

  35. void LcdWriteCmd(unsigned char cmd)
  36. {
  37.     LcdWaitReady();
  38.     LCD1602_RS = 0;
  39.     LCD1602_RW = 0;
  40.     LCD1602_DB = cmd;
  41.     LCD1602_E  = 1;
  42.     LCD1602_E  = 0;
  43. }

  44. void LcdWriteDat(unsigned char dat)
  45. {
  46.     LcdWaitReady();
  47.     LCD1602_RS = 1;
  48.     LCD1602_RW = 0;
  49.     LCD1602_DB = dat;
  50.     LCD1602_E  = 1;
  51.     LCD1602_E  = 0;
  52. }
  53. void LcdSetCursor(unsigned char x, unsigned char y)
  54. {
  55.     unsigned char addr;
  56.    
  57.     if (y == 0)  
  58.         addr = 0x00 + x;
  59.     else
  60.         addr = 0x40 + x;  
  61.     LcdWriteCmd(addr | 0x80);
  62. }
  63. void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
  64. {
  65.     LcdSetCursor(x, y);
  66.     while (*str != '\0')
  67.     {
  68.         LcdWriteDat(*str++);
  69.     }
  70. }
  71. void InitLcd1602()
  72. {
  73.     LcdWriteCmd(0x38);  
  74.     LcdWriteCmd(0x0C);  
  75.     LcdWriteCmd(0x06);  //文字不动,地址自动+1
  76.     LcdWriteCmd(0x01);  //清屏
  77. }


  78. void main()
  79. {
  80.         unsigned char psec=0xAA;//秒备份,初值AA确保首次读取时间后会刷新显示
  81.         unsigned char time[8];    //当前时间数组
  82.         unsigned char str[12];    //字符串转换缓冲区

  83.     EA = 1;           //开总中断
  84.     ConfigTimer0(1);  //T0定时1ms
  85.     InitDS1302();     //初始化实时时钟
  86.     InitLcd1602();    //初始化液晶
  87.    
  88.     while (1)
  89.     {
  90.         if (flag200ms)  //每200ms读取依次时间
  91.         {
  92.             flag200ms = 0;
  93.             DS1302BurstRead(time); //读取DS1302当前时间
  94.             if (psec != time[0])   //检测到时间有变化时刷新显示
  95.             {
  96.                 str[0] = '2';  
  97.                 str[1] = '0';
  98.                 str[2] = (time[6] >> 4) + '0';  
  99.                 str[3] = (time[6]&0x0F) + '0';  
  100.                 str[4] = '-';
  101.                 str[5] = (time[4] >> 4) + '0';  
  102.                 str[6] = (time[4]&0x0F) + '0';
  103.                 str[7] = '-';
  104.                 str[8] = (time[3] >> 4) + '0';  
  105.                 str[9] = (time[3]&0x0F) + '0';
  106.                 str[10] = '\0';
  107.                 LcdShowStr(0, 0, str);
  108.                 //显示到液晶的第一行

  109.                 str[0] = (time[5]&0x0F) + '0';  
  110.                 str[1] = '\0';
  111.                 LcdShowStr(11, 0, "week");
  112.                 LcdShowStr(15, 0, str); //显示到液晶的第一行
  113.          
  114.                 str[0] = (time[2] >> 4) + '0';  
  115.                 str[1] = (time[2]&0x0F) + '0';
  116.                 str[2] = ':';
  117.                 str[3] = (time[1] >> 4) + '0';  
  118.                 str[4] = (time[1]&0x0F) + '0';
  119.                 str[5] = ':';
  120.                 str[6] = (time[0] >> 4) + '0';  
  121.                 str[7] = (time[0]&0x0F) + '0';
  122.                 str[8] = '\0';
  123.                 LcdShowStr(4, 1, str);  //显示到第二行
  124.                
  125.                 psec = time[0];  //用当前值更新上次秒数
  126.             }
  127.         }
  128.     }
  129. }

  130. /* 发送一个字节到DS1302通信总线上 */
  131. void DS1302ByteWrite(unsigned char dat)
  132. {
  133.     unsigned char mask;
  134.    
  135.     for (mask=0x01; mask!=0; mask<<=1)  //低位在前,逐位输出
  136.     {
  137.         if ((mask&dat) != 0) //首先输出该位数据
  138.             DS1302_IO = 1;
  139.         else
  140.             DS1302_IO = 0;
  141.         DS1302_CK = 1;       //拉高时钟
  142.         DS1302_CK = 0;       //拉低时钟,
  143.     }
  144.     DS1302_IO = 1;           //确保释放IO
  145. }
  146. /* 由DS1302读取一个字节*/
  147. unsigned char DS1302ByteRead()
  148. {
  149.     unsigned char mask;
  150.     unsigned char dat = 0;
  151.    
  152.     for (mask=0x01; mask!=0; mask<<=1) //低位在前,逐位输出
  153.     {
  154.         if (DS1302_IO != 0)  //读取IO引脚,并设置对应位
  155.         {
  156.             dat |= mask;
  157.         }
  158.         DS1302_CK = 1;       //拉高时钟
  159.         DS1302_CK = 0;       //拉低时钟,完成一个位
  160.     }
  161.     return dat;      
  162. }
  163. /* reg-寄存器地址,dat-待写入字节 */
  164. void DS1302SingleWrite(unsigned char reg, unsigned char dat)
  165. {
  166.     DS1302_CE = 1;                  
  167.     DS1302ByteWrite((reg<<1)|0x80);  
  168.     DS1302ByteWrite(dat);      
  169.     DS1302_CE = 0;           
  170. }
  171. /* reg-寄存器地址,返回值-读到的字节 */
  172. unsigned char DS1302SingleRead(unsigned char reg)
  173. {
  174.     unsigned char dat;
  175.    
  176.     DS1302_CE = 1;  
  177.     DS1302ByteWrite((reg<<1)|0x81);  
  178.     dat = DS1302ByteRead();   
  179.     DS1302_CE = 0;   
  180.     return dat;
  181. }
  182. void  DS1302BurstWrite(unsigned char *dat)
  183. {
  184.         unsigned char i;

  185.         DS1302_CE = 1;
  186.         DS1302ByteWrite(0xBE);
  187.         for(i=0; i<8; i++)
  188.         {
  189.                 DS1302ByteWrite(dat[i]);
  190.         }
  191.         DS1302_CE = 0;
  192. }

  193. void  DS1302BurstRead(unsigned char *dat)
  194. {
  195.         unsigned char i;

  196.         DS1302_CE = 1;
  197.         DS1302ByteWrite(0xBF);
  198.         for(i=0; i<8; i++)
  199.         {
  200.                 dat[i] = DS1302ByteRead();
  201.         }
  202.         DS1302_CE = 0;
  203. }
  204. /* DS1302初始化,掉电则重新设置初试时间*/
  205. void InitDS1302()
  206. {
  207.     unsigned char dat;
  208.     unsigned char code InitTime[] = {0x00,0x30,0x00, 0x16, 0x05, 0x04, 0x19};        //2019年5月16日 星期四12:30:00
  209.    
  210.     DS1302_CE = 0;
  211.     DS1302_CK = 0;
  212.     dat = DS1302SingleRead(0);
  213.     if ((dat & 0x80) != 0)      //秒寄存器最高位CH值判断DS1302是否已停止
  214.     {
  215.         DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据
  216.         DS1302BurstWrite(InitTime);  //设置DS1302为默认的初始时间
  217.     }
  218. }
  219. /* 配置并启动T0,ms-T0定时时间 */
  220. void ConfigTimer0(unsigned int ms)
  221. {
  222.     unsigned long tmp;  //临时变量
  223.    
  224.     tmp = 11059200 / 12;
  225.     tmp = (tmp * ms) /1000;
  226.     tmp = 65536 - tmp;
  227.     tmp = tmp + 12;           //补偿中断响应延时造成的误差
  228.     T0RH = (unsigned char)(tmp>>8);
  229.     T0RL = (unsigned char)tmp;
  230.     TMOD &= 0xF0;   //清零T0的控制位
  231.     TMOD |= 0x01;   
  232.     TH0 = T0RH;
  233.     TL0 = T0RL;
  234.     ET0 = 1;
  235.     TR0 = 1;   
  236. }
  237. /* T0中断服务函数,200ms定时*/
  238. void InterruptTimer0() interrupt 1
  239. {
  240.     static unsigned char tmr200ms = 0;
  241.    
  242.     TH0 = T0RH;  //重新加载重载值
  243.     TL0 = T0RL;
  244.     tmr200ms++;
  245.     if (tmr200ms >= 200)  //定时200ms
  246.     {
  247.         tmr200ms = 0;
  248.         flag200ms = 1;
  249.     }
  250. }
复制代码



回复

使用道具 举报

ID:149451 发表于 2019-5-18 23:21 | 显示全部楼层
仿真了下,挺好的,不闪呀。掉电闪频检查下硬件、电源
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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