51单片机使用 8线/4线/PCF8574(I2C) 驱动 LCD1602



一、8线驱动

接线图(共需要 8 + 2 = 10 个 IO 控制)

在这里插入图片描述

#define  LCD1602_Port P2		//LCD1602数据端口

//*****控制端口定义*****//
//RW 接地,只写不读
sbit LcdRs = P3 ^ 3;
sbit LcdEn = P3 ^ 2;

void LCD1602_Write(uchar style, uchar input)
{
	LcdEn = 0;
	if(style == 0){
		LcdRs = 0;		//命令'0'
	}
	else{
		LcdRs = 1;		//数据'1'
	}
	Delay1ms();
	LCD1602_Port = input;
	Delay1ms();
	LcdEn = 1;
	Delay1ms();
	LcdEn = 0;
	Delay1ms();
}

void LCD1602_Initial()
{
	LcdEn = 0;
	LCD1602_Write(0, 0x38);   //8位数据端口,2行显示,5*7点阵
	LCD1602_Write(0, 0x0c);	 //开启显示, 无光标
	LCD1602_Write(0, 0x06);	 //AC递增, 画面不动
	LCD1602_Write(0, 0x01);   //清屏
	Delay10ms();
}

void LCD1602_GotoXY(uchar x, uchar y)	 //X为显示指针的位置,即为各行的第几个位置,Y选行
{
	if(x == 0)
		LCD1602_Write(0, 0x80 + y);

	if(x == 1)
		LCD1602_Write(0, (0x80 + 0x40 + y));
}

void LCD1602_Display_NoXY(uchar *str)	//向LCD写入字符串
{
	while(*str != '\0') {
		LCD1602_Write(1, *str);
		str++;
	}
}

void main(void)
{
	LCD1602_Initial();
	Delay10ms();
	LCD1602_GotoXY(0, 2);
	LCD1602_Display_NoXY("Hello Word!");

	while(1);
}

二、4线驱动

接线图(共需要 4 + 2 = 6 个 IO 控制)
在这里插入图片描述

#define LCD_Port P0				//数据口

sbit RS = P3 ^ 5;
sbit EN = P3 ^ 4;

uchar table1[] = "LCD1602A DISPLAY";  //16
uchar table2[] = "By wxhntmy";//10

//LCD使能
void lcd_en_enable()
{
	EN = 1;
	Delay100us();
	EN = 0;
	Delay100us();
}

//写命令
void LCD_Write_Com(uchar cmd)
{
	uchar high, low, temp;
	high = cmd & 0xF0;
	low = (cmd << 4) & 0xF0;

	EN = 0;
	Delay100us();
	RS = 0;
	temp = LCD_Port & 0x0F;	//保持P0口低四位不变
	LCD_Port = temp | high;	//写入命令高四位
	Delay100us();
	lcd_en_enable();

	temp = LCD_Port & 0x0F;	//保持P0口低四位不变
	LCD_Port = temp | low;	//写入命令低四位
	Delay100us();
	lcd_en_enable();
}

//写数据
void LCD_Write_Data(uchar dat)
{
	uchar high, low, temp;
	high = dat & 0xF0;
	low = (dat << 4) & 0xF0;

	EN = 0;
	Delay100us();
	RS = 1;
	temp = LCD_Port & 0x0F;	//保持P0口低四位不变
	LCD_Port = temp | high;	//写入数据高四位
	Delay100us();
	lcd_en_enable();

	temp = LCD_Port & 0x0F;	//保持P0口低四位不变
	LCD_Port = temp | low;	//写入数据低四位
	Delay100us();
	lcd_en_enable();
}
//X为显示指针的位置,即为各行的第几个位置,Y选行
void LCD1602_GotoXY(uchar x, uchar y)
{
	if(x == 0)
		LCD_Write_Com(0x80 + y);

	if(x == 1)
		LCD_Write_Com(0x80 + 0x40 + y);
}
//向LCD写入字符串
void LCD1602_Display_NoXY(uchar *str)
{
	while(*str != '\0') {
		LCD_Write_Data(*str);
		str++;
	}
}

//初始化
void LCD_Init()
{
	Delay200ms();//等待供电稳定

	LCD_Write_Com(0x30);
	Delay5ms();
	LCD_Write_Com(0x30);
	Delay5ms();
	LCD_Write_Com(0x30);
	Delay1ms();
	LCD_Write_Com(0x20);
	Delay1ms();
	LCD_Write_Com(0x28);//设置4位格式,2行,5x7
	lcd_en_enable();
	LCD_Write_Com(0x28);//设置4位格式,2行,5x7
	LCD_Write_Com(0x0C);//整体显示,关光标,不闪烁
	LCD_Write_Com(0x06);//设定输入方式,增量不移位
	LCD_Write_Com(0x01);//清除屏幕显示
	Delay10ms();
}


//主函数
void main(void)
{
	LCD_Init();		//液晶屏初始化

	//显示字符串
	LCD1602_GotoXY(0, 0);
	LCD1602_Display_NoXY(table1);

	LCD1602_GotoXY(1, 3);
	LCD1602_Display_NoXY(table2);

	while(1);
}

三、PCF8574(I2C) 驱动

1、PCF8574 介绍

  • 操作电压 2.5~6.0V
  • 低备用电流(≤10μA)
  • I2C 并行口扩展电路
  • 开漏中断输出
  • I2C 总线 实现 8 位远程 I/O 口
  • 与大多数 MCU 兼容
  • 口输出锁存,具有大电流驱动能力,可直接驱动 LED
  • 通过 3 个硬件地址引脚可寻址 8 个器件(PCF8574A 可多达 16 个)
  • DIP16,SO16 或 SSOP20 形式封装

        PCF8574 是 CMOS 电路。它通过两条双向总线(I2C)可使大多数 MCU 实现远程 I/O 口扩展。该器件包含一个 8 位准双向口和一个 I2C 总线接口。PCF8574 电流消耗很低,且口输出锁存具有大电流驱动能力,可直接驱动 LED。它还带有一条中断接线(INT)可与 MCU 的中断逻辑相连。通过 INT 发送中断信号,远端 I/O 口不必经过 I2C 总线通信就可通知 MCU 是否有数据从端口输入。这意味着 PCF8574可以作为一个单被控器。
        PCF8574 和 PCF8574A 的唯一区别仅在于器件地址不相同。

PCF8574 和 PCF8574A 的从地址:
在这里插入图片描述

PCA8574 地址图(A2 A1 A0 悬空默认为1):
在这里插入图片描述
PCA8574A 地址图(A2 A1 A0 悬空默认为1):
在这里插入图片描述

写模式(IO 用作输出)

        I2C 主机写入地址后,接着写入八位数据,这八位数据表示 PCF8574 八个 IO 的输出电平,例如写入的数据第 6 位为 1,则 PCF8574 的 P5 口输出高电平。

        I2C 主机写一字节数据流程:start > write_write_address > master_receive_ack > write_data > master_receive_ack > stop
在这里插入图片描述
读模式(IO 用作输入)

        I2C 主机写入地址后,接着读取八位数据,这八位数据表示 PCF8574 八个 IO 的输入电平,例如读取的数据第 6 位为 1,则 PCF8574 的 P5 口输入为高电平。

        I2C 主机读一字节数据流程:start > write_read_address > master_receive_ack > receive_data > master_send_nack > stop
在这里插入图片描述

2、接线图

在这里插入图片描述

3、示例代码

#define	LCD_I2C_ADDRESS		0x27 << 1	//I2C地址,需要左移一位
#define BACKLIGHT			0x08		//PCF8574 P3口,背光开关
#define En 					0x04		//使能位,PCF8574 P2口
#define Rw 					0x02		//读/写位,PCF8574 P1口
#define Rs 					0x01		//选择位,PCF8574 P0口

#define setbit(x,y)  x |= (1 << y)		//指定的某一位数置1
#define clrbit(x,y)  x &= ~(1 << y)		//指定的某一位数置0
#define reversebit(x,y)  x ^= (1 << y)	//指定的某一位数取反

uchar table1[] = "LCD1602A PCF8574";  //16
uchar table2[] = "By wxhntmy";//10

//i2c写一字节数据
void i2c_write_char(uchar address, uchar dat)
{
	start();
	send_data(address);
	recv_ack();
	send_data(dat);
	recv_ack();
	stop();
}
//i2c读一字节数据
uchar i2c_read_char(uchar address)
{
	uchar dat;
	start();
	send_data(address + 1);
	recv_ack();
	dat = recv_data();
	send_nack();
	stop();
	return dat;
}

//LCD使能
void lcd_en_enable(uchar value)
{
	i2c_write_char(LCD_I2C_ADDRESS, value | En);	//EN = 1
	Delay100us();
	clrbit(value, 2);
	i2c_write_char(LCD_I2C_ADDRESS, value);	//EN = 0
	Delay100us();
}

//lcd写命令/数据,mode=0命令,mode=1数据
void lcd_write(uchar mode, uchar cmd)
{
	uchar high, low;
	uchar temp;
	high = cmd & 0xF0 | BACKLIGHT;			//高四位
	low = (cmd << 4) & 0xF0 | BACKLIGHT;	//低四位变高四位

	temp = i2c_read_char(LCD_I2C_ADDRESS);		//获取引脚电平
	temp = temp & 0xF0;		//保留高四位电平

	i2c_write_char(LCD_I2C_ADDRESS, temp | BACKLIGHT);//en = 0,写引脚时保持高四位电平不变
	Delay100us();

	if(mode == 0) {
		i2c_write_char(LCD_I2C_ADDRESS, temp | BACKLIGHT);//rs = 0,写引脚时保持高四位电平不变
	} else {
		i2c_write_char(LCD_I2C_ADDRESS, temp | Rs | BACKLIGHT);//rs = 1,写引脚时保持高四位电平不变
	}

	temp = i2c_read_char(LCD_I2C_ADDRESS);		//获取引脚电平
	temp = temp & 0x0F;		//保留低四位电平
	
	i2c_write_char(LCD_I2C_ADDRESS, high | temp);//写高四位数据时保持低四位引脚电平不变
	Delay100us();
	lcd_en_enable(high | temp);

	i2c_write_char(LCD_I2C_ADDRESS, low | temp);//写高四位数据时保持低四位引脚电平不变
	Delay100us();
	lcd_en_enable(low | temp);

}
//lcd初始化
void lcd_init()
{
	uchar temp;
	Delay50ms();
	Delay50ms();
	Delay50ms();
	Delay50ms();//等待供电稳定
	lcd_write(0, 0x30);
	Delay5ms();
	lcd_write(0, 0x30);
	Delay5ms();
	lcd_write(0, 0x30);
	Delay1ms();
	lcd_write(0, 0x20);
	Delay1ms();

	//用四线时,1602的初始化只需要高四位数据就可以完成,在初始化完成之后必须再传入四位数据,
	//执行完“lcd_write(0, 0x28);”之后液晶已经初始化,其实在执行了一半的时候就已经初始化完成,
	//此时又传入了四位数据(一个写语句会传入8位数据),这时候如果直接写数据的话,就会形成乱码,所以需要两次功能性初始化。
	lcd_write(0, 0x28);   //4位数据端口,2行显示,5*7点阵
	temp = i2c_read_char(LCD_I2C_ADDRESS);		//获取引脚电平
	lcd_en_enable(temp);

	lcd_write(0, 0x28);   //4位数据端口,2行显示,5*7点阵
	lcd_write(0, 0x0c);	 //开启显示, 无光标
	lcd_write(0, 0x06);	 //AC递增, 画面不动
	lcd_write(0, 0x01);   //清屏
	Delay50ms();
}
//Y为显示指针的位置,即为各行的第几个位置,X选行
//Y:0-15
//X:0-1
void LCD1602_GotoXY(uchar x, uchar y)
{
	if(x == 0)
		lcd_write(0, 0x80 + y);

	if(x == 1)
		lcd_write(0, (0x80 + 0x40 + y));
}
//向LCD写入字符串
void LCD1602_Display_NoXY(uchar *str)
{
	while(*str != '\0') {
		lcd_write(1, *str);
		str++;
	}
}

void main()
{
	init_i2c();

	lcd_init();
	
	//显示字符串
	LCD1602_GotoXY(0, 0);
	LCD1602_Display_NoXY(table1);

	LCD1602_GotoXY(1, 3);
	LCD1602_Display_NoXY(table2);

	while(1)}
  • 15
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菠萝蚊鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值