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

2020-02-05 09:24发布

准备搞个自行车里程速度表,因为准备添加的功能过多,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);

       
       
       
       
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
yyande
1楼-- · 2020-02-05 12:13
 精彩回答 2  元偷偷看……
www1519
2楼-- · 2020-02-05 14:10
初始化时的几个延时搞定就ok了,没那么恐怖
hecat
3楼-- · 2020-02-05 15:03
同解,初始化的延时适当加长些,很容易成功的。
90999
4楼-- · 2020-02-05 19:39
C8051F330 啊, 都不是普通51, 当然要适当加延时拉
無智
5楼-- · 2020-02-06 01:21
印象中C8051F的单片机是普通51的12倍吧。
bluefeel
6楼-- · 2020-02-06 02:54
 精彩回答 2  元偷偷看……

一周热门 更多>