搜索
bottom↓
回复: 21

AVR四线法驱动1602,但是,只要一硬件复位,就出现异常

[复制链接]

出0入0汤圆

发表于 2014-10-15 10:49:34 | 显示全部楼层 |阅读模式
AVR四线法驱动1602,但是,只要一硬件复位,就出现异常。
烧写完程序还是正常的。
但是只要一复位,LCD上就多了“π,  t”。再次复位,“π,  t”消失,再次复位,“π,  t”又消失。周而复始。
用的是ICC编译器。
下面贴出程序。
主函数:
#include <iom16v.h>
#include <macros.h>
#include"lcd1602.h"
void main(void)
{
          
        // Port_init();
         lcd_init();
         //lcd_clear();
         lcd_locate(1,4);
         lcd_string("xGL");
         
         
         
}
LCD1602的C文件
#include "lcd1602.h"
void delay_lcd_us(unsigned int xus)/*us延时函数 8*0.125=1us*/
{
    int i,j;
        for(j=0;j<8;j++)
        {
          for (i=0;i<xus;i++)
          NOP();
        }  
}
void delay_lcd_ms(unsigned int xms)/*ms延时函数*/
{
    while(xms--)
    {                          
            unsigned int j;               
        for(j=1;j<=1332;j++);                                            
    }
}
void lcd_init(void) //显示屏初始化函数
{
         //EN_CLR;
         //lcd_clear();
        DDRB = 0xFF;                    //I/O口方向设置
        //LCD_DATA_DDR|=LCD_DATA|LCD_RS|LCD_EN;        //数据口方向为输出
       
        delay_lcd_ms(5);        //上电延时,以使供电稳定
        lcd_write_com(0x28);        //4bit interface,2line,5*7dots
        lcd_write_com(0x08);        //关显示,不显光标,光标不闪烁
        lcd_write_com(0x04);        //写一字符,整屏显示不移动
       
        lcd_clear();            //清屏
        delay_lcd_ms(5);
        lcd_write_com(0x0c);        //开显示,光标、闪烁都关闭
        //lcd_write_com(0x05);        //写一字符,整屏右移
        //lcd_write_com(0x06);        //写一字符,整屏显示不移动
        //lcd_write_com(0x07);        //写一字符,整屏左移
        //lcd_write_com(0x0B);        关闭显示(不显示字符,只有背光亮)       
        //lcd_write_com(0x0D);        //开显示,不显示光标,但光标闪烁
        //lcd_write_com(0x0E);        //开显示,显示光标,但光标不闪烁
        //lcd_write_com(0x0F);        //开显示,光标、闪烁均显示
}
void lcd_en_write(void)        //LCD写时序控制EN端产生一个高电平脉冲,控制LCD写时序
{
    EN_SET;
    delay_lcd_us(5);
    EN_CLR;
}
void lcd_clear(void)//清屏函数
{
  lcd_write_com(0x01);
  delay_lcd_ms(5);
}
void lcd_write_com(unsigned char lcd_com)//写指令函数  
{
  delay_lcd_us(35);
  RS_CLR;
  RW_CLR;
  lcd_data_port&=0X0f;             //清高四位
  lcd_data_port|=(lcd_com&0Xf0);   //写高四位
  lcd_en_write();                  //写入指令数据
  delay_lcd_us(35);
  lcd_com=lcd_com<<4;              //低四位移到高四位
  lcd_data_port&=0X0f;             //清高四位
  lcd_data_port|=(lcd_com&0Xf0);   //写低四位
  lcd_en_write();                  //写入指令数据
}
void lcd_write_data(unsigned char lcd_data)//写数据函数
{
  delay_lcd_us(35);
  RS_SET;
  RW_CLR;
  lcd_data_port&=0X0f;//清高四位
  lcd_data_port|=(lcd_data&0Xf0);//写高四位
  lcd_en_write();//写入数据
  delay_lcd_us(35);
  lcd_data=lcd_data<<4;//低四位移到高四位
  lcd_data_port&=0X0f;//清高四位
  lcd_data_port|=(lcd_data&0Xf0);//写低四位
  lcd_en_write();//写入指数据
}
//----------------- LCD显示定位函数,行、列定位----------------------------
void lcd_locate(unsigned char x,unsigned char y)
{        unsigned char aa;
        if (x==1)         aa=0x80;
        if (x==2)         aa=0x80+0x40;
        lcd_write_com(aa+y-1);   
}
void lcd_string(unsigned char const *DData  )  //在1602LCD上显示一一串字符
{               unsigned char aa;
                                aa=0;
                                while(DData[aa]!='\0')         //取字符串是否结束?
                                {          lcd_write_data(DData[aa]); //显示单个字符
                                        aa++;               
                        }
}
void lcd_1_char(unsigned char data_1_char)         //在1602LCD上显示一个1位的整数
{                unsigned char lcd_table[2];
               
                lcd_table[1]=data_1_char%10;       //获得个位的数字
   
                lcd_write_data(lcd_table[1]+0x30); //显示个位
}
//-------------------------------------------------------------------------
void lcd_2_char(unsigned char data_2_char)      //在1602LCD上显示一个2位的整数
{                unsigned char lcd_table[3];

                lcd_table[1]=data_2_char/10;    //获得十位的数字
                lcd_table[2]=data_2_char%10;    //获得个位的数字
   
                lcd_write_data(lcd_table[1]+0x30); //显示十位     
                lcd_write_data(lcd_table[2]+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_3_char(unsigned char data_3_char)        //在1602LCD上显示一个3位的整数
{                unsigned char lcd_table[4];

                lcd_table[1]=data_3_char/100;       //获得百位的数字
                lcd_table[2]=data_3_char%100/10;    //获得十位的数字
                lcd_table[3]=data_3_char%10;        //获得个位的数字
            
                lcd_write_data(lcd_table[1]+0x30); //显示百位     
                lcd_write_data(lcd_table[2]+0x30); //显示十位     
                lcd_write_data(lcd_table[3]+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_4_char(unsigned char data_4_char)        //在1602LCD上显示一个4位的整数
{                unsigned char lcd_table[5];

                lcd_table[1]=data_4_char/1000;        //获得千位的数字
                lcd_table[2]=data_4_char%1000/100;    //获得百位的数字
                lcd_table[3]=data_4_char%100/10;      //获得十位的数字
                lcd_table[4]=data_4_char%10;          //获得个位的数字

                lcd_write_data(lcd_table[1]+0x30); //显示千位
                lcd_write_data(lcd_table[2]+0x30); //显示百位     
                lcd_write_data(lcd_table[3]+0x30); //显示十位     
                lcd_write_data(lcd_table[4]+0x30); //显示个位
}
//----------------------------------------------------------------------------------
void lcd_5_char(unsigned int data_char)        //在1602LCD上显示一个5位的整数
{                unsigned char lcd_table[9];
                                              
                lcd_table[1]=data_char%100000/10000;        //获得万位的数字
                lcd_table[2]=data_char%10000/1000;          //获得千位的数字
                lcd_table[3]=data_char%1000/100;            //获得百位的数字
                lcd_table[4]=data_char%100/10;              //获得十位的数字
                lcd_table[5]=data_char%10;                  //获得个位的数字

                       
                lcd_write_data(lcd_table[1]+0x30); //显示万位
                lcd_write_data(lcd_table[2]+0x30); //显示千位
                lcd_write_data(lcd_table[3]+0x30); //显示百位     
                lcd_write_data(lcd_table[4]+0x30); //显示十位     
                lcd_write_data(lcd_table[5]+0x30); //显示个位
}
//-------------------------------------------------------
void lcd_char(unsigned int data_char)
{  unsigned int n;
   if(data_char>9999)          n=1;
   else if(data_char>999)  n=2;
   else if(data_char>99)  n=3;
   else if(data_char>9)  n=4;
   else        n=5;
   switch(n)
        {
         case 1:lcd_5_char(data_char); break;
         case 2:lcd_4_char(data_char); break;
         case 3:lcd_3_char(data_char); break;
         case 4:lcd_2_char(data_char); break;
         case 5:lcd_1_char(data_char); break;
         default : break;
        }
}
void lcd_float(float f_data)        //在1602LCD上显示一个小于100、保留3位小数的浮点数
{                unsigned char lcd_table[5];
                unsigned long aa;
                aa=f_data*1000;                   //保留3位小数

                lcd_table[0]= aa/10000 ;                //分别获取各位上的数
                lcd_table[1]= aa%10000/1000 ;
                lcd_table[2]= aa%1000/100 ;
                lcd_table[3]= aa%100/10 ;
                lcd_table[4]= aa%10 ;               
                if (lcd_table[0]==0)         lcd_write_data(' '); //如果整数部分的十位数是0则不显示(显示空格)
                        else lcd_write_data(lcd_table[0]+0x30); //显示整数部分的十位数,加上0x30以便直接得到相应的ASCII码去显示
                lcd_write_data(lcd_table[1]+0x30); //显示整数部分的个位数
                lcd_write_data('.');                            //显示小数点"."         
                lcd_write_data(lcd_table[2]+0x30); //显示小数部分的十分位     
                lcd_write_data(lcd_table[3]+0x30); //显示小数部分的百分位     
                lcd_write_data(lcd_table[4]+0x30); //显示小数部分的千分位
}


。h文件
#ifndef __LCD1602_H__
#define __LCD1602_H__

#include <iom16v.h>
#include <macros.h>

#define lcd_data_port  PORTB
//一定要用高4位
#define LCD_DATA_DDR        DDRB     
#define LCD_DATA                ((1<<PB4)|(1<<PB5)|(1<<PB6)|(1<<PB7))

#define RS_CLR        lcd_data_port&= ~(1 << PB1)
#define RS_SET        lcd_data_port|= (1 << PB1)

#define EN_CLR        lcd_data_port&= ~(1 << PB3)
#define EN_SET        lcd_data_port|= (1 << PB3)

#define LCD_RS                        (1<<PB1)
#define LCD_EN                        (1<<PB3)


#define RW_CLR        lcd_data_port&= ~(1 << PB2)
#define RW_SET        lcd_data_port|= (1 << PB2)

void delay_lcd_us(unsigned int xus);
void delay_lcd_ms(unsigned int xms);

void lcd_init(void);
void lcd_en_write(void);
void lcd_clear(void);
void lcd_write_com(unsigned char lcd_com);   //LCD送命令子函数
void lcd_write_data(unsigned char lcd_data);  //LCD送显示数据子函数
void lcd_locate(unsigned char x,unsigned char y);  //显示定位 x是行,y是列
void lcd_string(unsigned char const *DData);//显示字符串
void lcd_1_char(unsigned char data_1_char);//显示一位整数:
void lcd_2_char(unsigned char data_2_char);//显示二位整数:
void lcd_3_char(unsigned char data_3_char);        //显示三位整数:
void lcd_4_char(unsigned char data_4_char);        //显示四位整数:
void lcd_4_char(unsigned char data_5_char);        //显示五位整数:
void lcd_char(unsigned int data_char);       //显示任意位的整数
void lcd_float(float f_data);        //在1602LCD上显示一个小于100、保留3位小数的浮点数
#endif /* LCD1602_H_ */

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

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

出0入0汤圆

 楼主| 发表于 2014-10-15 11:15:55 | 显示全部楼层
重新烧写程序也是会有同样的问题

出0入0汤圆

发表于 2014-10-15 11:20:49 | 显示全部楼层
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33,0x32;
此外,楼主的main最后怎么没while(1)?

出0入0汤圆

 楼主| 发表于 2014-10-15 11:28:20 | 显示全部楼层
lcw_swust 发表于 2014-10-15 11:20
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33 ...

没加while(1)也应该能够显示吧。谢谢回复。我试试

出0入0汤圆

 楼主| 发表于 2014-10-15 11:40:58 | 显示全部楼层
lcw_swust 发表于 2014-10-15 11:20
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33 ...

可以额。。。谢谢大神。查不到
lcd_write_com(0x33);
lcd_write_com(0x32);
是什么意思。。。。能给出你查找到这个方法的途径吗

出0入0汤圆

 楼主| 发表于 2014-10-15 11:43:13 | 显示全部楼层
lcw_swust 发表于 2014-10-15 11:20
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33 ...

真的很开心。很感谢。捣鼓很久了。查找不到方法才最痛苦。

出0入0汤圆

发表于 2014-10-15 13:21:28 | 显示全部楼层
panhai0101 发表于 2014-10-15 11:40
可以额。。。谢谢大神。查不到
lcd_write_com(0x33);
lcd_write_com(0x32);

这里有个较详细的说明:
http://www.amobbs.com/thread-4344053-1-1.html
总之,注意一点:在没有初始化之前, LCM 1602 默认是 8位操作模式的。
4位相对于8位来说,一条指令变成了两条。
也许3楼我给的两条指令不一定合适,也许一条指令就够了,也就是说也许只需要在0x28指令前再发一个0x28指令。
我都不记得我那两条指令0x33\0x32是怎么来的了。

出0入0汤圆

发表于 2014-10-15 13:50:52 | 显示全部楼层
帮顶,拿分

出0入0汤圆

 楼主| 发表于 2014-10-15 15:40:59 | 显示全部楼层
lcw_swust 发表于 2014-10-15 13:21
这里有个较详细的说明:
http://www.amobbs.com/thread-4344053-1-1.html
总之,注意一点:在没有初始化 ...

恩恩。是我自己的问题。在这个论坛上得来的程序里,前面的初始化就是有两条0x28.。。我写的时候以为多余就拉下了。谢谢无私帮助。这错误太愚蠢了。

出0入0汤圆

 楼主| 发表于 2014-10-15 15:57:16 | 显示全部楼层
lcw_swust 发表于 2014-10-15 13:21
这里有个较详细的说明:
http://www.amobbs.com/thread-4344053-1-1.html
总之,注意一点:在没有初始化 ...

不对。。。两条0x28还是不行,三条0x28的话还需要复位才能正常。
还是0x33。0x32好使。
强迫症,菜鸟。小问题就痛不欲生了。见笑了。谢谢

出0入0汤圆

发表于 2014-10-15 16:05:51 | 显示全部楼层
panhai0101 发表于 2014-10-15 15:57
不对。。。两条0x28还是不行,三条0x28的话还需要复位才能正常。
还是0x33。0x32好使。
强迫症,菜鸟。小 ...

哦,这么怪,多加些延时试试。

出0入0汤圆

 楼主| 发表于 2014-10-15 16:37:14 | 显示全部楼层
lcw_swust 发表于 2014-10-15 16:05
哦,这么怪,多加些延时试试。

对。。。老是出些小小问题。问题,像虱子,捉拿不完

出0入0汤圆

发表于 2014-10-16 19:46:39 | 显示全部楼层
时序不对?这里好像有成功的,看看  http://www.amobbs.com/thread-3586540-1-1.html

出0入0汤圆

发表于 2014-10-16 21:57:11 | 显示全部楼层
void  Init( void )
{
        Write4BitCmd(0x20);
        Delay(10);
        WriteCmd(0x28);
        Delay(10);
        WriteCmd(0x28);
        WriteCmd(0x06);
        WriteCmd(0x0C);
        WriteCmd(0x01);
        Delay(10);
}

出0入0汤圆

 楼主| 发表于 2014-10-16 22:54:13 | 显示全部楼层
想不到 发表于 2014-10-16 21:57
void  Init( void )
{
        Write4BitCmd(0x20);

谢谢。谢谢。无私帮助。

出0入0汤圆

 楼主| 发表于 2014-10-16 23:01:54 | 显示全部楼层
120542121 发表于 2014-10-16 19:46
时序不对?这里好像有成功的,看看  http://www.amobbs.com/thread-3586540-1-1.html

对。这个可行。参考了

出0入0汤圆

 楼主| 发表于 2014-10-16 23:02:35 | 显示全部楼层
想不到 发表于 2014-10-16 21:57
void  Init( void )
{
        Write4BitCmd(0x20);

Write4BitCmd(0x20);和WriteCmd(0x28);
  两个函数不一样哦     
        

出0入0汤圆

发表于 2014-10-16 23:05:48 | 显示全部楼层
void Write4BitCmd( unsigned char Byte )
{
        P1 = Byte&0xf0;
        RS = 0;
        RW = 0;
        E  = 1;
        _nop_();
        E  = 0;
        _nop_();
}
       
void WriteCmd( unsigned char CmdByte )
{
        Delay(50);
        Write4BitCmd(CmdByte&0xf0);
        Write4BitCmd(CmdByte<<4);
}

出0入0汤圆

 楼主| 发表于 2014-10-16 23:14:34 | 显示全部楼层
上传可用的。谢谢大家

本帖子中包含更多资源

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

x

出0入0汤圆

 楼主| 发表于 2014-10-16 23:16:25 | 显示全部楼层
想不到 发表于 2014-10-16 23:05
void Write4BitCmd( unsigned char Byte )
{
        P1 = Byte&0xf0;

呵呵。。这个没多大懂。。不好意思。。见笑了

出0入0汤圆

 楼主| 发表于 2014-10-16 23:24:19 | 显示全部楼层
120542121 发表于 2014-10-16 19:46
时序不对?这里好像有成功的,看看  http://www.amobbs.com/thread-3586540-1-1.html

这个成功的。但是有的时候,只要一移植。。就出错。。。

出0入0汤圆

发表于 2014-10-21 22:09:27 | 显示全部楼层
panhai0101 发表于 2014-10-16 23:24
这个成功的。但是有的时候,只要一移植。。就出错。。。

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

本版积分规则

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

GMT+8, 2024-7-23 17:18

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

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