LCD1602模块-带IIC转接板
LCD1602简介
写时序
读时序
指令表

字符表
IIC转接板-PCF8574、PCF8574T
IIC地址
IIC写时序
IIC读时序
示例代码
iic.c
#include "iic.h"
// IIC总线的延时函数,根据实际情况调整时间
void IIC_Delay()
{
uint8_t i;
/*
下面的时间是通过逻辑分析仪测试得到的。
工作条件:CPU主频72MHz ,MDK编译环境,1级优化
循环次数为10时,SCL频率 = 205KHz
循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
*/
for (i = 0; i < 10; i++);
}
// IIC总线的初始化函数
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
//开启时钟
IIC_SDA_GPIO_CLK_ENABLE();
IIC_SCL_GPIO_CLK_ENABLE();
// 配置SDA、SCL引脚为开漏输出
GPIO_InitStruct.Pin = SDA_GPIO_PIN | SCL_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//注意:如果不在同个port,需要初始化两次
HAL_GPIO_Init(SDA_GPIO_PORT, &GPIO_InitStruct);
// 初始化时将SDA、SCL置高
IIC_SDA_1();
IIC_SCL_1();
}
// IIC总线的起始信号函数
void IIC_Start(void)
{
// 先将SDA、SCL置高
IIC_SDA_1();
IIC_SCL_1();
IIC_Delay();
// 拉低SDA,开始起始信号
IIC_SDA_0();
IIC_Delay();
// 拉低SCL,开始传输数据
IIC_SCL_0();
IIC_Delay();
}
// IIC总线的停止信号函数
void IIC_Stop(void)
{
// 先将SDA、SCL置低
IIC_SDA_0();
IIC_SCL_1();
IIC_Delay();
// 拉高SCL,传输结束
IIC_SDA_1();
}
//发送数据
void IIC_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位 bit7 */
for (i = 0; i < 8; i++) {
if (_ucByte & 0x80) {
IIC_SDA_1();
}else{
IIC_SDA_0();
}
IIC_Delay();
IIC_SCL_1();
IIC_Delay();
IIC_SCL_0();
if (i == 7) {
IIC_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个 bit */
IIC_Delay();
}
}
//接收数据
uint8_t IIC_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 读到第 1 个 bit 为数据的 bit7 */
value = 0;
for (i = 0; i < 8; i++) {
value <<= 1;
IIC_SCL_1();
IIC_Delay();
if (IIC_SDA_READ()) {
value++;
}
IIC_SCL_0();
IIC_Delay();
}
return value;
}
//等待从设备响应
uint8_t IIC_WaitAck(void)
{
uint8_t re;
IIC_SDA_1(); /* CPU释放SDA总线 */
IIC_Delay();
IIC_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
IIC_Delay();
if (IIC_SDA_READ()) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
IIC_SCL_0();
IIC_Delay();
return re;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_Ack(void)
{
IIC_SDA_0(); /* CPU驱动SDA = 0 */
IIC_Delay();
IIC_SCL_1(); /* CPU产生1个时钟 */
IIC_Delay();
IIC_SCL_0();
IIC_Delay();
IIC_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void IIC_NAck(void)
{
IIC_SDA_1(); /* CPU驱动SDA = 1 */
IIC_Delay();
IIC_SCL_1(); /* CPU产生1个时钟 */
IIC_Delay();
IIC_SCL_0();
IIC_Delay();
}
iic.h
#ifndef __IIC_H
#define __IIC_H
#include "stm32f1xx_hal.h"
// IIC总线的SDA、SCL引脚定义
#define SDA_GPIO_PORT GPIOB
#define SDA_GPIO_PIN GPIO_PIN_7
#define SCL_GPIO_PORT GPIOB
#define SCL_GPIO_PIN GPIO_PIN_6
// 定义IIC总线时钟
#define IIC_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define IIC_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
// 定义IIC总线的高、低电平信号
#define IIC_SDA_1() HAL_GPIO_WritePin(SDA_GPIO_PORT, SDA_GPIO_PIN, GPIO_PIN_SET)
#define IIC_SDA_0() HAL_GPIO_WritePin(SDA_GPIO_PORT, SDA_GPIO_PIN, GPIO_PIN_RESET)
#define IIC_SCL_1() HAL_GPIO_WritePin(SCL_GPIO_PORT, SCL_GPIO_PIN, GPIO_PIN_SET)
#define IIC_SCL_0() HAL_GPIO_WritePin(SCL_GPIO_PORT, SCL_GPIO_PIN, GPIO_PIN_RESET)
// IIC总线的SDA、SCL信号读写操作函数
#define IIC_SDA_READ() HAL_GPIO_ReadPin(SDA_GPIO_PORT, SDA_GPIO_PIN)
#define IIC_SCL_READ() HAL_GPIO_ReadPin(SCL_GPIO_PORT, SCL_GPIO_PIN)
void IIC_Init(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_SendByte(uint8_t _ucByte);
uint8_t IIC_ReadByte(void);
uint8_t IIC_WaitAck(void);
void IIC_Ack(void);
void IIC_NAck(void);
#endif /** __IIC_H */
lcd1602-iic.c
#include "iic.h"
//发送数据
void sendData(uint8_t data)
{
uint8_t x = 0;
IIC_Init();
IIC_Start();
IIC_SendByte(0x4e); //写地址
IIC_WaitAck();
IIC_SendByte(data); //数据
IIC_WaitAck();
IIC_Stop();
}
//设置高为|=
#define LCD1602_E_1 0x04
#define LCD1602_RW_1 0x02
#define LCD1602_RS_1 0x01
#define LCD1602_P3_1 0x08
//设置低为&=
#define LCD1602_P3_0 0xf7
#define LCD1602_E_0 0xfb
#define LCD1602_RW_0 0xfd
#define LCD1602_RS_0 0xfe
// 通过IIC发送两个8bit数据
void IIC_SendTwoData(uint8_t data1,uint8_t data2)
{
IIC_Start(); //发送起始信号
IIC_SendByte(0x4e); //写设备地址
IIC_WaitAck(); //等待响应
IIC_SendByte(data1); //发送数据1
IIC_WaitAck();//等待响应
IIC_SendByte(data2); //发送数据2
IIC_WaitAck();//等待响应
IIC_Stop();//发送结束信号
}
//发送4字节命令,高位为数据,低四位为控制
void WriteHalfCommand(uint8_t command)
{
uint8_t tempCommand = command;
tempCommand &= LCD1602_RS_0; //模式为指令模式
tempCommand &= LCD1602_RW_0; //模式为写模式
tempCommand |= LCD1602_E_1; //设置时钟为高
tempCommand |= LCD1602_P3_1; //设置背景灯亮
IIC_SendTwoData(tempCommand,tempCommand&LCD1602_E_0);
HAL_Delay(1);
}
//发送8字节命令
void WriteFullCommand(uint8_t command)
{
WriteHalfCommand((command&0xf0));
WriteHalfCommand((command&0x0f)<<4);
}
//发送4字节数据
void WriteHalfData(uint8_t data)
{
uint8_t tempData = data;
tempData |= LCD1602_RS_1; //模式为数据模式
tempData &= LCD1602_RW_0; //模式为写模式
tempData |= LCD1602_E_1; //设置时钟为高
tempData |= LCD1602_P3_1; //设置背景灯亮
IIC_SendTwoData(tempData,tempData&LCD1602_E_0);
}
//发送8字节数据
void WriteFullData(uint8_t data)
{
WriteHalfData((data&0xf0));
WriteHalfData((data&0x0f)<<4);
}
//发送8字节数据
void ClearScreen(uint8_t data)
{
//清屏
WriteFullCommand(0x01);
}
void showChar(uint8_t row,uint8_t col,char ch)
{
WriteFullCommand(0x80+(0x40*row)+col);
WriteFullData(ch);
}
void showLine(uint8_t row,uint8_t col,char *string)
{
WriteFullCommand(0x80+(0x40*row)+col);
while(*string){
WriteFullData(*string);
string++;
}
}
void initLCD1602(void)
{
IIC_Init();
//设置4bit模式
WriteHalfCommand(0x20);
WriteFullCommand(0x28);
WriteFullCommand(0x08);
WriteFullCommand(0x01);
WriteFullCommand(0x06);
//开启显示、不显示光标、不闪烁光标
WriteFullCommand(0x0c);
}
…后续更新详细(TODO)