[其他芯片] 数码管驱动和键盘扫描芯片CH452的使用分享

[复制链接]
850|3
dffzh 发表于 2025-11-11 10:44 | 显示全部楼层 |阅读模式
芯片, , , ,
#申请原创#


@21小跑堂

CH452是一款用来驱动数码管显示和扫描键盘的芯片,可以动态驱动8位数码管或者64只LED,具有BCD译码、闪烁、移位、段位寻址、光柱译码等功能;同时还可以进行64键的键盘扫描;CH452通过可以级联的4线串行接口或者2线串行接口与单片机等交换数据。我们使用的是28引脚的CH452A,使用4线串行接口进行通信,如下图所示:
361886912a238c19a0.png
584516912a23e7b3ad.png
接下来我就先分享一下自己解读CH452芯片手册的获取到的一些主要信息,然后展示一下基于C语言的芯片驱动代码。
CH452A的主要引脚说明如下图所示:
137926912a24b1a772.png
89726912a250c77a4.png
数码管显示驱动和键盘扫描相互独立,MCU可以通过操作设定系统参数命令来分别启用或者关闭这两个功能:
237566912a25d391fb.png
CH452支持扫描极限控制,可以通过降低扫描极限值来提高数码管的显示亮度:
986156912a268be765.png
另外,为了防止因为按键抖动或者外界干扰而产生误码,芯片自带按键消抖机制,其主要原理是实行两次扫描,即只有当两次键盘扫描的结果相同时,才会被确认有有效按键:
509426912a27448e64.png
需要注意的是,CH452不支持组合按键,在同一时刻,不能有两个或者更多的按键被按下;如果出现这种情况,则按键代码较小的按键优先。
按键读取时,CH452会先通过DOUT引脚触发低电平的按键中断输出,MCU检测到按键中断后,再通过按键读取命令读取当前按键值。另外,。单片机可以在任何时候读取按键代码,但一般在CH452检测到有效按键而产生 键盘中断时读取按键代码,此时按键代码的位6总是1,另外,如果需要了解按键何时释放,单片机 可以通过查询方式定期读取按键代码,直到按键代码的位6为0。
CH452支持的操作命令如下表所示,另外,对于4线接口,只支持持下表中[方向]属性含“写”的命令和[读取按键代码]命令:
612416912a27ecdca4.png
具体需要配置哪些操作命令,坛友们可以根据项目和产品需求进行操作。
以上就是我解读CH452的一些比较重要的信息,其他包括时序图什么的,可以参考数据手册。
然后我再分享一下CH452的基于C语言的驱动代码,主要包括两个文件,一个是CH452.c源文件,一个是CH452.h头文件,其中延时时间这块需要根据不同MCU平台及硬件参数自行调整,确保时序波形不失真的情况下可以满足速度要求。
其中头文件的主要代码如下所示,主要包括硬件GPIO配置(不同MCU可以自行修改),CH452常用命令定义及对外函数接口声明等:
  1. #ifndef __CH452A_H__
  2. #define __CH452A_H__

  3. #include "at32f403a_407.h"
  4. #include "bsp_exit.h"

  5. #define  CH452_RST1_GPIO        GPIOA
  6. #define  CH452_DCLK_GPIO        GPIOB
  7. #define  CH452_DIN_GPIO         GPIOB
  8. #define  CH452_DOUT_GPIO        GPIOB
  9. #define  CH452_LOAD_GPIO        GPIOA

  10. #define  CH452_RST1_PIN                GPIO_PINS_2  //GPIO_PINS_12
  11. #define  CH452_DCLK_PIN                GPIO_PINS_3
  12. #define  CH452_DIN_PIN                GPIO_PINS_5
  13. #define  CH452_DOUT_PIN                GPIO_PINS_4
  14. #define  CH452_LOAD_PIN         GPIO_PINS_11

  15. #define CH452_RESET_SET()    gpio_bits_write(CH452_RST1_GPIO, CH452_RST1_PIN, TRUE)
  16. #define CH452_RESET_CLR()    gpio_bits_write(CH452_RST1_GPIO, CH452_RST1_PIN, FALSE)

  17. #define CH452_DCLK_SET()     gpio_bits_write(CH452_DCLK_GPIO, CH452_DCLK_PIN, TRUE)
  18. #define CH452_DCLK_CLR()     gpio_bits_write(CH452_DCLK_GPIO, CH452_DCLK_PIN, FALSE)

  19. #define CH452_LOAD_SET()     gpio_bits_write(CH452_LOAD_GPIO, CH452_LOAD_PIN, TRUE)
  20. #define CH452_LOAD_CLR()     gpio_bits_write(CH452_LOAD_GPIO, CH452_LOAD_PIN, FALSE)

  21. #define CH452_DIN_SET()      gpio_bits_write(CH452_DIN_GPIO, CH452_DIN_PIN, TRUE)
  22. #define CH452_DIN_CLR()      gpio_bits_write(CH452_DIN_GPIO, CH452_DIN_PIN, FALSE)

  23. #define CH452_DOUT_READ()    gpio_input_data_bit_read(CH452_DOUT_GPIO,CH452_DOUT_PIN)

  24. #define        DISABLE_KEY_INTERRUPT()        {DISABLE_CH452A_DOUT_INT();}
  25. #define        ENABLE_KEY_INTERRUPT()        {ENABLE_CH452A_DOUT_INT() ;}
  26. #define CLEAR_KEY_INT_FLAG()    {CLEAR_CH452A_INT_FLAG();}   

  27. /* CH451和CH452的常用命令码 */
  28. #define CH452_NOP                0x0000                                        // 空操作
  29. #define CH452_RESET     0x0201                                        // 复位
  30. #define CH452_LEVEL                0x0100                                        // 加载光柱值,需另加7位数据
  31. #define CH452_CLR_BIT        0x0180                                        // 段位清0,需另加6位数据
  32. #define CH452_SET_BIT        0x01C0                                        // 段位置1,需另加6位数据
  33. #define CH452_SLEEP                0x0202                                        // 进入睡眠状态
  34. #define CH452_LEFTMOV   0x0300                            // 设置移动方式-左移
  35. #define CH452_LEFTCYC   0x0301                            // 设置移动方式-左循环
  36. #define CH452_RIGHTMOV  0x0302                            // 设置移动方式-右移
  37. #define CH452_RIGHTCYC  0x0303                            // 设置移动方式-右循环       
  38. #define CH452_SELF_BCD        0x0380                                        // 自定义BCD码,需另加7位数据
  39. #define CH452_SYSOFF    0x0400                                        // 关闭显示、关闭键盘
  40. #define CH452_SYSON1    0x0401                                        // 开启显示
  41. #define CH452_SYSON2    0x0403                                        // 开启显示、键盘
  42. #define CH452_SYSON2W   0x0423                                        // 开启显示、键盘, 真正2线接口
  43. #define CH452_NO_BCD    0x0550                                        // 设置默认显示方式,可另加3位扫描极限,0101 0101 0000
  44. #define CH452_BCD       0x0580                                        // 设置BCD译码方式,可另加3位扫描极限
  45. #define CH452_TWINKLE   0x0600                            // 设置闪烁控制,需另加8位数据
  46. #define CH452_GET_KEY        0x0700                                        // 获取按键,返回按键代码
  47. #define CH452_DIG0      0x0800                                        // 数码管位0显示,需另加8位数据
  48. #define CH452_DIG1      0x0900                            // 数码管位1显示,需另加8位数据
  49. #define CH452_DIG2      0x0a00                            // 数码管位2显示,需另加8位数据
  50. #define CH452_DIG3      0x0b00                            // 数码管位3显示,需另加8位数据
  51. #define CH452_DIG4      0x0c00                            // 数码管位4显示,需另加8位数据
  52. #define CH452_DIG5      0x0d00                                        // 数码管位5显示,需另加8位数据
  53. #define CH452_DIG6      0x0e00                                        // 数码管位6显示,需另加8位数据
  54. #define CH452_DIG7      0x0f00                            // 数码管位7显示,需另加8位数据

  55. // BCD译码方式下的特殊字符
  56. #define                CH452_BCD_SPACE                0x10
  57. #define                CH452_BCD_PLUS                0x11
  58. #define                CH452_BCD_MINUS                0x12
  59. #define                CH452_BCD_EQU                0x13
  60. #define                CH452_BCD_LEFT                0x14
  61. #define                CH452_BCD_RIGHT                0x15
  62. #define                CH452_BCD_UNDER                0x16
  63. #define                CH452_BCD_CH_H                0x17
  64. #define                CH452_BCD_CH_L                0x18
  65. #define                CH452_BCD_CH_P                0x19
  66. #define                CH452_BCD_DOT                0x1A
  67. #define                CH452_BCD_SELF                0x1E
  68. #define                CH452_BCD_TEST                0x88
  69. #define                CH452_BCD_DOT_X                0x80

  70. // 有效按键代码
  71. #define                CH452_KEY_MIN                0x40
  72. #define                CH452_KEY_MAX                0x7F

  73. // 设置延时时间
  74. #define     DLCK_FREQ_DELAY     10
  75. #define     CMD_LOAD_DELAY      60

  76. // LED matrix: 5*8
  77. #define   CH452_LED_DIG_NUM    5
  78. #define   CH452_LED_SEG_NUM    8

  79. extern const uint16_t ch452_dig_cmd[CH452_LED_DIG_NUM];

  80. // 对外子程序
  81. extern void CH452_Init(void);    // 初始化CH452
  82. extern uint8_t CH452_Read(void);             // 从CH452读取按键代码
  83. extern void CH452_Write(uint16_t cmd);         // 向CH452发出操作命令
  84. extern void CH452_UpdateRow(uint8_t row, uint8_t data);  //将LED数据写入CH452


  85. #endif /* __CH452A_H__ */
其中源文件的主要代码如下所示,主要包括CH452初始化接口、写数据接口、读数据接口等:

  1. #include "ch452a.h"

  2. // 更新字数据的命令
  3. const uint16_t ch452_dig_cmd[CH452_LED_DIG_NUM] =
  4. {
  5.     CH452_DIG0,
  6.         CH452_DIG1,
  7.         CH452_DIG2,
  8.         CH452_DIG3,
  9.         CH452_DIG4
  10. };

  11. static void CH452_Delay(uint32_t count)
  12. {
  13.      uint32_t i;

  14.      for(i = 0; i < count; i++)
  15.      {
  16.              __asm("nop");
  17.      }
  18. }

  19. // CH452A初始化配置
  20. void CH452_Init(void)
  21. {
  22.     uint8_t row = 0;

  23.     //复位CH452
  24.     CH452_Write(CH452_RESET);
  25.         CH452_Delay(1000);
  26.     //启用显示和键盘
  27.     CH452_Write(CH452_SYSON2);
  28.         //设置扫描极限为5,DIG0~DIG4
  29.         CH452_Write(CH452_NO_BCD);

  30.         //清除所有LED状态
  31.         for(row = 0; row < CH452_LED_DIG_NUM; row++)
  32.         {
  33.         CH452_Write(ch452_dig_cmd[row] | 0x00);
  34.     }
  35. }

  36. //定义一无符号整型变量存储12字节的命令字。
  37. void CH452_Write(uint16_t cmd)
  38. {
  39.         uint8_t i;
  40.        
  41.         DISABLE_KEY_INTERRUPT();                  //禁止键盘中断,防止传输过程中被CH452中断而进入中断服务程序中再次传输
  42.         CH452_LOAD_CLR();                 //命令开始,LOAD=0
  43.         for(i=0; i<12; i++)                                //送入12位数据,低位在前
  44.         {
  45.             // 输出位数据
  46.                 if (cmd & 1)
  47.                 {
  48.                     CH452_DIN_SET();
  49.                 }
  50.                 else
  51.                 {
  52.                     CH452_DIN_CLR();
  53.                 }  
  54.             CH452_DCLK_CLR();
  55.                 CH452_Delay(DLCK_FREQ_DELAY);
  56.             cmd>>=1;
  57.             CH452_DCLK_SET();             //上升沿有效
  58.             CH452_Delay(DLCK_FREQ_DELAY);
  59.         }
  60.           CH452_LOAD_SET();         //加载数据,LOAD上升沿
  61.         //命令数据加载周期不小于6US,to test
  62.         CH452_Delay(CMD_LOAD_DELAY);
  63.           ENABLE_KEY_INTERRUPT();
  64. }

  65. //*************************************************
  66. //输入按键代码子程序,从CH452读取
  67. uint8_t CH452_Read(void)
  68. {
  69.         uint8_t i;
  70.           uint8_t cmd = 0;
  71.         uint8_t keycode = 0;                //定义命令字,和数据存储器

  72.         // 发送读命令高4位(0111b)
  73.           DISABLE_KEY_INTERRUPT();                //禁止键盘中断,防止传输过程中被CH452中断而进入中断服务程序中再次传输       
  74.           cmd = (uint8_t)(CH452_GET_KEY>>8);        //读按键的命令字
  75.           CH452_LOAD_CLR();
  76.           for(i=0; i<4; i++)  // 只需要发出高4位,多发也可以,但应该确保最后留下的4位是该命令码
  77.         {
  78.             // 输出位数据
  79.                 if (cmd & 1)
  80.                 {
  81.                     CH452_DIN_SET();
  82.                 }
  83.                 else
  84.                 {
  85.                     CH452_DIN_CLR();
  86.                 }  
  87.             CH452_DCLK_CLR();               
  88.                 CH452_Delay(DLCK_FREQ_DELAY);
  89.             cmd>>=1;                              //往右移一位\
  90.             CH452_DCLK_SET();                              //产生时钟上升沿锁通知CH451输入位数据
  91.             CH452_Delay(DLCK_FREQ_DELAY);
  92.         }
  93.           CH452_LOAD_SET();                                      //产生加载上升沿通知CH451处理命令数据

  94.         // 读取7位键值(高位在前)
  95.           keycode=0;                                      //清除keycode
  96.           for(i=0; i<7; i++)
  97.         {
  98.                 keycode <<= 1;                              //数据移入keycode,高位在前,低位在后
  99.                 if (CH452_DOUT_READ())
  100.                 {
  101.                     keycode++;      //从高到低读入数据
  102.                     //keycode |= 0x01;
  103.                 }
  104.             CH452_DCLK_CLR();                              //产生时钟下升沿通知CH451输出下一位
  105.             CH452_Delay(DLCK_FREQ_DELAY);
  106.             CH452_DCLK_SET();
  107.                 CH452_Delay(DLCK_FREQ_DELAY);
  108.         }
  109.           CLEAR_KEY_INT_FLAG();             //清中断标志
  110.           ENABLE_KEY_INTERRUPT();
  111.        
  112.           return keycode;                             //反回键值
  113. }


  114. // 写入数据到CH452A,更新LED扫描
  115. void CH452_UpdateRow(uint8_t row, uint8_t data)
  116. {
  117.     uint16_t cmd = 0;
  118.    
  119.     switch(row)
  120.         {
  121.         case 0:
  122.                         cmd = CH452_DIG0;
  123.                         break;
  124.         case 1:
  125.                         cmd = CH452_DIG1;
  126.                         break;
  127.         case 2:
  128.                         cmd = CH452_DIG2;
  129.                         break;
  130.         case 3:
  131.                         cmd = CH452_DIG3;
  132.                         break;
  133.         case 4:
  134.                         cmd = CH452_DIG4;
  135.                         break;
  136.                 case 5:
  137.                         cmd = CH452_DIG5;
  138.                         break;
  139.                 case 6:
  140.                         cmd = CH452_DIG6;
  141.                         break;
  142.                 case 7:
  143.                         cmd = CH452_DIG7;
  144.                         break;
  145.         default:
  146.                         return;
  147.     }
  148.    
  149.     // 更新显示缓冲区和硬件
  150.     CH452_Write(cmd | data);
  151. }
以上的对CH452的解读分享,给大家提供参考。


 楼主| dffzh 发表于 2025-11-11 10:47 | 显示全部楼层
#申请原创#
@21小跑堂 管理员,你好,求原创审核哦!
sxy4517 发表于 2025-11-11 13:44 来自手机 | 显示全部楼层
数码管还用在哪些行业?
 楼主| dffzh 发表于 2025-11-11 14:35 | 显示全部楼层
sxy4517 发表于 2025-11-11 13:44
数码管还用在哪些行业?

我们是用CH452来驱动LED阵列的,和驱动数码管类似。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

208

主题

1797

帖子

23

粉丝
快速回复 在线客服 返回列表 返回顶部