yyande 发表于 2012-5-10 23:23:17

发泄一下!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);

       
       
       
       
}

yyande 发表于 2012-5-10 23:26:30

因为才搞定LCD1602,有些垃圾代码没有清理,还有部分代码没有注释,大家见谅!

www1519 发表于 2012-5-10 23:37:33

初始化时的几个延时搞定就ok了,没那么恐怖

hecat 发表于 2012-5-10 23:56:08

同解,初始化的延时适当加长些,很容易成功的。

90999 发表于 2012-5-11 00:03:51

C8051F330 啊, 都不是普通51, 当然要适当加延时拉

無智 发表于 2012-5-11 00:34:32

印象中C8051F的单片机是普通51的12倍吧。

bluefeel 发表于 2012-5-11 00:41:47

本帖最后由 bluefeel 于 2012-5-11 00:47 编辑

很简单的,你参考按照HD44780数据手册的时序和初始化步骤,绝对没有问题,根本不需要看别人的程序。

记得是官方英文版的HD44780数据手册。

shark 发表于 2012-5-11 01:13:47

7楼正解!         

downtoearth 发表于 2012-5-11 05:15:10

这个我都搅了一阵子才搅掂!

mowin 发表于 2012-5-11 07:56:51

7楼对。只要严格按照时序做,一点都不难,也不会出现奇奇怪怪的问题。

tiancaigao7 发表于 2012-5-11 10:25:22

330驱动1602的4线方式很简单呀,时序主要就是延迟,足够大的延迟是关键。这部分不难。

raxb 发表于 2012-5-11 14:12:22

很容易啊,坛里的高手可以用一个IO口搞定

jetli 发表于 2012-5-11 15:56:29

{:titter:}搜索 一下 2个 io驱动 1602 cowboy 出品的

yyande 发表于 2012-5-11 18:45:01

谁说延时足够就成的?一开始我RS、RW、E引脚电平改变时,全部加上延时,而且延时改的好大,结果还是乱码!
那时候LCD1602初始化+显示被我不小心改到要5S钟,还是乱码!,后来不过是将写数据与写命令函数中E=1改到Lcd_data = Lcd_com语句前面,并加大延时才成功的!

millwood0 发表于 2012-5-11 19:14:27

很简单的,你参考按照HD44780数据手册的时序和初始化步骤,绝对没有问题,根本不需要看别人的程序。

absolutely agree.

donglaile 发表于 2012-5-14 01:06:56

我用了4位线的,也是出乱码,我把lcd写命令和数据的函数执行时,关了总中断,然后又开中断就好啦

LT1234567 发表于 2012-5-14 06:49:03

yyande 发表于 2012-5-11 18:45 static/image/common/back.gif
谁说延时足够就成的?一开始我RS、RW、E引脚电平改变时,全部加上延时,而且延时改的好大,结果还是乱码!
...

态度要改改,太冲了,别人也是在帮你

electricit 发表于 2012-5-14 07:48:59

可以参考一下傻孩子的1602库函数,我用了几次,基本上是一次成功

guzhongqi 发表于 2012-5-14 08:07:10

拿来主义要不得,认真研究一下文档,也许比你copy一个代码效率还高点。

mowin 发表于 2012-5-14 08:10:21

LT1234567 发表于 2012-5-14 06:49 static/image/common/back.gif
态度要改改,太冲了,别人也是在帮你

没事,我们已经明白为什么这么难了。
页: [1]
查看完整版本: 发泄一下!4bit数据接口的LCD1602A也太难搞定了!