求助各位大侠,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);
}
自己做个沙发{:lol:},为什么代码发到阿莫这里感觉要比在keil里清爽多了{:titter:} 本帖最后由 lcw_swust 于 2014-9-4 14:50 编辑
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会一直存在.
应当改为显示位数不变,数据位数不足时以空格补足 lcw_swust 发表于 2014-9-4 14:49
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会 ...
之前尝试过,但是1602驱动程序是网上下的,只是有些地方自己加了小改动,你说的那部分改过,但失败了,因为我不会指针
也尝试过在void LCD1602_Disp_num(uchar row, uchar col, uint num)里增加过清屏,但是直接不显示了,现在我再试试你说的方法,尝试着改下, 谢谢先 lcw_swust 发表于 2014-9-4 14:49
//根据0的个数,将字符串左移count个
应该是这里引起的,100显示三位,99只显示两位,若不清屏,之前的0当然会 ...
加了清屏为什么 ad_time 显示不闪 而temp1和temp2一直闪 问题已解决,虽然能用了,但感觉还不是很完美,主要修改了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
毫无疑问
是你的刷新数据的代码部分出问题了
是不是缓存这里出了问题,新的驱动试过了没有问题。只是高位为0时不会左移了,感觉有点不爽{:lol:} 你的这个与数码钟很相似
比如数码钟,秒个位到10就向秒十位进位
秒到60了就向分个位进位
不存在移位呀
.............. 显示两位数时用上空格,并定点显示 显示两位数时用上空格,并定点显示 lxa0 发表于 2014-9-5 19:12
你的这个与数码钟很相似
比如数码钟,秒个位到10就向秒十位进位
秒到60了就向分个位进位
比如我显示的是 12345一直往下减到 45时,是显示 “ 45” 而不是“45 ” weimas 发表于 2014-9-9 09:27
比如我显示的是 12345一直往下减到 45时,是显示 “ 45” 而不是“45 ”...
找你的方式
应该是显示 00045 吧?
最后应该是 00000 对吧? lxa0 发表于 2014-9-9 14:00
找你的方式
应该是显示 00045 吧?
最后应该是 00000 对吧?
不对,是“00045”而不是“45000” 这里的“0”代表空白啊 是不是需要清屏? sunzehua 发表于 2014-9-10 10:02
是不是需要清屏?
清屏的时候发现显示会抖动 不用清屏,补空格刷新即可 今天有点时间就折腾了一下,问题竟然解决了{: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]