weimas 发表于 2014-9-4 14:37:57

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

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

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

#include"Hardconfig.h"



/**************************************************************************
* 名        称:                void LCD1602_Busy()                                 
* 功        能:                液晶屏忙碌检查                                                
* 说        明:                                                                  
* 输        入:                                                                        
* 输        出:                返回初始化的结果(0:不忙碌   1:忙碌)                        
**************************************************************************/
void LCD1602_Busy()
{
        do
        {
                LCD_DATAPort=0xff;
                LCD_RS=0;
                LCD_RW=1;
                LCD_EN=0;       
                LCD_EN=1;
        }
        while(BUSY);
        LCD_EN=0;               
}


/**************************************************************************
* 名        称:                void LCD1602_Write_cmd(uchar cmd)                                 
* 功        能:                向LCD1602写指令                                                
* 说        明:                                                                  
* 输        入:   cmd   要写入的指令值                                                                  
* 输        出:                                          
**************************************************************************/
void LCD1602_Write_cmd(uchar cmd)
{
        LCD1602_Busy();
        LCD_EN=0;
        LCD_RS=0;
        LCD_RW=0;
        LCD_DATAPort=cmd;
        _nop_();
    _nop_();
        LCD_EN=1;
        _nop_();
    _nop_();
        LCD_EN=0;                       
}


/**************************************************************************
* 名        称:                void LCD1602_Write_dat(uchar dat)                                 
* 功        能:                向LCD1602写数据                                                
* 说        明:                                                                  
* 输        入:   dat   要写入的数据值                                                                  
* 输        出:                                          
**************************************************************************/
void LCD1602_Write_dat(uchar dat)
{
        LCD1602_Busy();
        LCD_EN=0;
        LCD_RS=1;
        LCD_RW=0;
        LCD_DATAPort=dat;
        _nop_();
    _nop_();
        LCD_EN=1;
        _nop_();
    _nop_();
        LCD_EN=0;                       
}


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


/**************************************************************************
* 名        称:                void LCD1602_Clear()                                 
* 功        能:                清屏                                                
* 说        明:                                                                  
* 输        入:                                                                        
* 输        出:                返回初始化的结果(0:复位成功   1:复位失败)                        
**************************************************************************/
void LCD1602_Clear()
{
        LCD1602_Write_cmd(0x01);
}


/**************************************************************************
* 名        称:                uchar LCD1602_Disp_add(uchar row,uchar col)                                 
* 功        能:                设定lcd显示位置,即地址                                                
* 说        明:   row 行坐标 1~2
                                col 列坐标 1-16                                                            
* 输        入:   行、列坐标                                                                  
* 输        出:                返回 0 修改失败
                    返回 1 修改成功            
************************************************************************* */
uchar LCD1602_Disp_add(uchar row,uchar col)
{
    uchar address=0;
    if((row < 1) || (row > 2) || (col < 1) || (col > 16))        //判断参数合法性
    {      
      return 0;        //参数有误,直接返回
    }
    if(row==1)                //把坐标转换成地址
    {
                address=col-1;
    }
    else if(row==2)
    {
                address=0x40+(col-1);
    }   
    LCD1602_Write_cmd(0x80|address);        //写入地址
    return 1;
}

/**************************************************************************
* 名        称:                void LCD1602_Disp_chr(uchar row, uchar col, uchar chr)                                 
* 功        能:                在特定的坐标写入字符                                                
* 说        明:   row 行坐标 1~2        如果是0则不进行坐标改动
                                col 列坐标 1-16        如果是0则不进行坐标改动
                                chr 字符ASCII码                                                            
* 输        入:                uchar row, uchar col, uchar chr    例如:LCD1602_Disp_chr(1, 3,0x70)                                                                  
* 输        出:                           
************************************************************************* */
void LCD1602_Disp_chr(uchar row, uchar col, uchar chr)
{   
    if((row != 0) && (col != 0)) //改动光标位置
    {
      if(!LCD1602_Disp_add(row, col))
      {
                        return;                //光标修改失败,直接返回
      }
    }
    LCD1602_Write_dat(chr);                //写入字符
}

/**************************************************************************
* 名        称:                void LCD1602_Disp_string(uchar row, uchar col, uchar *str)                                 
* 功        能:                在特定的坐标写入字符串,没有换行功能                                                
* 说        明:                row -- 行坐标 1~2, 如果是0则不进行坐标改动
                              col -- 列坐标 1~16,如果是0则不进行坐标改动
                              str -- 字符串地址                                                            
* 输        入:                uchar row, uchar col, uchar *str   例如:LCD1602_Disp_string(1, 3,"abcdefgh")                                                                  
* 输        出:                           
************************************************************************* */
void LCD1602_Disp_string(uchar row,uchar col,uchar *str)
{
    uchar count = 0;   
    if((row != 0) && (col != 0))        //改动光标位置
    {
      if(!LCD1602_Disp_add(row, col))
      {
            return;                //光标修改失败,直接返回
      }
    }
    while(*str!='\0')                //写入字符串
    {
      LCD1602_Write_dat(*str);
      str++;      
      count++;        //这里用count计数,防止死循环
      if(count>16)
      {
            break;
      }
    }
}

/*********************************************************************
* 名        称:                void LCD1602_Disp_num(uchar row, uchar col, uint num)               
* 功        能:                在特定的坐标写入数字,没有换行功能       
* 说        明:                row-- 行坐标 1~2, 如果是0则不进行坐标改动
                                col-- 列坐标 1~16,如果是0则不进行坐标改动
                              num-- 要显示的数字,范围0~9999
* 输        入:                uchar row, uchar col, uint num
* 输        出:
*********************************************************************/
void LCD1602_Disp_num(uchar row, uchar col, uint num)        //注意num的取值范围为0~65535
{
    uchar str;                //保存num转换成的字符串
    uchar temp=0,i=0,count=0;
    uchar *p;
   
       

    //取得千位,转换成ASCII码存入str
    temp=num/1000;
    str=temp+'0';
   
    //取得百位
    num= num - 1000 * temp;
    temp= num/100;
    str= temp+'0';
   
    //取得十位                                                                                                                  
    num= num - 100 * temp;
    temp= num / 10;
    str=temp+'0';
   
    //取得个位
    temp= num % 10;
    str=temp+'0';
   
    //添加字符串结束标志
    str='\0';
   
    //统计高位0的位数
    p=str;
    while(*p!='\0')
    {
      if(*p++=='0')
      {
            count++;
      }
      else
      {
            break;
      }
    }
                                                                                                                                           
    if(count==0)
    {
      //最高位不为0,不用处理
    }
    else if((count>0)&&(count<4))
    {
                for(i=0;i<(4-count);i++) //根据0的个数,将字符串左移count个
      {
              str=str;
      }
      str= '\0';
    }
    else if(count==4)
    {
      str='\0';
    }
           LCD1602_Disp_string(row,col,str);
}                                                                          
                                                                                                                                            


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

uchar AD7887_READ_ONE_BYTE()   
{   
        uchar i,j,k;
        uchar Readvalue=0;        //定义转换后的AD数值
        AD_CS=1;
        AD_SCLK=1;               
        AD_DOUT=1;               
        AD_DIN=1;

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

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

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

        for(k=0;k<4;k++)                   //读循环4次 只产生时钟信号,不读数据
        {
                AD_SCLK=0;
          AD_SCLK=1;
        }
                                                                       
        AD_SCLK=1;
        AD_CS =1;

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


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

        return ADC_Result;
}


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

    ADC = 0;
    for(j = 0; j < 16; j++)                        //16为滤波强度
    {
      ADC_result = 0;
      ADC_min = ADC_max = GetADCResult(channel);
      for(i = 0; i < 8; i++)
      {
            ADC_tmp = GetADCResult(channel);
            if(ADC_tmp < ADC_min)
            {
                                ADC_result += ADC_min;
                ADC_min = ADC_tmp;
            }
            else if(ADC_tmp > ADC_max)
            {
                ADC_result += ADC_max;
                ADC_max = ADC_tmp;
            }
            else
            {
                ADC_result += ADC_tmp;
            }
      }

      ADC_result /= 8;
      ADC += ADC_result;
    }
    ADC /= 16;

    return ADC;

}




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

//        temp1=0;
}


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

}                                                                                                                                                     
                                                                                                                                                               


#include"STC89C5xRC.h"
#include <intrins.h>
#include "LCD1602.h"
#include "AD7887.h"
#include "Hardconfig.h"

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

uint temp1=0,temp2=0;

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


/**********定时器0初始化***********/
void Timer0Init(void)
{
    TMOD &= 0xf0 ;
    TMOD |= 0x01 ;      //定时器0工作方式1
        TH0=(65536-(FOSC/12)*ds_time)/ 256;                //定时器重新赋初值
        TL0=(65536-(FOSC/12)*ds_time)% 256;                  

    TR0= 1 ;
    ET0= 1 ;
}       



void main()
{
        Timer0Init();
    EA = 1 ;

        Delay_us(100);
        LCD1602_Init();
        LCD1602_Clear();

        while(1)
        {       

        }       
}



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

        LCD1602_Clear();
        ad_time++;
       
        LCD1602_Disp_num(2,10,ad_time);
       
        temp1=filter(AD_Channel_0);
        LCD1602_Disp_num(1,1,temp1);
       
        temp2=filter(AD_Channel_1);
        LCD1602_Disp_num(2,1,temp2);
       

}

weimas 发表于 2014-9-4 14:39:56

自己做个沙发{:lol:},为什么代码发到阿莫这里感觉要比在keil里清爽多了{:titter:}

lcw_swust 发表于 2014-9-4 14:49:12

本帖最后由 lcw_swust 于 2014-9-4 14:50 编辑

//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会一直存在.
应当改为显示位数不变,数据位数不足时以空格补足

weimas 发表于 2014-9-4 14:59:24

lcw_swust 发表于 2014-9-4 14:49
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会 ...

之前尝试过,但是1602驱动程序是网上下的,只是有些地方自己加了小改动,你说的那部分改过,但失败了,因为我不会指针
也尝试过在void LCD1602_Disp_num(uchar row, uchar col, uint num)里增加过清屏,但是直接不显示了,现在我再试试你说的方法,尝试着改下, 谢谢先

weimas 发表于 2014-9-4 15:27:23

lcw_swust 发表于 2014-9-4 14:49
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会 ...

加了清屏为什么 ad_time 显示不闪 而temp1和temp2一直闪

weimas 发表于 2014-9-4 17:03:57

问题已解决,虽然能用了,但感觉还不是很完美,主要修改了LCD1602的驱动里 void LCD1602_Disp_num(uchar row, uchar col, uint num) 函数,代码如下:void LCD1602_Disp_num(uchar row, uchar col, uint num)        //注意num的取值范围为0~65535
{
        uchar str;               
    uchar temp=0,test=0,count=0;


    //取得万位
    temp=num/10000;
    str=temp;
        LCD1602_Disp_chr(row,col,table]);
   
    //取得千位
    num= num - 10000 * temp;
    temp= num/1000;
    str= temp;
        LCD1602_Disp_chr(row,col+1,table]);

        //取得百位
    num= num - 1000 * temp;
    temp= num/100;
    str= temp;
        LCD1602_Disp_chr(row,col+2,table]);

    //取得十位
    num= num - 100 * temp;
    temp= num/10;
    str= temp;
        LCD1602_Disp_chr(row,col+3,table]);

    //取得个位
    temp= num % 10;
    str=temp;
        LCD1602_Disp_chr(row,col+4,table]);

        if(str==0)
        {
                LCD1602_Disp_chr(row,col,0x20);       
                if(str==0)
                {
                        LCD1602_Disp_chr(row,col+1,0x20);
                        if(str==0)
                        {
                                LCD1602_Disp_chr(row,col+2,0x20);
                                if(str==0)
                                {
                                        LCD1602_Disp_chr(row,col+3,0x20);
                                        if(str==0)
                                        {
                                                LCD1602_Disp_chr(row,col+4,0x30);
                                        }
                                }
                        }
                }

        }
}                                                                          
       

lxa0 发表于 2014-9-4 20:08:07

毫无疑问
是你的刷新数据的代码部分出问题了

weimas 发表于 2014-9-5 08:55:09

lxa0 发表于 2014-9-4 20:08
毫无疑问
是你的刷新数据的代码部分出问题了

是不是缓存这里出了问题,新的驱动试过了没有问题。只是高位为0时不会左移了,感觉有点不爽{:lol:}

lxa0 发表于 2014-9-5 19:12:19

你的这个与数码钟很相似
比如数码钟,秒个位到10就向秒十位进位
秒到60了就向分个位进位
不存在移位呀
..............

258963519 发表于 2014-9-8 16:45:48

显示两位数时用上空格,并定点显示

258963519 发表于 2014-9-8 16:46:07

显示两位数时用上空格,并定点显示

weimas 发表于 2014-9-9 09:27:47

lxa0 发表于 2014-9-5 19:12
你的这个与数码钟很相似
比如数码钟,秒个位到10就向秒十位进位
秒到60了就向分个位进位


比如我显示的是 12345一直往下减到 45时,是显示 “   45” 而不是“45   ”

lxa0 发表于 2014-9-9 14:00:54

weimas 发表于 2014-9-9 09:27
比如我显示的是 12345一直往下减到 45时,是显示 “   45” 而不是“45   ”...

找你的方式
应该是显示 00045 吧?
最后应该是 00000 对吧?

weimas 发表于 2014-9-10 09:41:53

lxa0 发表于 2014-9-9 14:00
找你的方式
应该是显示 00045 吧?
最后应该是 00000 对吧?

不对,是“00045”而不是“45000”   这里的“0”代表空白啊

sunzehua 发表于 2014-9-10 10:02:23

是不是需要清屏?

weimas 发表于 2014-9-10 10:34:48

sunzehua 发表于 2014-9-10 10:02
是不是需要清屏?

清屏的时候发现显示会抖动

fscd 发表于 2014-9-10 11:23:06

不用清屏,补空格刷新即可

weimas 发表于 2014-9-17 10:59:18

今天有点时间就折腾了一下,问题竟然解决了{:lol:}在最初原来程序上增加了一条语句完美解决不清屏问题,附上程序void LCD1602_Disp_num(uchar row, uchar col, uint num)        //注意num的取值范围为0~65535
{
        uchar str;                //保存num转换成的字符串
    uchar temp=0,i=0,count=0;
    uchar *p;
   
       

    //取得千位,转换成ASCII码存入str
    temp=num/1000;
    str=temp+'0';
   
    //取得百位
    num= num - 1000 * temp;
    temp= num/100;
    str= temp+'0';
   
    //取得十位                                                                                                                  
    num= num - 100 * temp;                                                                       
    temp= num / 10;
    str=temp+'0';
   
    //取得个位
    temp= num % 10;
    str=temp+'0';
   
    //添加字符串结束标志
    str='\0';
   
    //统计高位0的位数
    p=str;
    while(*p!='\0')
    {
      if(*p++=='0')
      {
            count++;
      }
      else
      {
            break;                                                                                       
      }
    }
                                                                                                                                           
   if(count==0)
    {
      //最高位不为0,不用处理
    }
   else if((count>0)&&(count<4))
    {
                for(i=0;i<(4-count);i++) //根据0的个数,将字符串左移count个
      {
              str=str;
                        LCD1602_Disp_chr(row,5-count,0x20);        //最后一位填充空白
                }
      str= '\0';
          
    }                                                                          
    else if(count==4)
    {
      str='\0';
    }
        LCD1602_Disp_string(row,col,str);                                                                 

}                                                                                         
                                                                                                                                          

其中 LCD1602_Disp_chr(row,5-count,0x20);        //最后一位填充空白
为新加的语句

谢谢各位
页: [1]
查看完整版本: 求助各位大侠,LCD1602显示数值从100变到99时显示990