一、LCD1602的使用
从上图可知,不是所有的地址都可以直接用来显示字符数据,只有第一行中的 00-0F,第二行中的 40-4F 才能显示,其他地址只能用于存储。
从上图可以看到,以上给的时间参数全部是 ns 级别的,而 51 单片机的机器周期是 1us,指令周期是 2-4 个机器周期,所以即便在程序里不加延时程序,也可以很好的配合 LCD1602 的时序要求了。
LCD1602 操作步骤如下所示:
(1)初始化
(2)写命令(RS=L),设置显示坐标
(3)写数据(RS=H)
在此,不需要读出它的数据的状态或者数据本身。所以只需要看两个写时序:
① 当要写指令字,设置 LCD1602 的工作方式时:需要把 RS 置为低电平,RW置为低电平,然后将数据送到数据口 D0~D7,最后 E 引脚一个高脉冲将数据写入。
② 当要写入数据字,在 1602 上实现显示时:需要把 RS 置为高电平,RW 置为低电平,然后将数据送到数据口 D0~D7,最后 E 引脚一个高脉冲将数据写入。
写指令和写数据,差别仅仅在于 RS 的电平不一样而已。
二、硬件设计
这里原理图是使用的 8 位 LCD1602 接口设计,从上图中可以看出,该电路是并不是独立的, LCD1602 的 8 位数据口 DB0-DB7与单片机的 P00-P07 管脚连接,LCD1602 的 RS、RW、E 脚与单片机的 P26、P25、P27 管脚连接。RJ1 是一个电位器,用来调节 LCD1602 对比度即显示亮度。
1、编写lcd.h
#ifndef _lcd_H
#define _lcd_H
#include "public.h"
//#define LCD1602_4PINS
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
void LCD_WriteCmd(u8 cmd);
void LCD_WriteData(u8 dat);
void LcdInit();
void LCD_Clear();
void LCD_Dispstring(u8 x,u8 line,u8 *p);
#endif
2、编写lcd.c
#include "lcd.h"
void Lcd1602_Delay1ms(uint c)
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
#ifndef LCD1602_4PINS
void LCD_WriteCmd(uchar com)
{
LCD1602_E = 0;
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DATAPINS = com;
Lcd1602_Delay1ms(1);
LCD1602_E = 1;
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#else
void LCD_WriteCmd(uchar com)
{
LCD1602_E = 0;
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DATAPINS = com;
Lcd1602_Delay1ms(1);
LCD1602_E = 1;
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
// Lcd1602_Delay1ms(1);
LCD1602_DATAPINS = com << 4;
Lcd1602_Delay1ms(1);
LCD1602_E = 1;
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
#ifndef LCD1602_4PINS
void LCD_WriteData(uchar dat)
{
LCD1602_E = 0;
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DATAPINS = dat;
Lcd1602_Delay1ms(1);
LCD1602_E = 1;
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#else
void LCD_WriteData(uchar dat)
{
LCD1602_E = 0;
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DATAPINS = dat;
Lcd1602_Delay1ms(1);
LCD1602_E = 1;
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4;
Lcd1602_Delay1ms(1);
LCD1602_E = 1;
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
#ifndef LCD1602_4PINS
void LcdInit()
{
LCD_WriteCmd(0x38);
LCD_WriteCmd(0x0c);
LCD_WriteCmd(0x06);
LCD_WriteCmd(0x01);
LCD_WriteCmd(0x80);
}
#else
void LCD_Init()
{
LCD_WriteCmd(0x32);
LCD_WriteCmd(0x28);
LCD_WriteCmd(0x0c);
LCD_WriteCmd(0x06);
LCD_WriteCmd(0x01);
LCD_WriteCmd(0x80);
}
#endif
void LCD_Clear()
{
LCD_WriteCmd(0x01);
LCD_WriteCmd(0x80);
}
void LCD_Dispstring(u8 x,u8 line,u8 *p)
{
char i=0;
if(line<1)
{
while(*p!='\0')
{
if(i<16-x)
{
LCD_WriteCmd(0x80+i+x);
}
else
{
LCD_WriteCmd(0x40+0x80+i+x-16);
}
LCD_WriteData(*p);
p++;
i++;
}
}
else
{
while(*p!='\0')
{
if(i<16-x)
{
LCD_WriteCmd(0x80+0x40+i+x);
}
else
{
LCD_WriteCmd(0x80+i+x-16);
}
LCD_WriteData(*p);
p++;
i++;
}
}
}
3、编写main.c
#include "reg52.h"
#include "lcd.h"
typedef unsigned int ui;
typedef unsigned char uc;
uc disp[]="love story";
void main()
{
ui i;
LcdInit();
for(i=0;i<16;i++)
{
LCD_WriteData(disp[i]);
}
while(1);
}
注:
在程序中我们可以看到如下程序框架:
#ifndef LCD1602_4PINS
...程序段 1...
#else
...程序段 2...
#endif
这个是条件选择编译结构,意思是:如果没有定义 LCD1602_4PINS 则执行程序段 1,否则执行程序段 2。