2.ch452a 4线驱动按键扫描
h传输方式:4线驱动
ch452a接线:
RETI-GND,
DCLK-PA15,
DIN-PC10,
LOAD-PC11,
DOUT-PC12,
VCC-VCC
单片机: stm32f103ret6
数字矩阵按键4*4中的S2:S2[DIG4,SEG0]
SEG 输出输入 DIG 输出
- SEG7 ~SEG0 三态输出 及输入 数码管的段驱动,高电平有效, 键盘扫描输入,高电平有效,内置下拉,没有用到键盘扫描,所以供参考显示。
- DIG7 ~DIG0 输出 数码管的字驱动,低电平有效, 键盘扫描输出,高电平有效, DIG6 和 DIG7 可用于 GPO 通用输出
- DIG7~DIG0引脚用于列扫描输出,SEG7~SEG0引脚都带有内部下拉电阻,用于行扫描输入。
手册和原厂的参考代码在资源中
代码:
1. 硬件抽象层 (ch452_hal.h)
#ifndef __CH452_HAL_H
#define __CH452_HAL_H#include "stm32f1xx_hal.h"// 用户引脚配置(与您的要求一致)
#define CH452_DCLK_PORT GPIOC
#define CH452_DCLK_PIN GPIO_PIN_10
#define CH452_DIN_PORT GPIOC
#define CH452_DIN_PIN GPIO_PIN_11
#define CH452_LOAD_PORT GPIOC
#define CH452_LOAD_PIN GPIO_PIN_12
#define CH452_DOUT_PORT GPIOD
#define CH452_DOUT_PIN GPIO_PIN_2// 硬件控制宏(优化版本)
#define CH452_DCLK_SET() HAL_GPIO_WritePin(CH452_DCLK_PORT, CH452_DCLK_PIN, GPIO_PIN_SET)
#define CH452_DCLK_CLR() HAL_GPIO_WritePin(CH452_DCLK_PORT, CH452_DCLK_PIN, GPIO_PIN_RESET)
#define CH452_DIN_SET() HAL_GPIO_WritePin(CH452_DIN_PORT, CH452_DIN_PIN, GPIO_PIN_SET)
#define CH452_DIN_CLR() HAL_GPIO_WritePin(CH452_DIN_PORT, CH452_DIN_PIN, GPIO_PIN_RESET)
#define CH452_LOAD_SET() HAL_GPIO_WritePin(CH452_LOAD_PORT, CH452_LOAD_PIN, GPIO_PIN_SET)
#define CH452_LOAD_CLR() HAL_GPIO_WritePin(CH452_LOAD_PORT, CH452_LOAD_PIN, GPIO_PIN_RESET)
#define CH452_DOUT_READ() HAL_GPIO_ReadPin(CH452_DOUT_PORT, CH452_DOUT_PIN)// 中断控制(使用EXTI2)
#define DISABLE_KEY_INTERRUPT() HAL_NVIC_DisableIRQ(EXTI2_IRQn)
#define ENABLE_KEY_INTERRUPT() HAL_NVIC_EnableIRQ(EXTI2_IRQn)
#define CLEAR_KEY_INTER_FLAG() __HAL_GPIO_EXTI_CLEAR_IT(CH452_DOUT_PIN)// 精确延时(基于DWT)
void CH452_Delay_Init(void);
static inline void DELAY_1US(void) {uint32_t ticks = SystemCoreClock / 1000000 / 5;while(ticks--);
}// 原厂命令兼容
#include "ch452cmd.h"// 驱动函数
void CH452_Init(void);
void CH452_Write(uint16_t cmd);
uint8_t CH452_Read(void);#endif
2. 驱动实现 (ch452_hal.c)
#include "ch452_hal.h"// DWT延时初始化
void CH452_Delay_Init(void) {if(!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;DWT->CYCCNT = 0;DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;}
}// GPIO初始化
void CH452_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};// 时钟使能__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();// DCLK(PC10), DIN(PC11), LOAD(PC12) 推挽输出GPIO_InitStruct.Pin = CH452_DCLK_PIN | CH452_DIN_PIN | CH452_LOAD_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);// DOUT(PD2) 外部中断GPIO_InitStruct.Pin = CH452_DOUT_PIN;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);// 初始状态CH452_LOAD_SET();CH452_DCLK_CLR();
}// 写命令(严格遵循原厂时序)
void CH452_Write(uint16_t cmd) {DISABLE_KEY_INTERRUPT();CH452_LOAD_CLR();for(uint8_t i = 0; i < 12; i++) {(cmd & 1) ? CH452_DIN_SET() : CH452_DIN_CLR();CH452_DCLK_CLR();DELAY_1US();cmd >>= 1;CH452_DCLK_SET();DELAY_1US();}CH452_LOAD_SET();for(uint8_t i = 0; i < 6; i++) DELAY_1US(); // 保持6usENABLE_KEY_INTERRUPT();
}// 读键值(优化后的实现)
uint8_t CH452_Read(void) {uint8_t keycode = 0;DISABLE_KEY_INTERRUPT();// 发送读命令高4位(0111b)CH452_LOAD_CLR();for(uint8_t i = 0; i < 4; i++) {(0x07 & (1 << i)) ? CH452_DIN_SET() : CH452_DIN_CLR();CH452_DCLK_CLR();DELAY_1US();CH452_DCLK_SET();DELAY_1US();}CH452_LOAD_SET();// 读取7位键值(高位在前)for(uint8_t i = 0; i < 7; i++) {keycode <<= 1;if(CH452_DOUT_READ()) keycode |= 0x01;CH452_DCLK_CLR();DELAY_1US();CH452_DCLK_SET();DELAY_1US();}CLEAR_KEY_INTER_FLAG();ENABLE_KEY_INTERRUPT();return keycode;
}// 完整初始化
void CH452_Init(void) {CH452_Delay_Init();CH452_GPIO_Init();// 配置中断HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0);HAL_NVIC_EnableIRQ(EXTI2_IRQn);// 复位CH452CH452_Write(CH452_RESET);HAL_Delay(10);CH452_Write(CH452_SYSON2); // 启用显示和键盘
}
3. 应用示例 (main.c)
#include "main.h"
#include "ch452_hal.h"volatile uint8_t ch452_key_event = 0;// 中断回调
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {if(GPIO_Pin == CH452_DOUT_PIN) {ch452_key_event = 1;}
}int main(void) {HAL_Init();SystemClock_Config();// 初始化CH452CH452_Init();// 数码管显示测试CH452_Write(CH452_BCD | 0x07); // BCD译码,8位数码管CH452_Write(CH452_DIG0 | 8); // 显示数字8while(1) {if(ch452_key_event) {uint8_t key = CH452_Read();if((key & 0x7F) == 0x23) { // DIG4+SEG0按键HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);}ch452_key_event = 0;}__WFI(); // 低功耗等待}
}// EXTI2中断处理(必须实现)
void EXTI2_IRQHandler(void) {HAL_GPIO_EXTI_IRQHandler(CH452_DOUT_PIN);
}