发泄一下!4bit数据接口的LCD1602A也太难搞定了!
准备搞个自行车里程速度表,因为准备添加的功能过多,I/O脚不够,参考网上的资料搞了个4Bit数据接口的1602程序,结果才下载进单片机时还行,重启后立马显示乱码!上网查了N久,发现有两点可能导致这个问题!第一:初始化出错,第二:操作时序不正确!网上初始化有好几种,全都试了一遍,无效!后来根据太阳人网上的数据手册微调了一下时序,暂时稳定了!贴出程序请大家指正!/*******************************************************************************
*工 程 名: 自行车里程表
*开始日期: 2012年05月06日
*编 写 人: lilin
*工程描述: 自用A3144E测速,LCD1602显示
*******************************************************************************
*硬件描述:
*单 片 机: C8051F330 DIP20
*传 感 器: A3144E
*显 示 器: LCD1602
*硬件连接: D4——D7 P1.4——P1.7
RS P0.0
RW P0.1
E P0.2
*******************************************************************************/
/*******************************************************************************
*版本记录: V0.1
*功 能: LCD1602显示测试完成,8Bit数据线控制
*待 改 进: 4Bit数据线控制,改进日期5-10---完成
*******************************************************************************/
#include <c8051f330.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
//预处理数值定义区
#define Delays_timer0 24121 //定时器延时时间2MS
#define Wheel_length 1.87 //自行车单周行程1.87M
#define Lcd_data P1 //1602数据口为单片机P1口,4位数据线接在P1.4-P1.7
/********************************变量定义区************************************/
//BIT数据定义区
sbit Lcd_rs=P0^0; //LCD1602 RS引脚接P0.0
sbit Lcd_rw=P0^1; //LCD1602 R/W引脚接P0.1
sbit Lcd_ee=P0^2; //LCD1602 E引脚接P0.2
//8位数据定义区
uint8 Soft_Id=0; //程序运行允许位,最高位为零速标志位;
uint8 Delays_lcd=0; //LCD1602延时参数;
uint8 Time_s=0; //时钟显示
uint8 Time_m=0;
uint8 Time_h=0;
//16位数据定义区
uint16 Mcu_time=0; //单片机定时器计数器;
uint16 Wheel_time=0; //单周车轮所需时间;
uint16 New_time=0; //最新采集的单周所需时间数据;
uint16 Old_time=0; //以前采集的单周所需时间数据;
uint16 Wheel_count=0; //自行车车轮转数计数;
uint16 Cycling_speed=0; //自行车速度(米/秒);
//数组定义区
/******************************函数区******************************************/
/*******************************************************************************
*函 数 名: Mcu_Init()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: 单片机相关初始化,HL振荡器、IO口、定时器
*传入参数: 无
*返回参数: 无
*内部变量: 无
*全局变量: 无
*******************************************************************************/
void Mcu_Init(void)
{
//系统时钟初始化 SYSCLK=24MHZ,内部HL振荡器使能
OSCICL += 4;
OSCICN |= ( 1<<7 );
while( !( OSCICN & 0x40 ) );
OSCICN |= 3;
CLKSEL = 0;
//禁止看门狗
PCA0MD &= 0xBF;
//I/O口初始化,P0.7为INT0,交叉开关跳过
P0MDIN=0xff;
P1MDIN=0xff;
P0MDOUT=0x00; //P0漏极开路输出
P1MDOUT=0x00; //P1漏极开路输出
P0SKIP=0x80; //P0引脚交叉开关跳过P0.7
P1SKIP=0x00;
XBR0=0x00;
XBR1=0x40; //交叉开关使能,引脚弱上拉
//INT0初始化,边缘触发,P0.7脚为INT0引脚
IT0=1;
IT01CF=0x07;
//定时器0初始化
//定时器0运行在16位重载模式,系统时钟
TMOD=0x01;
CKCON=0x04;
TH0=(65536-Delays_timer0)>>8;
TL0=(65536-Delays_timer0)&0xff;
TR0=1;
//开启Timer0,INT0中断
EX0=1;
ET0=1;
EA=1;
}
/*******************************************************************************
*函 数 名: Delays_ms()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: 系统运行过快,延时MS
*传入参数: Dly_time:需要延时的MS数
*返回参数: 无
*内部变量: iii
*全局变量: 无
*******************************************************************************/
void Delays_ms(uint8 Dly_time)
{
Delays_lcd=Dly_time+1;
while(Delays_lcd);
}
/*******************************************************************************
*函 数 名: Check_lcd()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: LCD1602忙状态检查,DB7=1
*传入参数: 无
*返回参数: P1
*内部变量: 无
*全局变量: 无
*******************************************************************************/
unsigned char Check_lcd(void)
{
uint8 temp1=0 ;
do
{
Lcd_rs = 0;
Lcd_rw = 1;
Lcd_ee = 0;
Lcd_ee = 1;
Delays_ms(2);
temp1=Lcd_data & 0xf0;
Delays_ms(1);
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Delays_ms(2);
Lcd_ee = 0;
}
while(temp1 & 0x80);
return(Lcd_data);
}
/*******************************************************************************
*函 数 名: Wcom_lcd()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: Lcd1602写命令函数
*传入参数: Lcd_com:命令代码 ,BuysC:是否要求忙检查
*返回参数: 无
*内部变量: 无
*全局变量: 无
*******************************************************************************/
void Wcom_lcd(uint8 Lcd_com,uint8 BuysC )
{
if (BuysC) Check_lcd(); //根据需要检测忙
Lcd_rs = 0;
Lcd_rw = 0;
Lcd_ee = 0;
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=(Lcd_com & 0xf0);
Delays_ms(2);
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=((Lcd_com & 0x0f))<<4;
Delays_ms(2);
Lcd_ee = 0;
}
/*******************************************************************************
*函 数 名: Wdat_lcd()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: Lcd1602写数据函数
*传入参数: Lcd_dat:需要写入的数据
*返回参数: 无
*内部变量: 无
*全局变量: 无
*******************************************************************************/
void Wdat_lcd(unsigned char Lcd_dat)
{
Check_lcd(); //检测忙
Lcd_rs = 1;
Lcd_rw = 0;
Lcd_ee = 0; //延时
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=(Lcd_dat & 0xf0);
Delays_ms(2);
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=((Lcd_dat & 0x0f))<<4;
Delays_ms(2);
Lcd_ee = 0;
}
/*
unsigned char Rdat_lcd(void)
{
Lcd_rs = 1;
Delays_sys();
Lcd_rw = 1;
Delays_sys();
Lcd_ee = 0;
Delays_sys();
Lcd_ee = 0;
Delays_sys();
Lcd_ee = 1;
Delays_sys();
return(Lcd_data);
}
*/
/*******************************************************************************
*函 数 名: DisplayOneChar
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: Lcd1602插入数据函数
*传入参数: X:一行中的位置 ,Y:第几行,DData:需插入的数据
*返回参数: 无
*内部变量: 无
*全局变量: 无
*******************************************************************************/
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y)
{
X |= 0x40; //当要显示第二行时地址码+0x40;
}
X |= 0x80; // 算出指令码
Wcom_lcd(X, 0); //这里不检测忙信号,发送地址码
Wdat_lcd(DData);
}
/*******************************************************************************
*函 数 名: DisplayOneChar
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: Lcd1602插入数据函数
*传入参数: X:一行中的位置 ,Y:第几行,DData:需插入的数据
*返回参数: 无
*内部变量: 无
*全局变量: 无
*******************************************************************************/
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData>0x20) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData); //显示单个字符
ListLength++;
X++;
}
}
}
/*******************************************************************************
*函 数 名: timer0()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: 定时器0中断程序,系统自动调用
*传入参数: 无
*返回参数: 无
*内部变量: 无
*全局变量: Mcu_time,Wheel_time,Soft_Id
*******************************************************************************/
void timer0() interrupt 1
{
//重置Timer0寄存器
TH0=(65536-Delays_timer0)>>8;
TL0=(65536-Delays_timer0)&0xff;
//定时器计数器自加1
Mcu_time++;
//轮子单周所需时间计数
if(Soft_Id & 0x80)
{
Wheel_time++;
}
//Lcd1602延时
if(Delays_lcd >0)
{
Delays_lcd--;
}
}
/*******************************************************************************
*函 数 名: INT0_ISR()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: 外部中断0中断程序,系统自动调用
*传入参数: 无
*返回参数: 无
*内部变量: 无
*全局变量: Wheel_count,Wheel_time,Soft_Id,New_time,Old_time
*******************************************************************************/
void INT0_ISR(void) interrupt 0
{
Wheel_count++;
if(Soft_Id & 0x80)
{
Old_time =New_time;
New_time =Wheel_time;
}
else
{
Soft_Id |= 0x80;
Old_time =0;
New_time =0;
}
Wheel_time=0;
}
void Wcom_lcd_8(uint8 Lcd_com,uint8 BuysC )
{
if (BuysC) Check_lcd(); //根据需要检测忙
Lcd_rs = 0;
Lcd_rw = 0;
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Lcd_data = Lcd_com;
Delays_ms(2);
Lcd_ee = 0;
}
/*******************************************************************************
*函 数 名: Lcd_Init()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: Lcd1602初始化函数
*传入参数: 无
*返回参数: 无
*内部变量: 无
*全局变量: 无
*******************************************************************************/
void Lcd_Init(void)
{
Delays_ms(240);
Delays_ms(240);
Lcd_data |= 0xf0;
Wcom_lcd_8(0x30,0); //三次显示模式设置,不检测忙信号
Delays_ms(20);
Wcom_lcd_8(0x30,0); //三次显示模式设置,不检测忙信号
Delays_ms(20);
Wcom_lcd_8(0x30,0); //三次显示模式设置,不检测忙信号
Delays_ms(20);
Wcom_lcd_8(0x20,0);
Delays_ms(20);
/*
Wcom_lcd(0x28,0);
Delays_ms(5);
Wcom_lcd(0x28,0);
Delays_ms(5);
*/
Wcom_lcd(0x2c,1); //显示模式设置,开始要求每次检测忙信号,4Bit模式
Wcom_lcd(0x08,1); //关闭显示
Wcom_lcd(0x01,1); //显示清屏
Wcom_lcd(0x06,1); // 显示光标移动设置
Wcom_lcd(0x0C,1); // 显示开及光标设置
Wcom_lcd(0x80,1);
Delays_ms(5);
}
/*******************************************************************************
*函 数 名: main()
*日 期: 2012年05月06日
*编 写 人: Lilin
*函数说明: 主函数
*传入参数: 无
*返回参数: 无
*内部变量: 无
*全局变量: Wheel_count,Wheel_time,Soft_Id,New_time,Old_time,Cycling_speed,
Mcu_time,
*******************************************************************************/
void main(void)
{
Mcu_Init();
Lcd_Init();
DisplayListChar(1, 0,"0.0km/h");
DisplayListChar(10, 0,"0.0km");
DisplayListChar(0, 1,"00:00:00");
DisplayListChar(9, 1,"Power:0");
while(1);
} 因为才搞定LCD1602,有些垃圾代码没有清理,还有部分代码没有注释,大家见谅! 初始化时的几个延时搞定就ok了,没那么恐怖 同解,初始化的延时适当加长些,很容易成功的。 C8051F330 啊, 都不是普通51, 当然要适当加延时拉 印象中C8051F的单片机是普通51的12倍吧。 本帖最后由 bluefeel 于 2012-5-11 00:47 编辑
很简单的,你参考按照HD44780数据手册的时序和初始化步骤,绝对没有问题,根本不需要看别人的程序。
记得是官方英文版的HD44780数据手册。
7楼正解! 这个我都搅了一阵子才搅掂! 7楼对。只要严格按照时序做,一点都不难,也不会出现奇奇怪怪的问题。 330驱动1602的4线方式很简单呀,时序主要就是延迟,足够大的延迟是关键。这部分不难。 很容易啊,坛里的高手可以用一个IO口搞定 {:titter:}搜索 一下 2个 io驱动 1602 cowboy 出品的 谁说延时足够就成的?一开始我RS、RW、E引脚电平改变时,全部加上延时,而且延时改的好大,结果还是乱码!
那时候LCD1602初始化+显示被我不小心改到要5S钟,还是乱码!,后来不过是将写数据与写命令函数中E=1改到Lcd_data = Lcd_com语句前面,并加大延时才成功的! 很简单的,你参考按照HD44780数据手册的时序和初始化步骤,绝对没有问题,根本不需要看别人的程序。
absolutely agree. 我用了4位线的,也是出乱码,我把lcd写命令和数据的函数执行时,关了总中断,然后又开中断就好啦 yyande 发表于 2012-5-11 18:45 static/image/common/back.gif
谁说延时足够就成的?一开始我RS、RW、E引脚电平改变时,全部加上延时,而且延时改的好大,结果还是乱码!
...
态度要改改,太冲了,别人也是在帮你 可以参考一下傻孩子的1602库函数,我用了几次,基本上是一次成功 拿来主义要不得,认真研究一下文档,也许比你copy一个代码效率还高点。 LT1234567 发表于 2012-5-14 06:49 static/image/common/back.gif
态度要改改,太冲了,别人也是在帮你
没事,我们已经明白为什么这么难了。
页:
[1]