#申请原创#
@21小跑堂
CH452是一款用来驱动数码管显示和扫描键盘的芯片,可以动态驱动8位数码管或者64只LED,具有BCD译码、闪烁、移位、段位寻址、光柱译码等功能;同时还可以进行64键的键盘扫描;CH452通过可以级联的4线串行接口或者2线串行接口与单片机等交换数据。我们使用的是28引脚的CH452A,使用4线串行接口进行通信,如下图所示:
接下来我就先分享一下自己解读CH452芯片手册的获取到的一些主要信息,然后展示一下基于C语言的芯片驱动代码。 CH452A的主要引脚说明如下图所示:
数码管显示驱动和键盘扫描相互独立,MCU可以通过操作设定系统参数命令来分别启用或者关闭这两个功能:
CH452支持扫描极限控制,可以通过降低扫描极限值来提高数码管的显示亮度:
另外,为了防止因为按键抖动或者外界干扰而产生误码,芯片自带按键消抖机制,其主要原理是实行两次扫描,即只有当两次键盘扫描的结果相同时,才会被确认有有效按键:
需要注意的是,CH452不支持组合按键,在同一时刻,不能有两个或者更多的按键被按下;如果出现这种情况,则按键代码较小的按键优先。 按键读取时,CH452会先通过DOUT引脚触发低电平的按键中断输出,MCU检测到按键中断后,再通过按键读取命令读取当前按键值。另外,。单片机可以在任何时候读取按键代码,但一般在CH452检测到有效按键而产生 键盘中断时读取按键代码,此时按键代码的位6总是1,另外,如果需要了解按键何时释放,单片机 可以通过查询方式定期读取按键代码,直到按键代码的位6为0。 CH452支持的操作命令如下表所示,另外,对于4线接口,只支持持下表中[方向]属性含“写”的命令和[读取按键代码]命令:
具体需要配置哪些操作命令,坛友们可以根据项目和产品需求进行操作。 以上就是我解读CH452的一些比较重要的信息,其他包括时序图什么的,可以参考数据手册。 然后我再分享一下CH452的基于C语言的驱动代码,主要包括两个文件,一个是CH452.c源文件,一个是CH452.h头文件,其中延时时间这块需要根据不同MCU平台及硬件参数自行调整,确保时序波形不失真的情况下可以满足速度要求。 其中头文件的主要代码如下所示,主要包括硬件GPIO配置(不同MCU可以自行修改),CH452常用命令定义及对外函数接口声明等: - #ifndef __CH452A_H__
- #define __CH452A_H__
- #include "at32f403a_407.h"
- #include "bsp_exit.h"
- #define CH452_RST1_GPIO GPIOA
- #define CH452_DCLK_GPIO GPIOB
- #define CH452_DIN_GPIO GPIOB
- #define CH452_DOUT_GPIO GPIOB
- #define CH452_LOAD_GPIO GPIOA
- #define CH452_RST1_PIN GPIO_PINS_2 //GPIO_PINS_12
- #define CH452_DCLK_PIN GPIO_PINS_3
- #define CH452_DIN_PIN GPIO_PINS_5
- #define CH452_DOUT_PIN GPIO_PINS_4
- #define CH452_LOAD_PIN GPIO_PINS_11
- #define CH452_RESET_SET() gpio_bits_write(CH452_RST1_GPIO, CH452_RST1_PIN, TRUE)
- #define CH452_RESET_CLR() gpio_bits_write(CH452_RST1_GPIO, CH452_RST1_PIN, FALSE)
- #define CH452_DCLK_SET() gpio_bits_write(CH452_DCLK_GPIO, CH452_DCLK_PIN, TRUE)
- #define CH452_DCLK_CLR() gpio_bits_write(CH452_DCLK_GPIO, CH452_DCLK_PIN, FALSE)
- #define CH452_LOAD_SET() gpio_bits_write(CH452_LOAD_GPIO, CH452_LOAD_PIN, TRUE)
- #define CH452_LOAD_CLR() gpio_bits_write(CH452_LOAD_GPIO, CH452_LOAD_PIN, FALSE)
- #define CH452_DIN_SET() gpio_bits_write(CH452_DIN_GPIO, CH452_DIN_PIN, TRUE)
- #define CH452_DIN_CLR() gpio_bits_write(CH452_DIN_GPIO, CH452_DIN_PIN, FALSE)
- #define CH452_DOUT_READ() gpio_input_data_bit_read(CH452_DOUT_GPIO,CH452_DOUT_PIN)
- #define DISABLE_KEY_INTERRUPT() {DISABLE_CH452A_DOUT_INT();}
- #define ENABLE_KEY_INTERRUPT() {ENABLE_CH452A_DOUT_INT() ;}
- #define CLEAR_KEY_INT_FLAG() {CLEAR_CH452A_INT_FLAG();}
- /* CH451和CH452的常用命令码 */
- #define CH452_NOP 0x0000 // 空操作
- #define CH452_RESET 0x0201 // 复位
- #define CH452_LEVEL 0x0100 // 加载光柱值,需另加7位数据
- #define CH452_CLR_BIT 0x0180 // 段位清0,需另加6位数据
- #define CH452_SET_BIT 0x01C0 // 段位置1,需另加6位数据
- #define CH452_SLEEP 0x0202 // 进入睡眠状态
- #define CH452_LEFTMOV 0x0300 // 设置移动方式-左移
- #define CH452_LEFTCYC 0x0301 // 设置移动方式-左循环
- #define CH452_RIGHTMOV 0x0302 // 设置移动方式-右移
- #define CH452_RIGHTCYC 0x0303 // 设置移动方式-右循环
- #define CH452_SELF_BCD 0x0380 // 自定义BCD码,需另加7位数据
- #define CH452_SYSOFF 0x0400 // 关闭显示、关闭键盘
- #define CH452_SYSON1 0x0401 // 开启显示
- #define CH452_SYSON2 0x0403 // 开启显示、键盘
- #define CH452_SYSON2W 0x0423 // 开启显示、键盘, 真正2线接口
- #define CH452_NO_BCD 0x0550 // 设置默认显示方式,可另加3位扫描极限,0101 0101 0000
- #define CH452_BCD 0x0580 // 设置BCD译码方式,可另加3位扫描极限
- #define CH452_TWINKLE 0x0600 // 设置闪烁控制,需另加8位数据
- #define CH452_GET_KEY 0x0700 // 获取按键,返回按键代码
- #define CH452_DIG0 0x0800 // 数码管位0显示,需另加8位数据
- #define CH452_DIG1 0x0900 // 数码管位1显示,需另加8位数据
- #define CH452_DIG2 0x0a00 // 数码管位2显示,需另加8位数据
- #define CH452_DIG3 0x0b00 // 数码管位3显示,需另加8位数据
- #define CH452_DIG4 0x0c00 // 数码管位4显示,需另加8位数据
- #define CH452_DIG5 0x0d00 // 数码管位5显示,需另加8位数据
- #define CH452_DIG6 0x0e00 // 数码管位6显示,需另加8位数据
- #define CH452_DIG7 0x0f00 // 数码管位7显示,需另加8位数据
- // BCD译码方式下的特殊字符
- #define CH452_BCD_SPACE 0x10
- #define CH452_BCD_PLUS 0x11
- #define CH452_BCD_MINUS 0x12
- #define CH452_BCD_EQU 0x13
- #define CH452_BCD_LEFT 0x14
- #define CH452_BCD_RIGHT 0x15
- #define CH452_BCD_UNDER 0x16
- #define CH452_BCD_CH_H 0x17
- #define CH452_BCD_CH_L 0x18
- #define CH452_BCD_CH_P 0x19
- #define CH452_BCD_DOT 0x1A
- #define CH452_BCD_SELF 0x1E
- #define CH452_BCD_TEST 0x88
- #define CH452_BCD_DOT_X 0x80
- // 有效按键代码
- #define CH452_KEY_MIN 0x40
- #define CH452_KEY_MAX 0x7F
- // 设置延时时间
- #define DLCK_FREQ_DELAY 10
- #define CMD_LOAD_DELAY 60
- // LED matrix: 5*8
- #define CH452_LED_DIG_NUM 5
- #define CH452_LED_SEG_NUM 8
- extern const uint16_t ch452_dig_cmd[CH452_LED_DIG_NUM];
- // 对外子程序
- extern void CH452_Init(void); // 初始化CH452
- extern uint8_t CH452_Read(void); // 从CH452读取按键代码
- extern void CH452_Write(uint16_t cmd); // 向CH452发出操作命令
- extern void CH452_UpdateRow(uint8_t row, uint8_t data); //将LED数据写入CH452
- #endif /* __CH452A_H__ */
其中源文件的主要代码如下所示,主要包括CH452初始化接口、写数据接口、读数据接口等:
- #include "ch452a.h"
- // 更新字数据的命令
- const uint16_t ch452_dig_cmd[CH452_LED_DIG_NUM] =
- {
- CH452_DIG0,
- CH452_DIG1,
- CH452_DIG2,
- CH452_DIG3,
- CH452_DIG4
- };
- static void CH452_Delay(uint32_t count)
- {
- uint32_t i;
-
- for(i = 0; i < count; i++)
- {
- __asm("nop");
- }
- }
- // CH452A初始化配置
- void CH452_Init(void)
- {
- uint8_t row = 0;
- //复位CH452
- CH452_Write(CH452_RESET);
- CH452_Delay(1000);
- //启用显示和键盘
- CH452_Write(CH452_SYSON2);
- //设置扫描极限为5,DIG0~DIG4
- CH452_Write(CH452_NO_BCD);
- //清除所有LED状态
- for(row = 0; row < CH452_LED_DIG_NUM; row++)
- {
- CH452_Write(ch452_dig_cmd[row] | 0x00);
- }
- }
- //定义一无符号整型变量存储12字节的命令字。
- void CH452_Write(uint16_t cmd)
- {
- uint8_t i;
-
- DISABLE_KEY_INTERRUPT(); //禁止键盘中断,防止传输过程中被CH452中断而进入中断服务程序中再次传输
- CH452_LOAD_CLR(); //命令开始,LOAD=0
- for(i=0; i<12; i++) //送入12位数据,低位在前
- {
- // 输出位数据
- if (cmd & 1)
- {
- CH452_DIN_SET();
- }
- else
- {
- CH452_DIN_CLR();
- }
- CH452_DCLK_CLR();
- CH452_Delay(DLCK_FREQ_DELAY);
- cmd>>=1;
- CH452_DCLK_SET(); //上升沿有效
- CH452_Delay(DLCK_FREQ_DELAY);
- }
- CH452_LOAD_SET(); //加载数据,LOAD上升沿
- //命令数据加载周期不小于6US,to test
- CH452_Delay(CMD_LOAD_DELAY);
- ENABLE_KEY_INTERRUPT();
- }
- //*************************************************
- //输入按键代码子程序,从CH452读取
- uint8_t CH452_Read(void)
- {
- uint8_t i;
- uint8_t cmd = 0;
- uint8_t keycode = 0; //定义命令字,和数据存储器
- // 发送读命令高4位(0111b)
- DISABLE_KEY_INTERRUPT(); //禁止键盘中断,防止传输过程中被CH452中断而进入中断服务程序中再次传输
- cmd = (uint8_t)(CH452_GET_KEY>>8); //读按键的命令字
- CH452_LOAD_CLR();
- for(i=0; i<4; i++) // 只需要发出高4位,多发也可以,但应该确保最后留下的4位是该命令码
- {
- // 输出位数据
- if (cmd & 1)
- {
- CH452_DIN_SET();
- }
- else
- {
- CH452_DIN_CLR();
- }
- CH452_DCLK_CLR();
- CH452_Delay(DLCK_FREQ_DELAY);
- cmd>>=1; //往右移一位\
- CH452_DCLK_SET(); //产生时钟上升沿锁通知CH451输入位数据
- CH452_Delay(DLCK_FREQ_DELAY);
- }
- CH452_LOAD_SET(); //产生加载上升沿通知CH451处理命令数据
- // 读取7位键值(高位在前)
- keycode=0; //清除keycode
- for(i=0; i<7; i++)
- {
- keycode <<= 1; //数据移入keycode,高位在前,低位在后
- if (CH452_DOUT_READ())
- {
- keycode++; //从高到低读入数据
- //keycode |= 0x01;
- }
- CH452_DCLK_CLR(); //产生时钟下升沿通知CH451输出下一位
- CH452_Delay(DLCK_FREQ_DELAY);
- CH452_DCLK_SET();
- CH452_Delay(DLCK_FREQ_DELAY);
- }
- CLEAR_KEY_INT_FLAG(); //清中断标志
- ENABLE_KEY_INTERRUPT();
-
- return keycode; //反回键值
- }
- // 写入数据到CH452A,更新LED扫描
- void CH452_UpdateRow(uint8_t row, uint8_t data)
- {
- uint16_t cmd = 0;
-
- switch(row)
- {
- case 0:
- cmd = CH452_DIG0;
- break;
- case 1:
- cmd = CH452_DIG1;
- break;
- case 2:
- cmd = CH452_DIG2;
- break;
- case 3:
- cmd = CH452_DIG3;
- break;
- case 4:
- cmd = CH452_DIG4;
- break;
- case 5:
- cmd = CH452_DIG5;
- break;
- case 6:
- cmd = CH452_DIG6;
- break;
- case 7:
- cmd = CH452_DIG7;
- break;
- default:
- return;
- }
-
- // 更新显示缓冲区和硬件
- CH452_Write(cmd | data);
- }
以上的对CH452的解读分享,给大家提供参考。
|