搜索
bottom↓
回复: 19

发泄一下!4bit数据接口的LCD1602A也太难搞定了!

[复制链接]

出0入0汤圆

发表于 2012-5-10 23:23:17 | 显示全部楼层 |阅读模式
准备搞个自行车里程速度表,因为准备添加的功能过多,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[ListLength]>0x20) //若到达字串尾则退出
        {
                if (X <= 0xF) //X坐标应小于0xF
                {
                        DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
                        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);

       
       
       
       
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2012-5-10 23:26:30 | 显示全部楼层
因为才搞定LCD1602,有些垃圾代码没有清理,还有部分代码没有注释,大家见谅!

出0入0汤圆

发表于 2012-5-10 23:37:33 | 显示全部楼层
初始化时的几个延时搞定就ok了,没那么恐怖

出0入25汤圆

发表于 2012-5-10 23:56:08 | 显示全部楼层
同解,初始化的延时适当加长些,很容易成功的。

出0入0汤圆

发表于 2012-5-11 00:03:51 | 显示全部楼层
C8051F330 啊, 都不是普通51, 当然要适当加延时拉

出0入0汤圆

发表于 2012-5-11 00:34:32 | 显示全部楼层
印象中C8051F的单片机是普通51的12倍吧。

出0入85汤圆

发表于 2012-5-11 00:41:47 | 显示全部楼层
本帖最后由 bluefeel 于 2012-5-11 00:47 编辑

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

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-5-11 01:13:47 | 显示全部楼层
7楼正解!           

出0入0汤圆

发表于 2012-5-11 05:15:10 | 显示全部楼层
这个我都搅了一阵子才搅掂!

出0入0汤圆

发表于 2012-5-11 07:56:51 | 显示全部楼层
7楼对。只要严格按照时序做,一点都不难,也不会出现奇奇怪怪的问题。

出0入0汤圆

发表于 2012-5-11 10:25:22 | 显示全部楼层
330驱动1602的4线方式很简单呀,时序主要就是延迟,足够大的延迟是关键。这部分不难。

出0入0汤圆

发表于 2012-5-11 14:12:22 | 显示全部楼层
很容易啊,坛里的高手可以用一个IO口搞定

出0入0汤圆

发表于 2012-5-11 15:56:29 | 显示全部楼层
  搜索 一下 2个 io驱动 1602 cowboy 出品的

出0入0汤圆

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

出0入0汤圆

发表于 2012-5-11 19:14:27 | 显示全部楼层
很简单的,你参考按照HD44780数据手册的时序和初始化步骤,绝对没有问题,根本不需要看别人的程序。


absolutely agree.

出0入0汤圆

发表于 2012-5-14 01:06:56 来自手机 | 显示全部楼层
我用了4位线的,也是出乱码,我把lcd写命令和数据的函数执行时,关了总中断,然后又开中断就好啦

出0入0汤圆

发表于 2012-5-14 06:49:03 | 显示全部楼层
yyande 发表于 2012-5-11 18:45
谁说延时足够就成的?一开始我RS、RW、E引脚电平改变时,全部加上延时,而且延时改的好大,结果还是乱码!
...

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

出0入4汤圆

发表于 2012-5-14 07:48:59 | 显示全部楼层
可以参考一下傻孩子的1602库函数,我用了几次,基本上是一次成功

出0入0汤圆

发表于 2012-5-14 08:07:10 | 显示全部楼层
拿来主义要不得,认真研究一下文档,也许比你copy一个代码效率还高点。

出0入0汤圆

发表于 2012-5-14 08:10:21 | 显示全部楼层
LT1234567 发表于 2012-5-14 06:49
态度要改改,太冲了,别人也是在帮你

没事,我们已经明白为什么这么难了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 02:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表