求助各位大侠,LCD1602显示数值从100变到99时显示990

2020-01-22 12:11发布

mcu: STC89C52
晶振:11.0592M
显示的是AD7887转换后的AD值(2进制)
问题如下:
1、中断函数里添加 LCD1602_Clear();函数时,显示ad_time值正常,但显示temp1,temp2值却是一闪一闪的,数值是正确的,100变到99时正常
2、中断函数里注释掉 LCD1602_Clear();函数时,显示ad_time值,temp1,temp2值均会出现最后一位或后几位的0一直存在的现象

麻烦各位帮忙看下,程序如下:

  1. #include"Hardconfig.h"



  2. /**************************************************************************
  3. * 名        称:                void LCD1602_Busy()                                 
  4. * 功        能:                液晶屏忙碌检查                                                  
  5. * 说        明:                                                                  
  6. * 输        入:                                                                        
  7. * 输        出:                返回初始化的结果(0:不忙碌   1:忙碌)                          
  8. **************************************************************************/
  9. void LCD1602_Busy()
  10. {
  11.         do
  12.         {
  13.                 LCD_DATAPort=0xff;
  14.                 LCD_RS=0;
  15.                 LCD_RW=1;
  16.                 LCD_EN=0;       
  17.                 LCD_EN=1;
  18.         }
  19.         while(BUSY);
  20.         LCD_EN=0;               
  21. }


  22. /**************************************************************************
  23. * 名        称:                void LCD1602_Write_cmd(uchar cmd)                                 
  24. * 功        能:                向LCD1602写指令                                                  
  25. * 说        明:                                                                  
  26. * 输        入:     cmd   要写入的指令值                                                                  
  27. * 输        出:                                          
  28. **************************************************************************/
  29. void LCD1602_Write_cmd(uchar cmd)
  30. {
  31.         LCD1602_Busy();
  32.         LCD_EN=0;
  33.         LCD_RS=0;
  34.         LCD_RW=0;
  35.         LCD_DATAPort=cmd;
  36.         _nop_();
  37.     _nop_();
  38.         LCD_EN=1;
  39.         _nop_();
  40.     _nop_();
  41.         LCD_EN=0;                       
  42. }


  43. /**************************************************************************
  44. * 名        称:                void LCD1602_Write_dat(uchar dat)                                 
  45. * 功        能:                向LCD1602写数据                                                  
  46. * 说        明:                                                                  
  47. * 输        入:     dat   要写入的数据值                                                                  
  48. * 输        出:                                          
  49. **************************************************************************/
  50. void LCD1602_Write_dat(uchar dat)
  51. {
  52.         LCD1602_Busy();
  53.         LCD_EN=0;
  54.         LCD_RS=1;
  55.         LCD_RW=0;
  56.         LCD_DATAPort=dat;
  57.         _nop_();
  58.     _nop_();
  59.         LCD_EN=1;
  60.         _nop_();
  61.     _nop_();
  62.         LCD_EN=0;                       
  63. }


  64. /**************************************************************************
  65. * 名        称:                void LCD1602_Init()                                 
  66. * 功        能:                初始化LCD1602                                                  
  67. * 说        明:                                                                  
  68. * 输        入:                                                                        
  69. * 输        出:                                         
  70. **************************************************************************/
  71. void LCD1602_Init()
  72. {
  73.         LCD1602_Write_cmd(0x38);                // 16*2显示,5*7点阵,8位数据接口
  74.         LCD1602_Write_cmd(0x0C);                // 显示器开、光标开、光标允许闪烁   
  75.         LCD1602_Write_cmd(0x06);                // 文字不动,光标自动右移   
  76.         LCD1602_Write_cmd(0x01);                // 清屏
  77. }


  78. /**************************************************************************
  79. * 名        称:                void LCD1602_Clear()                                 
  80. * 功        能:                清屏                                                  
  81. * 说        明:                                                                  
  82. * 输        入:                                                                        
  83. * 输        出:                返回初始化的结果(0:复位成功   1:复位失败)                          
  84. **************************************************************************/
  85. void LCD1602_Clear()
  86. {
  87.         LCD1602_Write_cmd(0x01);
  88. }


  89. /**************************************************************************
  90. * 名        称:                uchar LCD1602_Disp_add(uchar row,uchar col)                                 
  91. * 功        能:                设定lcd显示位置,即地址                                                  
  92. * 说        明:     row 行坐标 1~2
  93.                                 col 列坐标 1-16                                                              
  94. * 输        入:     行、列坐标                                                                  
  95. * 输        出:                返回 0 修改失败
  96.                     返回 1 修改成功            
  97. ************************************************************************* */
  98. uchar LCD1602_Disp_add(uchar row,uchar col)
  99. {
  100.     uchar address=0;
  101.     if((row < 1) || (row > 2) || (col < 1) || (col > 16))        //判断参数合法性
  102.     {      
  103.         return 0;        //参数有误,直接返回
  104.     }
  105.     if(row==1)                //把坐标转换成地址
  106.     {
  107.                 address=col-1;
  108.     }
  109.     else if(row==2)
  110.     {
  111.                 address=0x40+(col-1);
  112.     }     
  113.     LCD1602_Write_cmd(0x80|address);        //写入地址
  114.     return 1;
  115. }

  116. /**************************************************************************
  117. * 名        称:                void LCD1602_Disp_chr(uchar row, uchar col, uchar chr)                                 
  118. * 功        能:                在特定的坐标写入字符                                                  
  119. * 说        明:     row 行坐标 1~2        如果是0则不进行坐标改动
  120.                                 col 列坐标 1-16        如果是0则不进行坐标改动
  121.                                 chr 字符ASCII码                                                            
  122. * 输        入:                uchar row, uchar col, uchar chr    例如:LCD1602_Disp_chr(1, 3,0x70)                                                                    
  123. * 输        出:                           
  124. ************************************************************************* */
  125. void LCD1602_Disp_chr(uchar row, uchar col, uchar chr)
  126. {   
  127.     if((row != 0) && (col != 0)) //改动光标位置
  128.     {
  129.         if(!LCD1602_Disp_add(row, col))
  130.         {
  131.                         return;                //光标修改失败,直接返回
  132.         }
  133.     }
  134.     LCD1602_Write_dat(chr);                //写入字符
  135. }

  136. /**************************************************************************
  137. * 名        称:                void LCD1602_Disp_string(uchar row, uchar col, uchar *str)                                 
  138. * 功        能:                在特定的坐标写入字符串,没有换行功能                                                  
  139. * 说        明:                row -- 行坐标 1~2, 如果是0则不进行坐标改动
  140.                               col -- 列坐标 1~16,如果是0则不进行坐标改动
  141.                               str -- 字符串地址                                                            
  142. * 输        入:                uchar row, uchar col, uchar *str   例如:LCD1602_Disp_string(1, 3,"abcdefgh")                                                                    
  143. * 输        出:                           
  144. ************************************************************************* */
  145. void LCD1602_Disp_string(uchar row,uchar col,uchar *str)
  146. {
  147.     uchar count = 0;   
  148.     if((row != 0) && (col != 0))        //改动光标位置
  149.     {
  150.         if(!LCD1602_Disp_add(row, col))
  151.         {
  152.             return;                //光标修改失败,直接返回
  153.         }
  154.     }
  155.     while(*str!='')                //写入字符串
  156.     {
  157.         LCD1602_Write_dat(*str);
  158.         str++;        
  159.         count++;        //这里用count计数,防止死循环
  160.         if(count>16)
  161.         {
  162.             break;
  163.         }
  164.     }
  165. }

  166. /*********************************************************************
  167. * 名        称:                void LCD1602_Disp_num(uchar row, uchar col, uint num)               
  168. * 功        能:                在特定的坐标写入数字,没有换行功能       
  169. * 说        明:                row  -- 行坐标 1~2, 如果是0则不进行坐标改动
  170.                                 col  -- 列坐标 1~16,如果是0则不进行坐标改动
  171.                               num  -- 要显示的数字,范围0~9999
  172. * 输        入:                uchar row, uchar col, uint num
  173. * 输        出:
  174. *********************************************************************/
  175. void LCD1602_Disp_num(uchar row, uchar col, uint num)        //注意num的取值范围为0~65535
  176. {
  177.     uchar str[5];                //保存num转换成的字符串
  178.     uchar temp=0,i=0,count=0;
  179.     uchar *p;
  180.    
  181.        

  182.     //取得千位,转换成ASCII码存入str
  183.     temp=num/1000;
  184.     str[0]=temp+'0';
  185.    
  186.     //取得百位
  187.     num= num - 1000 * temp;
  188.     temp= num/100;
  189.     str[1]= temp+'0';
  190.    
  191.     //取得十位                                                                                                                  
  192.     num= num - 100 * temp;
  193.     temp= num / 10;
  194.     str[2]=temp+'0';
  195.    
  196.     //取得个位
  197.     temp= num % 10;
  198.     str[3]=temp+'0';
  199.    
  200.     //添加字符串结束标志
  201.     str[4]='';
  202.    
  203.     //统计高位0的位数
  204.     p=str;
  205.     while(*p!='')
  206.     {
  207.         if(*p++=='0')
  208.         {
  209.             count++;
  210.         }
  211.         else
  212.         {
  213.             break;
  214.         }
  215.     }
  216.                                                                                                                                            
  217.     if(count==0)
  218.     {
  219.         //最高位不为0,不用处理
  220.     }
  221.     else if((count>0)&&(count<4))
  222.     {
  223.                 for(i=0;i<(4-count);i++) //根据0的个数,将字符串左移count个
  224.         {
  225.                 str[i]=str[i+count];
  226.         }
  227.         str[i]= '';
  228.     }
  229.     else if(count==4)
  230.     {
  231.         str[1]='';
  232.     }
  233.            LCD1602_Disp_string(row,col,str);
  234. }                                                                          
  235.                                                                                                                                             
复制代码

  1. /*****************************8位精度*******************************/
  2. /*********************************************************************
  3. * 名        称:                uchar AD7887_READ_ONE_BYTE()               
  4. * 功        能:                读取转换后的AD数据
  5. * 说        明:                前4位数据为引导位0 后8位数据位转换后的AD值 取高8位数据,丢弃最后4位
  6. * 输        入:                无
  7. * 输        出:                Readvalue
  8. *********************************************************************/

  9. uchar AD7887_READ_ONE_BYTE()   
  10. {   
  11.         uchar i,j,k;
  12.         uchar Readvalue=0;        //定义转换后的AD数值
  13.         AD_CS=1;
  14.         AD_SCLK=1;               
  15.         AD_DOUT=1;               
  16.         AD_DIN=1;

  17.         AD_CS =0;                        //片选信号拉低
  18.         AD_SCLK=1;                        //时钟保持一会  由于51单片机执行一条指令时间为1us,所以可以不做延时
  19.        
  20.         for(i=0;i<4;i++)        //循环4次,跳过4位引导位
  21.         {
  22.                 AD_SCLK=0;
  23.                 AD_SCLK=1;
  24.         }

  25.         for(j=0;j<8;j++)        //读循环8次 刚好为一个字节
  26.         {
  27.                 AD_SCLK=0;                //时钟信号拉低
  28.                 Readvalue<<=1;        //数据左移1位 先读高位,后读低位
  29.                 AD_SCLK=1;                //时钟信号拉高

  30.                 if(AD_DOUT)                //如果AD_DOUT输出高电平
  31.                 {
  32.                         Readvalue|=0x01;        //将读到的数放在最低位,左移后变为高位
  33.                 }
  34.                 else
  35.                 {
  36.                         Readvalue&=0xfe;        //否则将读到的数据置为0
  37.                 }
  38.         }       

  39.         for(k=0;k<4;k++)                   //读循环4次 只产生时钟信号,不读数据
  40.         {
  41.                 AD_SCLK=0;
  42.             AD_SCLK=1;
  43.         }
  44.                                                                        
  45.         AD_SCLK=1;
  46.         AD_CS =1;

  47.         return Readvalue;                        //返回读到的数据                                           
  48. }                       


  49. /*********************************************************************
  50. * 名        称:                uchar GetADCResult(uchar AD_Channel)               
  51. * 功        能:                读取 uchar AD_Channel 通道的AD值
  52. * 说        明:                先写入要读取的通道(配置寄存器),然后读取数据
  53. * 输        入:                AD7887_WRITE_ONE_BYTE();AD7887_READ_ONE_BYTE()
  54. * 输        出:                ADCResult
  55. *********************************************************************/
  56. uchar GetADCResult(uchar AD_Channel)
  57. {
  58.         uchar ADC_Result;                                        //定义得到的转换结果 ADC_Result
  59.         AD7887_WRITE_ONE_BYTE(AD_Channel);        //配置寄存器为AD_Channel
  60.         ADC_Result=AD7887_READ_ONE_BYTE();  //读取AD_Channel通道的转换数据        并将值赋给ADC_Result

  61.         return ADC_Result;
  62. }


  63. /*******************滤波算法2****************************************
  64. * 名        称:                uchar filter(uchar channel)               
  65. * 功        能:                对uchar channel通道的AD值进行滤波处理
  66. * 说        明:                数据滤波函数 采用中位值平均滤波
  67. * 输        入:                GetADCResult(channel)
  68. * 输        出:                sum/(filter_N-2)  
  69. *********************************************************************/
  70. uchar filter(uchar channel)
  71. {
  72.         uint ADC_min, ADC_max, ADC_tmp, ADC_result, ADC;
  73.     uchar i, j;

  74.     ADC = 0;
  75.     for(j = 0; j < 16; j++)                        //16为滤波强度
  76.     {
  77.         ADC_result = 0;
  78.         ADC_min = ADC_max = GetADCResult(channel);
  79.         for(i = 0; i < 8; i++)
  80.         {
  81.             ADC_tmp = GetADCResult(channel);
  82.             if(ADC_tmp < ADC_min)
  83.             {
  84.                                 ADC_result += ADC_min;
  85.                 ADC_min = ADC_tmp;
  86.             }
  87.             else if(ADC_tmp > ADC_max)
  88.             {
  89.                 ADC_result += ADC_max;
  90.                 ADC_max = ADC_tmp;
  91.             }
  92.             else
  93.             {
  94.                 ADC_result += ADC_tmp;
  95.             }
  96.         }

  97.         ADC_result /= 8;
  98.         ADC += ADC_result;
  99.     }
  100.     ADC /= 16;

  101.     return ADC;

  102. }




  103. void AD_Display1()
  104. {
  105.                                                                                                                                   
  106.         uchar temp1=0;                                                                                                                       
  107.         temp1=filter(AD_Channel0);                 //将AD_Channel0通道读取到的值滤波后赋给temp1                                       
  108.         LCD1602_Disp_num(1,1,temp1);        //将temp1值在LCD1602的第1行第一列开始显示

  109. //        temp1=0;
  110. }


  111. void AD_Display2()                                                                  
  112. {
  113.         uchar temp2=0;
  114.         temp2=filter(AD_Channel1);                //将AD_Channel1通道读取到的值滤波后赋给temp2                                       
  115.         LCD1602_Disp_num(2,1,temp2);        //将temp2值在LCD1602的第2行第一列开始显示
  116.        
  117. //        temp2=0;                                                                                                                                          

  118. }                                                                                                                                                     
  119.                                                                                                                                                                    
复制代码

  1. #include"STC89C5xRC.h"
  2. #include <intrins.h>
  3. #include "LCD1602.h"
  4. #include "AD7887.h"
  5. #include "Hardconfig.h"

  6. #define AD_Channel_0 0X31                //双通道工作 通道1  模式2 PM1=0 PM0=1  AD7887电源始终开启
  7. #define AD_Channel_1 0X39                //双通道工作 通道2  模式2 PM1=0 PM0=1  AD7887电源始终开启

  8. uint temp1=0,temp2=0;

  9. uint ad_time=0;
  10. uint ds_time=50000;        //定时器定时时间


  11. /**********定时器0初始化***********/
  12. void Timer0Init(void)
  13. {
  14.     TMOD &= 0xf0 ;
  15.     TMOD |= 0x01 ;      //定时器0工作方式1
  16.           TH0=(65536-(FOSC/12)*ds_time)/ 256;                //定时器重新赋初值
  17.         TL0=(65536-(FOSC/12)*ds_time)% 256;                  
  18.   
  19.     TR0  = 1 ;
  20.     ET0  = 1 ;
  21. }         

  22.   

  23. void main()
  24. {
  25.         Timer0Init();
  26.     EA = 1 ;

  27.         Delay_us(100);
  28.         LCD1602_Init();
  29.         LCD1602_Clear();

  30.         while(1)
  31.         {         

  32.         }       
  33. }



  34. /**********        定时器0中断**********/
  35. void Time0Isr(void) interrupt 1
  36. {
  37.         TH0=(65536-(FOSC/12)*ds_time)/ 256;                //定时器重新赋初值
  38.         TL0=(65536-(FOSC/12)*ds_time)% 256;

  39.         LCD1602_Clear();
  40.         ad_time++;
  41.        
  42.         LCD1602_Disp_num(2,10,ad_time);
  43.        
  44.         temp1=filter(AD_Channel_0);
  45.         LCD1602_Disp_num(1,1,temp1);
  46.        
  47.         temp2=filter(AD_Channel_1);
  48.         LCD1602_Disp_num(2,1,temp2);
  49.        

  50. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
17条回答
weimas
1楼-- · 2020-01-22 14:07
自己做个沙发,为什么代码发到阿莫这里感觉要比在keil里清爽多了
lcw_swust
2楼-- · 2020-01-22 16:13
 精彩回答 2  元偷偷看……
weimas
3楼-- · 2020-01-22 20:00
lcw_swust 发表于 2014-9-4 14:49
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会 ...

之前尝试过,但是1602驱动程序是网上下的,只是有些地方自己加了小改动,你说的那部分改过,但失败了,因为我不会指针
也尝试过在void LCD1602_Disp_num(uchar row, uchar col, uint num)里增加过清屏,但是直接不显示了,现在我再试试你说的方法,尝试着改下, 谢谢先
weimas
4楼-- · 2020-01-22 23:41
lcw_swust 发表于 2014-9-4 14:49
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会 ...

加了清屏为什么 ad_time 显示不闪 而temp1和temp2一直闪
weimas
5楼-- · 2020-01-23 02:38
问题已解决,虽然能用了,但感觉还不是很完美,主要修改了LCD1602的驱动里 void LCD1602_Disp_num(uchar row, uchar col, uint num) 函数,代码如下:
  1. void LCD1602_Disp_num(uchar row, uchar col, uint num)        //注意num的取值范围为0~65535
  2. {
  3.         uchar str[5];               
  4.     uchar temp=0,test=0,count=0;


  5.     //取得万位
  6.     temp=num/10000;
  7.     str[0]=temp;
  8.         LCD1602_Disp_chr(row,col,table[str[0]]);
  9.    
  10.     //取得千位
  11.     num= num - 10000 * temp;
  12.     temp= num/1000;
  13.     str[1]= temp;
  14.         LCD1602_Disp_chr(row,col+1,table[str[1]]);

  15.         //取得百位
  16.     num= num - 1000 * temp;
  17.     temp= num/100;
  18.     str[2]= temp;
  19.         LCD1602_Disp_chr(row,col+2,table[str[2]]);

  20.     //取得十位
  21.     num= num - 100 * temp;
  22.     temp= num/10;
  23.     str[3]= temp;
  24.         LCD1602_Disp_chr(row,col+3,table[str[3]]);

  25.     //取得个位
  26.     temp= num % 10;
  27.     str[4]=temp;
  28.         LCD1602_Disp_chr(row,col+4,table[str[4]]);

  29.         if(str[0]==0)
  30.         {
  31.                 LCD1602_Disp_chr(row,col,0x20);       
  32.                 if(str[1]==0)
  33.                 {
  34.                         LCD1602_Disp_chr(row,col+1,0x20);
  35.                         if(str[2]==0)
  36.                         {
  37.                                 LCD1602_Disp_chr(row,col+2,0x20);
  38.                                 if(str[3]==0)
  39.                                 {
  40.                                         LCD1602_Disp_chr(row,col+3,0x20);
  41.                                         if(str[4]==0)
  42.                                         {
  43.                                                 LCD1602_Disp_chr(row,col+4,0x30);
  44.                                         }
  45.                                 }
  46.                         }
  47.                 }

  48.         }
  49. }                                                                          
  50.        
复制代码
lxa0
6楼-- · 2020-01-23 06:12
毫无疑问
是你的刷新数据的代码部分出问题了

一周热门 更多>