刚学1602液晶,C51单片机写程序时,写入LCD命令,请问帮忙解释下下面程序中EN=0开始后面的几条语句,谢谢

刚学1602液晶,C51单片机写程序时,写入LCD命令,请问帮忙解释下下面程序中EN=0开始后面的几条语句,谢谢,第1张

因为数据输入需EN引脚的一个高脉冲,其实就是EN 引脚

的一个上升沿

EN=0; //先;拉低

P0=cmd; //准备写入的数据

EN=1;//拉高,产生一个上升沿,写数据到1602

你好:

LCD 1602的响应速度相对于单片机的速度来说是偏慢的。

举个简单的例子,把一桶油通过漏斗向一个瓶子里倒,倒油的速度,即流量必须维持在一定范围之内,倒得太快油会从漏斗顶部溢出来,这样就浪费掉了。我们通过眼睛可以判断并使油面保持在顶面以下,以漏斗的额定流量来倒油,这样效率最高。

而对于单片机来说,1602好比那个瓶子漏斗,写入1602中要显示的数据好比油,如果以单片机的高运行速度向1602写数据就很可能造成上面所说的溢出,比如连续写入abc,结果只显示出了a,这是因为1602的显示芯片每次都要花时间来处理输入的ascii码数据,并把它显示出来。而我们却不容易主动地去控制写入数据的速度,所以1602使用忙信号就有必要了,每次单片机只有检测到忙信号为0,即不忙时,才向1602发数据。比如要显示abc,则这样 *** 作,写a---判忙---写b---判忙---写c---判忙。这样就不会出错了。

这几年推出的lcd,像手机的屏响应速度就比较快,而1602这个古董我用示波器测过,大约40us左右的忙处理时间,而很多速度快的单片机的指令周期都是ns级的。也就是说单片机相当一段时间都在‘等’LCD。

#include<reg52h>

#define uchar unsigned char

#define uint unsigned int

void busy(void)

{ uchar temp=0x80; //初始化temp最高位为1,使得能够进入下面

//的while循环

P0=0xff;(P0就是8个数据口)

rs=0; //设置命令 *** 作

rw=1; //设置读 *** 作

en=1; //使能

delay(100);(这是设的延时函数,不用解释)

while(temp & 0x80) //判忙,一旦表达式为假,即temp最高位为0,

//则表示1602不忙,跳出while

{temp=P0;delay(20);} //把p0的的高位读入temp,延时

en=0; //关闭使能信号

}

每次读写 *** 作都要调用这个busy函数

看门狗最好是在液晶初始化之前关,不然会不停地复位,当然就没有显示了。最好改成

WDTCN=0xde;//看门狗关

WDTCN=0xad;

PORT_Init();

SYSCLK_Init();

lcd_init(); // 对lcd初始化

#include

<reg51h>

#define

uchar

unsigned

char

#define

uint

unsigned

int

uchar

xpos

,ypos;

sbit

key=P2^0;

sbit

rs=P3^0;

sbit

rw=P3^1;

sbit

e=P3^2;

void

nop(){}

void

delay(uint

z)

//延时

{

uint

x,y;

for(x=z;x>0;x--)

for(y=112;y>0;y--);

}

void

check()

//判忙

{

rs=0;

rw=1;

e=0;

P1=0xff;

e=1;

nop();

nop();

while(P1&0x80){}

}

void

wrc(uchar

com)

//写指令

{

check();

rs=0;

rw=0;

e=1;

P1=com;

nop();

e=0;

nop();

}

void

wrd(uchar

date)

//写数据

{

check();

rs=1;

rw=0;

e=1;

P1=date;

nop();

e=0;

nop();

}

void

init()

//初始化

{

wrc(0x38);

wrc(0x01);

wrc(0x0c);

wrc(0x06);

}

void

lcdpos()

//内部数据地址指针定位

{

xpos&=0x01;

ypos&=0x1f;

if(xpos==0x00)

wrc(ypos|0x80);

else

wrc((ypos+0x40)|0x80);

}

void

lcdw(uchar

x,uchar

y,uchar

s)

//在指定的坐标下写字符串

{

xpos=x;

for(ypos=y;ypos<20;ypos++)

{

lcdpos();

wrd(s);

s++;

}

}

void

main()

{

init();

cgram();

while(1)

{

lcdw(0,0,"##########

");

lcdw(1,1,"!!!!!!!!!!

");

lcdw(2,2,"&&&&&&&&&&

");

lcdw(3,3,"$$$$$$$$$$

");

}

}

您好,//以下几条指令是在CE使能端产生一个正脉冲,使LCD响应指令digitalWrite(Enable,LOW); //先强制为低电平

delayMicroseconds(1); //延时1微秒digitalWrite(Enable,HIGH); //然后跳到高delayMicroseconds(1); //延时1微秒digitalWrite(Enable,LOW); //再回到低电平delayMicroseconds(1); //再延时一下}

//LCD数据写入函数void LcdDataWrite(int value) {int i = 0;digitalWrite(DI, HIGH); digitalWrite(RW, LOW); //RW端允许接收数据for (i=DB[0]; i <= DB[7]; i++) { //意思同上一个函数 digitalWrite(i,value &01); value >>= 1;}digitalWrite(Enable,LOW); //意思同上一个函数delayMicroseconds(1);digitalWrite(Enable,HIGH);delayMicroseconds(1);digitalWrite(Enable,LOW);delayMicroseconds(1); }

void setup (void) {int i = 0;for (i=Enable; i <= DI; i++) { //设置端口状态 pinMode(i,OUTPUT);}

//以下是LCD开机初始化的指令,多次执行0x38是确保初始化的成功率delay(100);LcdCommandWrite(0x38); // 8线2行的LCD用0x38 delay(64); LcdCommandWrite(0x38); delay(50); LcdCommandWrite(0x38); delay(20); LcdCommandWrite(0x06); //设定输入方式,增量不移位 delay(20); LcdCommandWrite(0x0E); //忘了 delay(20); LcdCommandWrite(0x01); //忘了

delay(100); LcdCommandWrite(0x80); //开显示,光标不闪 delay(20); }

提醒一下: 一般CE使能端在1602中, 大部分是在脉冲的下降沿生效。

void delay_1ms(uint x)//延时

{ uchar j; //加一变量 uchar i,j;

while((x--)!=0) //改为for(i=0;i<x;i++)

{ for(j=0;j<125;j++) ;

}

}

//检查LCD忙状态

bit lcd_busy() //其实大多数都delayms(5)代替的,尤其是仿真时不能用此函数

{

bit result;

rs=0;

rw=0;

e = 1;

delay_1ms(1);

result = (bit)(data&0x80); //不知data是不是已经#define了

e = 0;

return(result);

}

//写指令数据到LCD

void write1602_com(uchar com)

{while(lcd_busy());

rs = 0;

rw = 0;

e = 0;

delay_1ms(1);

data= com;

delay_1ms(1);

e = 1;

delay_1ms(1);

e = 0;

}

//写显示数据到LCD

void write1602_data(uchar dat)

{while(lcd_busy());

rs = 1;

rw = 0;

e = 0;

data = dat;

delay_1ms(1);

e = 1;

delay_1ms(1);

e = 0;

}

void start(void) //LCD初始化

{delay_1ms(15);

write1602_com(0x38);

delay_1ms(5);

write1602_com(0x38);

delay_1ms(5);

write1602_com(0x38);

delay_1ms(5);

write1602_com(0x0F);//显示开,关光标

delay_1ms(5);

write1602_com(0x06);//移动光标

delay_1ms(5);

write1602_com(0x01);//清除LCD的显示内容

delay_1ms(5);

}

/ 设定显示位置 /

/

void lcd_data(uchar dat) //1602两行地址不是连续的,第二行是0xC0开始的

{

write1602_com(dat|0x80); //数据指针=80+地址变量

}

/

void lcd_data(uchar dat)

{

unsigned char p;

if (pos>=0x10)

p=pos+0xb0;

else

p=pos+0x80;

write1602_com(p);

write1602_data(c);

}

void main()

{

start();

delay_1ms(10);

write1602_com(0x01); //已经清屏,不知道这句的意义

delay_1ms(10);

delay_1ms(5);

lcd_data(0x00);

delay_1ms(5);

for(i=0;i<12;i++)

{

if(i==13){ //建议这句话加上大括号,放到后边,放在这影响不好

while(1);}

write1602_data(table2[i]);//应先写地址再写数据,而你这地址是不变的,最终导致数组数据在

//一个地址上陆续显示,不知道会是啥效果,并且希望你的数组不是const的。

//可以写个连续显示的函数,加指针的

delay_1ms(1);

}

}

我这1602的程序及仿真还有很多,可以向我联系的

51单片机对lcd1602一些基础程序

#include <intrinsh>

#define dataport P1

sbit RS=P2^ 6;

sbit RW=P2^5;

sbit EN=P2^4;

//========================

//=========================

void waitfor() //检测忙信号函数

{

dataport=0xff;

RS=0;RW=1;_nop_(); //选择指令寄存器 读 *** 作

EN=1;_nop_(); //使能 *** 作

while(dataport&0x80); //如果最高位是1 表示1602正忙 原地踏步 忙完后芯片会将高位拉低

EN=0;

}

//======================

void writedata(unsigned char dataw) //写数据到lcm

{

waitfor(); //测忙

RS=1;RW=0;_nop_(); //选择数据寄存器 写 *** 作

dataport=dataw;_nop_(); //将数据送到数据口

EN=1;_nop_();_nop_();EN=0; //使能

}

//==========================

void writecmd(unsigned char cmd) //写命令到lcm

{

waitfor();

RS=0;RW=0;_nop_();

dataport=cmd;_nop_();

EN=1;_nop_();_nop_();EN=0;

}

//===========================

void init(void) // 初始化函数

{

writecmd(0x38); //功能设定 8位数据传输 双行显示

writecmd(0x0c);//显示器开关

writecmd(0x01);//清屏

writecmd(0x06);//字符进入模式 每进入一个字符光标向右移动一格 原有字符不动

//我在刚开始学的时候不知道下一个字符显示在哪 是和AC值有关还是和光标位置有关

//最后摸索出来是只和光标定位有关 现在还是不知道Ac值有什么用

}

//=========================

void location(unsigned char x,unsigned char y) //确实坐标函数

{

unsigned char temp;

temp=x&0x0f; //只要x数据的后四位

if(y){temp=temp|0x40;} //第一行为0 第二行为1 如果y=1则地址加0x40

temp|=0x80; //DDRAM地址的命令DB7为一

writecmd(temp);

}

//==============================

void displyonechar(unsigned char x,unsigned char y,unsigned char dataw) //显示一个字符函数

{

location(x,y);

writedata(dataw);

}

//=======================================

void displylistchar(unsigned char x,unsigned char y,unsigned char p) //显示字符串

{

while(p) //当一个字符型数组读完时P指的为零

{

displyonechar(x,y,(p++));

x++;

}

}

//=====================================================

void writecgram(unsigned char address,unsigned char p) //写CGRAM的数据

{

unsigned char i=8;

writecmd(address); //CGRAM里的地址 初始值0x40 每次加0x80

while(i--)

{

writedata(p);

p++;

}

}

//=====================================================

void displyonecharacter(unsigned char x,unsigned char y,unsigned char address,unsigned char p) //显示一个自定义字符

{

unsigned char i=8;

writecmd(address); //CGRAM里的地址 初始值0x40 每次加0x08

while(i--)

{

writedata(p);

p++;

}

//============================================================

location(x,y); //设定要显示的位置

writedata((address&=0x3f)/0x08); //要从CGRAM中读出数据在1602上显示 搞了半天发现CGRAM里的地址

} //和DDRAM里的地址有上面的转换关系

//========================================================

void displynumber(unsigned char x,unsigned char y,unsigned long num) //显示一个整数

{

unsigned int number[8];

int k,gh;

for(k=0;;k++)

{

(number+k)=(unsigned int)(num%10);//强制类型转换

num=num/10;

if(num==0)break;

}

for(gh=k;gh>=0;gh--)

{

displyonechar(x,y,((number+gh)+48));

x++;

}

}

//字型码

uchar code nin[]={0x08,0x0f,0x12,0x0f,0,0x1f,0x02,0x02};// "年"

uchar code yue[]={0x0f,0x09,0x0f,0x09,0x0f,0x09,0x0b,0x11};// "月"

uchar code ri[]={0x1f,0x11,0x11,0x1f,0x11,0x11,0x11,0x1f};// "日"

显示汉字

displyonecharacter(0,0,0x40,nin);

displyonecharacter(1,0,0x80,yue);

displyonecharacter(1,0,0xc0,ri);

给你一个lcd1602和键盘的程序,你稍加修改就可以用了#include "AT89X51h"

#include "lcd_1602c"

#include "keyc"

main()

{

unsigned char key;

LCD_Initial();

GotoXY(0,0);

Print("wait you press!");

while(1)

{

key=keyscan1();

if(key!=255)

{

GotoXY(0,1);

LCD_Write(1,key/100+0x30);

LCD_Write(1,key%100/10+0x30);

LCD_Write(1,key%10+0x30);

}

}

}

//端口定义

#define DBPort P0 //LCD数据端口

sbit LcdRs = P2^0;

sbit LcdRw = P2^1;

sbit LcdEn = P2^2;

sbit Lcdbf = P0^7; //LCD忙标志 Busy Flagvoid delay(unsigned int t) //延时

{

while(t--);

}void LCD_Wait(void) //读忙状态

{

LcdRs=0;

LcdRw=1;

LcdEn=1;delay(1);LcdEn=0; //下降沿

while(Lcdbf)

{

LcdEn=0;delay(1);LcdEn=1; //仿真才需要此语句,实际硬件中不需要

}

} void LCD_Write(bit style, unsigned char input) //写数据1/命令0

{

LcdRs=style;

LcdRw=0;

DBPort=input;

LcdEn=1;delay(1);LcdEn=0;

LCD_Wait();

}void LCD_Initial(void) //初始化LCD

{

LCD_Write(0,0x38); //8位数据端口,2行显示,57点阵

delay(300);

LCD_Write(0,0x0c); //显示模式

LCD_Write(0,0x01); //清屏

LCD_Write(0,0x06); //输入模式

delay(300);

}void GotoXY(unsigned char x, unsigned char y) //移动光标到指定位置

{

if(y==0) LCD_Write(0,0x80|x);

if(y==1) LCD_Write(0,0xc0|x);

}void Print(unsigned char str) //指定坐标输出字符串

{

while(str) LCD_Write(1,str++);

}

//P1接44键盘

unsigned char keyscan1() //行列法1

{

unsigned char row,rol;

P1=0x0f;

if(P1!=0x0f)

{

delay(10); //延时消抖

if (P1_0==0) row=0;

else if(P1_1==0) row=1;

else if(P1_2==0) row=2;

else if(P1_3==0) row=3;

else return(255); P1=0xf0;

if (P1_4==0) rol=0;

else if(P1_5==0) rol=1;

else if(P1_6==0) rol=2;

else if(P1_7==0) rol=3;

else return(255); while(P1!=0xf0); //等待释放

return(row4+rol);

}

else return(255);

}

以上就是关于刚学1602液晶,C51单片机写程序时,写入LCD命令,请问帮忙解释下下面程序中EN=0开始后面的几条语句,谢谢全部的内容,包括:刚学1602液晶,C51单片机写程序时,写入LCD命令,请问帮忙解释下下面程序中EN=0开始后面的几条语句,谢谢、LCD 1602显示字符,编写程序的时候,为何要弄一个忙信号判断函数这个有什么作用、用C8051F020 写 LCD 1602 液晶程序遇到的问题 液晶始终不显示等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/10107625.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存