AVR四线法驱动1602,但是,只要一硬件复位,就出现异常
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!='\0') //取字符串是否结束?
{ lcd_write_data(DData); //显示单个字符
aa++;
}
}
void lcd_1_char(unsigned char data_1_char) //在1602LCD上显示一个1位的整数
{ unsigned char lcd_table;
lcd_table=data_1_char%10; //获得个位的数字
lcd_write_data(lcd_table+0x30); //显示个位
}
//-------------------------------------------------------------------------
void lcd_2_char(unsigned char data_2_char) //在1602LCD上显示一个2位的整数
{ unsigned char lcd_table;
lcd_table=data_2_char/10; //获得十位的数字
lcd_table=data_2_char%10; //获得个位的数字
lcd_write_data(lcd_table+0x30); //显示十位
lcd_write_data(lcd_table+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_3_char(unsigned char data_3_char) //在1602LCD上显示一个3位的整数
{ unsigned char lcd_table;
lcd_table=data_3_char/100; //获得百位的数字
lcd_table=data_3_char%100/10; //获得十位的数字
lcd_table=data_3_char%10; //获得个位的数字
lcd_write_data(lcd_table+0x30); //显示百位
lcd_write_data(lcd_table+0x30); //显示十位
lcd_write_data(lcd_table+0x30); //显示个位
}
//------------------------------------------------------------------------
void lcd_4_char(unsigned char data_4_char) //在1602LCD上显示一个4位的整数
{ unsigned char lcd_table;
lcd_table=data_4_char/1000; //获得千位的数字
lcd_table=data_4_char%1000/100; //获得百位的数字
lcd_table=data_4_char%100/10; //获得十位的数字
lcd_table=data_4_char%10; //获得个位的数字
lcd_write_data(lcd_table+0x30); //显示千位
lcd_write_data(lcd_table+0x30); //显示百位
lcd_write_data(lcd_table+0x30); //显示十位
lcd_write_data(lcd_table+0x30); //显示个位
}
//----------------------------------------------------------------------------------
void lcd_5_char(unsigned int data_char) //在1602LCD上显示一个5位的整数
{ unsigned char lcd_table;
lcd_table=data_char%100000/10000; //获得万位的数字
lcd_table=data_char%10000/1000; //获得千位的数字
lcd_table=data_char%1000/100; //获得百位的数字
lcd_table=data_char%100/10; //获得十位的数字
lcd_table=data_char%10; //获得个位的数字
lcd_write_data(lcd_table+0x30); //显示万位
lcd_write_data(lcd_table+0x30); //显示千位
lcd_write_data(lcd_table+0x30); //显示百位
lcd_write_data(lcd_table+0x30); //显示十位
lcd_write_data(lcd_table+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;
unsigned long aa;
aa=f_data*1000; //保留3位小数
lcd_table= aa/10000 ; //分别获取各位上的数
lcd_table= aa%10000/1000 ;
lcd_table= aa%1000/100 ;
lcd_table= aa%100/10 ;
lcd_table= aa%10 ;
if (lcd_table==0) lcd_write_data(' '); //如果整数部分的十位数是0则不显示(显示空格)
else lcd_write_data(lcd_table+0x30); //显示整数部分的十位数,加上0x30以便直接得到相应的ASCII码去显示
lcd_write_data(lcd_table+0x30); //显示整数部分的个位数
lcd_write_data('.'); //显示小数点"."
lcd_write_data(lcd_table+0x30); //显示小数部分的十分位
lcd_write_data(lcd_table+0x30); //显示小数部分的百分位
lcd_write_data(lcd_table+0x30); //显示小数部分的千分位
}
。h文件
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include <iom16v.h>
#include <macros.h>
#define lcd_data_portPORTB
//一定要用高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_ */ 重新烧写程序也是会有同样的问题 貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33,0x32;
此外,楼主的main最后怎么没while(1)? lcw_swust 发表于 2014-10-15 11:20
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33 ...
没加while(1)也应该能够显示吧。谢谢回复。我试试 lcw_swust 发表于 2014-10-15 11:20
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33 ...
可以额。。。谢谢大神。查不到
lcd_write_com(0x33);
lcd_write_com(0x32);
是什么意思。。。。能给出你查找到这个方法的途径吗 lcw_swust 发表于 2014-10-15 11:20
貌似初始化成四位需要特殊的操作。
不知我的理解对不对,我是这样做的,在0X28指令之前发送两个指令:0X33 ...
真的很开心。很感谢。捣鼓很久了。查找不到方法才最痛苦。 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是怎么来的了。 帮顶,拿分 lcw_swust 发表于 2014-10-15 13:21
这里有个较详细的说明:
http://www.amobbs.com/thread-4344053-1-1.html
总之,注意一点:在没有初始化 ...
恩恩。是我自己的问题。在这个论坛上得来的程序里,前面的初始化就是有两条0x28.。。我写的时候以为多余就拉下了。谢谢无私帮助。这错误太愚蠢了。 lcw_swust 发表于 2014-10-15 13:21
这里有个较详细的说明:
http://www.amobbs.com/thread-4344053-1-1.html
总之,注意一点:在没有初始化 ...
不对。。。两条0x28还是不行,三条0x28的话还需要复位才能正常。
还是0x33。0x32好使。
强迫症,菜鸟。小问题就痛不欲生了。见笑了。谢谢
panhai0101 发表于 2014-10-15 15:57
不对。。。两条0x28还是不行,三条0x28的话还需要复位才能正常。
还是0x33。0x32好使。
强迫症,菜鸟。小 ...
哦,这么怪,多加些延时试试。 lcw_swust 发表于 2014-10-15 16:05
哦,这么怪,多加些延时试试。
对。。。老是出些小小问题。问题,像虱子,捉拿不完 时序不对?这里好像有成功的,看看http://www.amobbs.com/thread-3586540-1-1.html voidInit( void )
{
Write4BitCmd(0x20);
Delay(10);
WriteCmd(0x28);
Delay(10);
WriteCmd(0x28);
WriteCmd(0x06);
WriteCmd(0x0C);
WriteCmd(0x01);
Delay(10);
} 想不到 发表于 2014-10-16 21:57
voidInit( void )
{
Write4BitCmd(0x20);
谢谢。谢谢。无私帮助。 120542121 发表于 2014-10-16 19:46
时序不对?这里好像有成功的,看看http://www.amobbs.com/thread-3586540-1-1.html
对。这个可行。参考了 想不到 发表于 2014-10-16 21:57
voidInit( void )
{
Write4BitCmd(0x20);
Write4BitCmd(0x20);和WriteCmd(0x28);
两个函数不一样哦
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);
} 上传可用的。谢谢大家 想不到 发表于 2014-10-16 23:05
void Write4BitCmd( unsigned char Byte )
{
P1 = Byte&0xf0;
呵呵。。这个没多大懂。。不好意思。。见笑了 120542121 发表于 2014-10-16 19:46
时序不对?这里好像有成功的,看看http://www.amobbs.com/thread-3586540-1-1.html
这个成功的。但是有的时候,只要一移植。。就出错。。。 panhai0101 发表于 2014-10-16 23:24
这个成功的。但是有的时候,只要一移植。。就出错。。。
那一般是你移植的时候时序不对,主要查查演示函数
页:
[1]