最后一节讲了如何用蜂鸣器播放音乐,好玩的MCU ——如何用蜂鸣器播放音乐《敢问路在何方》。本节讲述1602液晶屏的操作,proteus仿真图如下。
102液晶屏有16个针脚,这意味着:
VDD脚为电源脚,1602液晶屏最佳工作电压为5v。
VO引脚用于调整1602显示器的对比度。通常,使用外部电位计来调整偏置信号(当此引脚的电压为0时,对比度最高)。
RS引脚是数据/命令选择端子。当该引脚为高电平时,1602操作数据,而当该引脚为低电平时,1602操作命令。数据是我们希望1602液晶屏显示的具体内容,命令是1602的设置(比如光标是否闪烁等。);
R/W引脚是读写选择端,可以高电平从1602读取数据,低电平写入数据。由于实际应用中我们基本上写1602,所以许多电路板直接将此引脚拉低。如果需要读1602,可以在PCB的实际设计中连接一排引脚,跳帽选择高低电平。
引脚E为使能信号,与1602的读写操作时序相关,产生高电平脉冲。
D0~D7引脚为8位并行数据端口,读写1602的数据非常方便。
602液晶屏为字符液晶屏,内置128个字符的ASCII字符集字体,只能显示ASCII字符,每行16个字符,共两行。如物理图所示,第一行第一列显示“A”,那么怎么写程序做到呢?首先我们需要知道,1602液晶屏内部有一个80B RAM缓冲区,其中第一行地址从00H到0FH,第二行地址从40H到4FH,可以显示。如果超出地址范围,则必须通过屏幕移动指令将其移动到0H到0FH或40H到4FH的范围内。其次,1602液晶屏内部的地址指针从80H开始。回到刚才的问题,我们需要将数据地址指针设置为(80H 00H)并将字符‘A’写入1602 LCD,那么1602 LCD的第一行和第一列将显示字符A。
话虽如此,我们如何将“数据”或“指令”写入1602?这里我们需要了解一下1602液晶屏的时序。时序,通俗地说就是指芯片设置的管脚级状态和时间之间的关系,芯片只有按照这个关系才能完成公式化工作。实际上,只写了1602,写操作的时序图如下所示。
时序图看起来很复杂。其实我们只需要把握几个关键点。根据时序图,
第一步:确定是写指令还是写数据:如果我们想写指令到1602,那么将RS引脚拉低;如果数据写入1602,RS引脚拉高;
第二步:将RW引脚拉低(对于写操作,如果是读操作,将RW引脚拉高);
第三步:DB0~DB7的数据为有效数据。此时,我们将数据或指令分配给DB0 ~ DB7。
第四步:E引脚发出一个最小持续时间为150纳秒的高脉冲,然后E引脚再次拉低。
通过以上四个步骤,1602可以写一次。因为1602时序图的时间是ns级,而AT89C52单片机的指令周期是us级,即使不在程序中增加延时程序,应该也能很好的满足1602的时序要求。但是,为了液晶显示的稳定性,最好增加一个短延迟。您可以在模拟中尝试不同的延迟值。
好的,我们可以从这里开始写程序。让1602液晶显示器的第一行显示“Toutiao:”,第二行显示“迪雅点气”。
#includereg52.h
# include ins . h//包含此头文件是为了调用-nop_()延迟函数(延迟一个机器周期)
#定义uchar无符号字符
#定义uint无符号整数
uchar代码DISPLAY 1[]=' Too条: ';//1602液晶屏第一行显示的内容
uchar代码display 2[]=' di ya Dian qi ';//1602液晶屏第二行显示什么
sbit LCD _ RS=p2^0;
sbit LCD _ rw=p2^1;
sbit LCD _ en=p2^2;
sfr DBPort=0x80//1602 LCD 8位并口D0~D
7连接单片机P0口#define LCD_COMMAND 0 //RS低电平写命令
#define LCD_DATA 1 //RS高电平写数据
void delayxms(uint xms); //延时
void LCD_Write(bit style, uchar input);//1602写操作函数,style值决定是写入命令还是写入数据,input是P0口的值
void LCD_Initial();//1602初始化函数
void delayxms(uint xms)
{
uint i,j = 0;
for(i = xms;i > 0;i--)
for(j = 110;j > 0;j--);
}
//LCD_Write函数的代码,大家要对照着时序图看就明白了。
void LCD_Write(bit style, unsigned char input)
{
lcd_RS = style;//RS高电平表示写数据,低电平表示写命令
lcd_RW = 0; //RW低电平表示写操作
_nop_(); //延时一个机器周期
DBPort = input; //向P0口赋值,也就是向1602的D0~D7这8位并行口赋值
_nop_();
lcd_EN = 1; //E引脚拉高
_nop_();
lcd_EN = 0; //延时之后E引脚再拉低,表示给E引脚一个高脉冲
delayxms(1);//这个延时很关键,保证向1602不断的写数据时E引脚能实现一个高脉冲
}
void LCD_Initial()
{
lcd_EN = 0;//初始化时E引脚拉低,为后续给E引脚高脉冲做好准备
LCD_Write(LCD_COMMAND,0x38); //设置16*2显示
LCD_Write(LCD_COMMAND,0x0C); //设置开显示,光标不显示且不闪烁
LCD_Write(LCD_COMMAND,0x06); //写一个字符后地址指针+1
LCD_Write(LCD_COMMAND,0x01); //显示清零,数据地址指针清零
}
void main(void)
{
uint index1,index2 = 0;//第一行和第二行要显示的内容的序号
LCD_Initial();
LCD_Write(LCD_COMMAND,0x80);//光标定位在第一行第一列
for(index1 = 0;index1 < 9;index1++)
{
LCD_Write(LCD_DATA,DISPLAY1[index1]);//依次写入“Toutiao:”
delayxms(1);//每写完一个字符后延时,使得1602显示稳定
}
LCD_Write(LCD_COMMAND,0x80+0x40);//光标定位在第二行第一列
for(index2 = 0;index2 < 13;index2++)
{
LCD_Write(LCD_DATA,DISPLAY2[index2]);//依次写入““di ya dian qi”
delayxms(1);
}
while(1);//程序死循环,1602静态显示
}
最终的效果如图所示,下一节继续讲下1602的初始化设置方面的内容,以及移入显示的效果。