首先是LM016L液晶显示屏的简单介绍:(啊!其实我一直没有搞懂!)
LM016L的结构:LM016L 液晶模块采用 HD44780控制器。HD44780具有简单而功能较强的指令集,可以实现字符移动、闪烁等功能。LM016L与单片机 MCU (Microcontroller Unit)通讯可采用8位或者4位并行传输两种方式。HD44780控制器由两个8位寄存器、指令寄存器(IR)和数据寄存器(DR)、忙标志(BF)、显示数据RAM( DDRAM)、字符发生器ROM(CGROM)、字符发生器RAM (CGRAM)、地址计数器(AC)。IR用于寄存指令码,只能写入不能读出;DR用于寄存数据,数据由内部操作自动写入DDRAM和CGRAM,或者暂存从 DDRAM和 CGRAM读出的数据;BF为1时,液晶模块处于内部处理模式,不响应外部操作指令和接受数据;DDRAM用来存储显示的字符,能存储80个字符码;CGROM由 8位字符码生成57点阵字符160种和510点阵字符32种,CGRAM是为用户编写特殊字符留用的,它的容量仅64字节,可以自定义8个57点阵字符或者4个510点阵字符;AC可以存储DDRAM和 CGRAM的地址,如果地址码随指令写入IR,则IR自动把地址码装入AC,同时选择DDRAM或CGRAM单元。
LM016L的控制指令:通过对HD44780写入控制指令,HD44780产生显示驱动信号来驱动LMO16L。HD44780的控制指令主要有:清除显示(Clear Display)、地址归位 (Return Home)、输入模式设定(Entry Mode Set)、显示开/关控制(Display On/Off Control)、功能设定(Function Set)、设定CGRAM的地址(Set CGRAM Address)、设定 DDRAM 的地址(Set DDRAM Address)、写 DDRAM/CGRAM (Write Date to DDRAMICGRAM)、读忙标志和地址(Read Busy Flagand Address)以及从 DDRAM和 CGRAM 中读数据(Read Date from DDRAM/CGRAM)。
具体指令解析,可以参见:LM016L指令解析
LM016L的DDRAM地址:
LM016L实际就是1602LCD,即一行可以显示16个字,可以显示两行,第一行起始地址是0x00,第二行起始地址是0x40;实际要向相应地址内写入内容的话,需要先将光标定位到相应位置——写入指令0x80+0x00或者0x80+0x40,对应单元写入数据之后AC会自动+1,另外在初始化的时候可以设置光标自动右移;
代码中包含LM016L读指令(检查忙信号)、写指令、写数据、初始化:
#include
#include
#define NOP _nop_()
#define noACK 0
#define ACK 1
#define uint unsigned int
#define uchar unsigned char
sbit E=P3^0; //LCD使能端口定义
sbit RW=P3^1; //LCD读写使能端口定义
sbit RS=P3^2; //LCD数据/命令选择方式端口定义
sbit bflag=P2^7; //LCD忙指示端口,高电平为忙
void busy_1602() //判忙LCD忙闲?
{
do
{
P2=0xff;
RS=0; //RS=0,RW=1时才可读忙信号
RW=1;
E=0;
_nop_();
//读取P2口数据,读取bflag
E=1;
}while(bflag); //当其值为0时,表示不忙,才可以接收命令或者数据信号
}
void wreg_1602(unsigned char com) //函数功能:写指令函数
{
busy_1602();
RS=0; //当RS=0,RW=0时,表明写入的是命令
RW=0;
E=1;
P2=com; //当使能由高到低时,LCD执行相应命令
E=0;
}
void wdata_1602(unsigned char dat) //函数功能:写数据函数
{
busy_1602();
RS=1; //当RS=1,RW=0时,表明写入的是数据
RW=0;
E=1;
P2=dat; //当使能由高到低时,LCD执行相应命令
E=0;
}
void lcd_pos(unsigned char pos) //函数功能:指定数据显示地址
{
wreg_1602(pos | 0x80); //命令8,最高位必须为1,第一行最左边地址为0x00;第二行为0x40 指令8
}
void init_1602() //函数功能:设置LCD_1602的开显示 光标不闪烁等的功能
{
wreg_1602(0x38); //指令6,8位数据总线,双行显示,每位采用5*7点阵 指令6
wreg_1602(0x08); //指令4,关显示,关光标,无闪烁 指令4
wreg_1602(0x06); //指令3,光标自动右移,文字不移动 指令3
wreg_1602(0x01); //指令1,清显示 指令1
wreg_1602(0x0c); //指令4,开显示 指令4
}
void main(void)
{
init_1602();
while(1)
{
lcd_pos(0x00+0x04); //第一行
//按道理第一行起始地址是0x00就ok
//但是考虑让显示居中一下,就从中间某个位置开始,就+0x04,即前面没写
wdata_1602('L');
wdata_1602('M');
wdata_1602('0');
wdata_1602('1');
wdata_1602('6');
wdata_1602('L');
wdata_1602('1');
lcd_pos(0x40+0x04); //第二行
//+0x04同第一行解释
wdata_1602('L');
wdata_1602('M');
wdata_1602('0');
wdata_1602('1');
wdata_1602('6');
wdata_1602('L');
wdata_1602('2');
}
}
此工程是老师给出的示例工程,在此只是记录自己的学习过程,整理笔记,若有不妥,戳我戳我!俺改!