文章目录
前言
关于CH452驱动网上资料较多,但都比较早,和个人实际需要存在出入,经参考整理,调通软硬件驱动程序,现将其整理分享,以作记录,驱动采用两线IIC形式,CH452为共阴极接法。由于硬件IIC很容易出问题,推荐使用软件IIC驱动。基础配置通过STM32CUBE生成。
一、硬件IIC驱动
1.硬件IIC GPIO选择
选择IIC1作为硬件IIC,即PB9为IIC的SDA, PB8为IIC的SCL
选择PD2作为CH452复位引脚,PC11作为CH452中断引脚,PC10作为CH452片选引脚
2.硬件IIC配置
3.硬件GPIO配置
4.硬件中断配置
不要忘记打开中断
5.添加驱动代码
生成代码后,在i2c.c中添加如下代码
通过CH452_HARDWARE_IIC_Write函数传输数据
在中断回调函数HAL_GPIO_EXTI_Callback中读取按键键值
static uint8_t CS_ADDR[2] = {0x20, 0x30};
void CH452_HARDWARE_IIC_Write(uint8_t cs, uint8_t addr, uint8_t data)
{
//CH452为7位地址,当其片选为0时,地址为0x20
//此处左移一位是由于HAL底层驱动传输的时候会直接将addr最后一位置0或1控制方向,针对7位地址格式的CH452需要左移一位才是正确的地址
uint16_t address = (CS_ADDR[cs] | addr) << 1;
while(HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)address, &data, 1, 0xff) != HAL_OK)
{
if(HAL_I2C_GetError(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
}
uint8_t CH452_HARDWARE_IIC_Read(uint8_t cs)
{
uint8_t data = 0;
uint16_t address = (CS_ADDR[cs] | 0x07) << 1;
while(HAL_I2C_Master_Receive(&hi2c1, (uint16_t)address, &data, 1, 0xff) != HAL_OK)
{
if(HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
{
Error_Handler();
}
}
return data;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_11)
{
uint8_t key_value = CH452_HARDWARE_IIC_Read(0);
}
}
void CH452Ctrl_Init(void)
{
//CH452硬件初始化
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);//CS 0
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);//RESET CH452
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_Delay(1);
//0x07-两线接口ACK命令,0xff-无意义
CH452_HARDWARE_IIC_Write(0, 0x07, 0xff);
HAL_Delay(1);
//0x04-设定系统参数命令,0x03-允许显示驱动,启用键盘扫描
CH452_HARDWARE_IIC_Write(0, 0x04, 0x03);
HAL_Delay(1);
uint8_t i;
for(i = 0; i < 8; i++)
{
//DIG0~8清屏
CH452_HARDWARE_IIC_Write(0, 0x08 + i, 0x00);
}
}
二、软件IIC驱动
1.软件IIC GPIO选择
与硬件IIC相同
2.软件GPIO配置
3.软件中断配置
不要忘记打开中断
4.TIM10配置
TIM10作为us延时的定时器,以匹配CH452软件IIC时序
5.系统时钟配置
配置系统时钟100MHz
6.添加驱动代码
生成代码后,在tim.h添加us延时函数声明
void delay_us(uint32_t nus);
在tim.c添加us延时函数
void delay_us(uint32_t nus)
{
uint16_t differ = 0xffff - nus - 5;
HAL_TIM_Base_Start(&htim10);
__HAL_TIM_SetCounter(&htim10, differ);
while(differ < 0xffff - 5)
{
differ = __HAL_TIM_GetCounter(&htim10);
}
HAL_TIM_Base_Stop(&htim10);
}
新建IIC.h,添加如下驱动代码
#ifndef __CH452_CTRL_H
#define __CH452_CTRL_H
#include <stdint.h>
#include "stm32f4xx_hal.h"
#include "tim.h"
#define CH452_CS_PIN GPIO_PIN_10
#define CH452_CS_PORT GPIOC
#define CH452_INT_PIN GPIO_PIN_11
#define CH452_INT_PORT GPIOC
#define CH452_INT_EXTI_IRQn EXTI15_10_IRQn
#define CH452_RST_PIN GPIO_PIN_2
#define CH452_RST_PORT GPIOD
#define CH452_SCL_PIN GPIO_PIN_8
#define CH452_SCL_PORT GPIOB
#define CH452_SDA_PIN GPIO_PIN_9
#define CH452_SDA_PORT GPIOB
#define SCL_SET HAL_GPIO_WritePin(CH452_SCL_PORT, CH452_SCL_PIN, GPIO_PIN_SET)
#define SCL_RST HAL_GPIO_WritePin(CH452_SCL_PORT, CH452_SCL_PIN, GPIO_PIN_RESET)
#define SDA_SET HAL_GPIO_WritePin(CH452_SDA_PORT, CH452_SDA_PIN, GPIO_PIN_SET)
#define SDA_RST HAL_GPIO_WritePin(CH452_SDA_PORT, CH452_SDA_PIN, GPIO_PIN_RESET)
void CH452Init(void);
void CH452_SOFTWARE_IIC_Write(uint8_t addr, uint8_t data);
uint8_t CH452_SOFTWARE_Read(uint8_t cs);
#endif
新建IIC.c文件,添加如下驱动代码,软件IIC驱动代码参考正点原子相关程序
#include "IIC.h"
static void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pin = CH452_SDA_PIN;
HAL_GPIO_Init(CH452_SDA_PORT, &GPIO_InitStruct);
}
static void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Pin = CH452_SDA_PIN;
HAL_GPIO_Init(CH452_SDA_PORT, &GPIO_InitStruct);
}
static void IIC_Start(void)
{
SDA_OUT();
SCL_SET;
SDA_SET;
delay_us(1);
SDA_RST;
delay_us(1);
SCL_RST;
delay_us(1);
}
static void IIC_Stop(void)
{
SDA_OUT();
SCL_RST;
SDA_RST;
delay_us(1);
SCL_SET;
SDA_SET;
delay_us(1);
}
static uint8_t IIC_Wait_Ack(void)
{
uint8_t waitTime = 0;
SDA_IN();
SCL_SET;
delay_us(1);
while(HAL_GPIO_ReadPin(CH452_SDA_PORT, CH452_SDA_PIN))
{
waitTime++;
if(waitTime > 250)
{
IIC_Stop();
return 1;
}
}
SCL_RST;
return 0;
}
static void IIC_Ack(void)
{
SCL_RST;
SDA_OUT();
SDA_RST;
delay_us(1);
SCL_SET;
delay_us(1);
SCL_RST;
}
static void IIC_NAck(void)
{
SCL_RST;
SDA_OUT();
SDA_SET;
delay_us(1);
SCL_SET;
delay_us(1);
SCL_RST;
}
static void IIC_Send_Byte(uint8_t data)
{
uint8_t t;
SDA_OUT();
SCL_RST;
for(t = 0; t < 8; t++)
{
if((data & 0x80) >> 7)
{
SDA_SET;
}
else
{
SDA_RST;
}
data <<= 1;
delay_us(1);
SCL_SET;
delay_us(1);
SCL_RST;
delay_us(1);
}
}
static uint8_t IIC_Read_Byte(uint8_t ack)
{
uint8_t i, receive = 0;
SDA_IN();
for(i = 0; i < 8; i++)
{
SCL_RST;
delay_us(1);
SCL_SET;
delay_us(1);
receive <<= 1;
if(HAL_GPIO_ReadPin(CH452_SDA_PORT, CH452_SDA_PIN)) receive++;
delay_us(1);
}
if(!ack)
IIC_NAck();
else
IIC_Ack();
return receive;
}
static const uint8_t CS_ADDR[2] = {0x20, 0x30};
void CH452_SOFTWARE_IIC_Write(uint8_t cs, uint8_t addr, uint8_t data)
{
IIC_Start();
IIC_Send_Byte((CS_ADDR[cs] | addr) << 1);
SDA_SET;
delay_us(1);
SCL_SET;
delay_us(1);
SCL_RST;
SDA_RST;
// if(addr == 0x07)
// {
// IIC_Wait_Ack();
// }
IIC_Send_Byte(data);
IIC_Stop();
delay_us(100);
}
uint8_t CH452_SOFTWARE_Read(uint8_t cs)
{
IIC_Start();
IIC_Send_Byte(((CS_ADDR[cs] | 0x07) << 1) | 0x01);
SCL_SET;
delay_us(1);
SCL_RST;
delay_us(1);
uint8_t data;
data = IIC_Read_Byte(0);
return data;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_11)
{
uint8_t key_value = CH452_SOFTWARE_Read(0);
}
}
void CH452Init(void)
{
HAL_GPIO_WritePin(CH452_CS_PORT, CH452_CS_PIN, GPIO_PIN_RESET);//CS 0
delay_us(100);
HAL_GPIO_WritePin(CH452_RST_PORT, CH452_RST_PIN, GPIO_PIN_SET);//RESET CH452
delay_us(100);
HAL_GPIO_WritePin(CH452_RST_PORT, CH452_RST_PIN, GPIO_PIN_RESET);
delay_us(100);
CH452_Write(0, 0x07, 0xff);//2 WIRE ACK
CH452_Write(0, 0x04, 0x03);//DISP-ON KEYB-ON INTM-LOW
uint8_t i;
for(i = 0; i < 8; i++)
{
CH452_Write(0, 0x08 + i, 0x00);
}
}
初始化CH452后通过CH452_SOFTWARE_IIC_Write传输显示数据,通过中断回调函数HAL_GPIO_EXTI_Callback读取键值。
总结
STM32硬件IIC控制CH452配置方便,但实际使用中较易出现错误,具体原因需要根据实际情况去调试发现;软件IIC控制时序更清晰,但使用的资源较多。推荐根据自己实际需要选择。