STM32与CH455g通信测试(仅键盘)
1、概述
CH455是数码管显示驱动和键盘扫描控制芯片。CH455内置时钟振荡电路,可以动态驱动4位数码管或者32只LED;同时还可以进行28键的键盘扫描;CH455通过SCL和SDA组成的2线串行接口与单片机等交换数据。

2、特点
●内置显示电流驱动级,段电流不小于25mA,字电流不小于160mA。
●动态显示扫描控制,支持8×4或者7×4,直接驱动4位数码管或者32只发光管LED。
●内部限流,通过占空比设定提供8级亮度控制。
●内置28键键盘控制器,基于7×4矩阵键盘扫描。
●内置按键状态输入的下拉电阻,内置去抖动电路。
●提供低电平有效的键盘中断,提供按键释放标志位,可供查询按键按下与释放。
●高速2线串行接口,时钟速度从0到4MHz,兼容两线I2C总线,节约引脚。
●内置上电复位,支持2.7V~5V电源电压。
●支持低功耗睡眠,节约电能,可以被按键唤醒或者被命令操作唤醒。
●内置时钟振荡电路,不需要外部提供时钟或者外接振荡元器件,更抗干扰。
3、引脚介绍

VCC:电源正电源,持续电流不小于150mA
GND:电源公共接地,持续电流不小于150mA
SEG0 ~SEG6:三态输出及输入数码管的段驱动,高电平有效,键盘扫描输入,高电平有效,内置下拉
SEG7:输出数码管的小数点段驱动输出,高电平有效,7段模式下的键盘中断输出,低电平有效
DIG0 ~DIG3:输出数码管的字驱动,低电平有效,键盘扫描输出,高电平有效
SDA:内置上拉开漏输出及输入2线串行接口的数据输入和输出,内置上拉电阻SCL:输入2线串行接口的数据时钟,内置上拉电阻
4、键盘扫描功能
键盘扫描CH455的键盘扫描功能支持7×4矩阵的28键键盘。在键盘扫描期间,DIG3~DIG0引脚用于列扫描输出,SEG6~SEG0引脚都带有内部下拉电阻,用于行扫描输入。CH455定期在显示驱动扫描过程中插入键盘扫描。在键盘扫描期间,DIG3~DIG0引脚按照DIG0至DIG3的顺序依次输出高电平,其余引脚输出低电平;SEG6~SEG0引脚的输出被禁止,当没有键被按下时,SEG6~SEG0都被下拉为低电平;当有键被按下时,例如连接DIG1与SEG4的键被按下,则当DIG1输出高电平时SEG4检测到高电平;为了防止因为按键抖动或者外界干扰而产生误码,CH455实行两次扫描,只有当两次键盘扫描的结果相同时,按键才会被确认有效。如果CH455检测到有效的按键,则记录下该按键代码,并通过INT#引脚产生低电平有效的键盘中断,此时单片机可以通过串行接口读取按键代码;在没有检测到新的有效按键之前,CH455不再产生任何键盘中断。CH455支持SEG1和SEG0针对同一DIG的组合键,组合键是最优先的,除此之外,如果多个键同时按下,那么按键代码较小的按键优先。例如连接DIG1与SEG1及连接DIG1与SEG0的两个键,可作为组合键。CH455所提供的按键代码为8位,位7始终为0,位2始终为1,位1~位0是列扫描码,位5~位3是行扫描码,位6是状态码(键按下为1,键释放为0)。例如,连接DIG1与SEG4的键被按下,则按键代码是01100101B或者65H,键被释放后,按键代码通常是00100101B或者25H(也可能是其它值,但是肯定小于40H),其中,对应DIG1的列扫描码为01B,对应SEG4的行扫描码为100B。单片机可以在任何时候读取按键代码,但一般在CH455检测到有效按键而产生键盘中断时读取按键代码,此时按键代码的位6总是1,另外,如果需要了解按键何时释放,单片机可以通过查询方式定期读取按键代码,直到按键代码的位6为0。下表是在DIG3~DIG0与SEG6~SEG0之间7×4矩阵的按键编址,也是数码管段位和发光管LED阵列的顺序编址。由于按键代码是8位,键按下时位6总是1,所以当键按下时,CH455所提供的实际按键代码是表中的按键编址加上40H,也就是说,此时的按键代码应该在44H到7FH之间。
| 编址 | DIG3 | DIG2 | DIG1 | DIG0 |
| SEG0 | 07H | 06H | 05H | 04H |
| SEG1 | 0FH | 0EH | 0DH | 0CH |
| SEG2 | 17H | 16H | 15H | 14H |
| SEG3 | 1FH | 1EH | 1DH | 1CH |
| SEG4 | 27H | 26H | 25H | 24H |
| SEG5 | 2FH | 2EH | 2DH | 2CH |
| SEG6 | 37H | 36H | 35H | 34H |
| SEG0+SEG1 | 3FH | 3EH | 3DH | 3CH |
5、串行接口
CH455具有硬件实现的2线串行接口,包含2个主要信号线:串行数据时钟输入线SCL、串行数据输入和输出线SDA;以及1个辅助信号线:中断输出线INT#。其中,SCL是带上拉的输入信号线,CH455中文手册4默认是高电平;SDA是带上拉的准双向信号线,默认是高电平;INT#是带上拉的开漏输出,在启用键盘扫描功能后作为键盘中断输出线,默认是高电平。SDA用于串行数据输入和输出,高电平表示位数据1,低电平表示位数据0,串行数据输入的顺序是高位在前,低位在后。SCL用于提供串行时钟,CH455在其上升沿从SDA输入数据,在其下降沿从SDA输出数据。在SCL为高电平期间发生的SDA下降沿定义为串行接口的启动信号,在SCL为高电平期间发生的SDA上升沿定义为串行接口的停止信号。CH455只在检测到启动信号后才接收并分析命令。所以在单片机I/O引脚资源紧张时,可以在保持SDA引脚状态不变的情况下,将SCL引脚与其它接口电路共用;如果能够确保SDA引脚的变化仅在SCL引脚为低电平期间发生,那么SCL引脚和SDA引脚都可以与其它接口电路共用。INT#用于键盘中断输出,默认是高电平。当CH455检测到有效按键时,INT#输出低电平有效的键盘中断;单片机被中断后,对CH455执行读操作,CH455将INT#恢复为高电平,并从SDA输出按键代码,单片机从SDA获得一个字节的数据,即按键代码。单片机与CH455的通讯过程总是分为6个步骤,按单片机的操作方向分成两种类型,一种是写操作,用于输出数据,一种是读操作,用于输入数据。具体过程可以参考例子程序中的说明。写操作包括以下6个步骤:输出启动信号、输出字节1、应答1、输出字节2、应答2、输出停止信号。其中,启动信号和停止信号如上所述,应答1和应答2总是固定为1,输出字节1和输出字节2各自包含8个数据位,即一个字节数据。读操作包括以下6个步骤:输出启动信号、输出字节1、应答1、输入字节2、应答2、输出停止信号。其中,启动信号和停止信号如上所述,应答1和应答2总是固定为1,输出字节1和输入字节2各自包含8个数据位,即一个字节数据。
6、操作命令
CH455的操作命令分为3组。各命令的启动信号、停止信号、应答1和应答2都相同,区别在于输出字节1和字节2的数据不同以及字节2的传输方向不同。
加载字数据命令:该命令的输出字节1为地址68H、6AH、6CH或者6EH,分别对应于DIG0~DIG3引脚驱动的4个数码管;输出字节2为[DIG_DATA]B,即00H到0FFH之间的值,是8位的字数据。加载字数据命令用于将字数据DIG_DATA写入字节1指定地址的数据寄存器中。例如,命令数据01101100B(即6CH对应DIG2)、01111001B表示将字数据79H写入第1个数据寄存器,使DIG2引脚驱动的数码管将显示E。
读取按键代码命令:该命令的输出字节1为01001111B,即4FH;输入字节2为按键代码。读取按键代码命令用于获得CH455最近检测到的有效按键的按键代码。该命令属于读操作,是唯一的具有数据返回的命令,单片机必须先释放SDA引脚(三态输出禁止或者上拉到高电平),然后CH455从SDA引脚输出按键代码,按键代码的有效数据是位7~位0,其中位6是状态码,位5~位0是扫描码和按键编址。
7、接口时序

TSSTA/THSTA/TSSTO/THSTO/TCLOW/TCHIG:最小时间100ns
TSD:最小时间30ns
THD:最小时间10ns
TAA/TDH:最小时间2ns
Rate:最大速率4Mbps
8、原理图接线

9、程序设计
由于这次只是做个简单的按键检测,所以只用到键盘扫描功能,数码管有需要再做吧。先定义一下系统参数:

// 设置系统参数命令
#define CH455_SCL_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET)
#define CH455_SCL_CLR HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET)
#define CH455_SCL_D_OUT {} // 设置SCL为输出方向,对于双向I/O需切换为输出 #define CH455_SDA_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)
#define CH455_SDA_CLR HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)
#define CH455_SDA_IN HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_9) // 读取SDA输入电平 #define CH455_BIT_ENABLE 0x01 // 开启/关闭位
#define CH455_BIT_SLEEP 0x04 // 睡眠控制位
#define CH455_BIT_7SEG 0x08 // 7段控制位
#define CH455_BIT_INTENS1 0x10 // 1级亮度
#define CH455_BIT_INTENS2 0x20 // 2级亮度
#define CH455_BIT_INTENS3 0x30 // 3级亮度
#define CH455_BIT_INTENS4 0x40 // 4级亮度
#define CH455_BIT_INTENS5 0x50 // 5级亮度
#define CH455_BIT_INTENS6 0x60 // 6级亮度
#define CH455_BIT_INTENS7 0x70 // 7级亮度
#define CH455_BIT_INTENS8 0x00 // 8级亮度 #define CH455_SYSOFF 0x0400 // 关闭显示、关闭键盘
#define CH455_SYSON ( CH455_SYSOFF | CH455_BIT_ENABLE ) // 开启显示、键盘
#define CH455_SLEEPOFF CH455_SYSOFF // 关闭睡眠
#define CH455_SLEEPON ( CH455_SYSOFF | CH455_BIT_SLEEP ) // 开启睡眠
#define CH455_7SEG_ON ( CH455_SYSON | CH455_BIT_7SEG ) // 开启七段模式
#define CH455_8SEG_ON ( CH455_SYSON | 0x00 ) // 开启八段模式
#define CH455_SYSON_4 ( CH455_SYSON | CH455_BIT_INTENS4 ) // 开启显示、键盘、4级亮度
#define CH455_SYSON_8 ( CH455_SYSON | CH455_BIT_INTENS8 ) // 开启显示、键盘、8级亮度 // CH455接口定义
#define CH455_I2C_ADDR 0x40 // CH455的地址
#define CH455_I2C_MASK 0x3E // CH455的高字节命令掩码 // 读取按键代码命令
#define CH455_GET_KEY 0x0700 // 获取按键,返回按键代码
define
另外,用的是stm32的HAL库,但是IIC通讯依然用的是IO口模拟IIC的,主要是因为CH455g的器件地址没有找到,其次是HAL库自带的IIC模块不太可靠。

//--------------------------------------------i2c-------------------------------------------
// 设置SDA为输出方向,对于双向I/O需切换为输出
void CH455_SDA_D_OUT()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } // 设置SDA为输入方向,对于双向I/O需切换为输入
void CH455_SDA_D_IN()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void CH455_I2c_Start( void ) // 操作起始
{
//DISABLE_KEY_INTERRUPT; //禁止键盘中断,防止开始时被CH455中断而进入中断服务程序中的START CH455_SDA_SET; /*发送起始条件的数据信号*/
CH455_SDA_D_OUT(); /* 设置SDA为输出方向 */
CH455_SCL_SET;
CH455_SCL_D_OUT; /* 设置SCL为输出方向 */
HAL_Delay(10);
CH455_SDA_CLR; /*发送起始信号*/
HAL_Delay(10);
CH455_SCL_CLR; /*钳住I2C总线,准备发送或接收数据 */
} void CH455_I2c_Stop( void ) // 操作结束
{
CH455_SDA_CLR;
CH455_SDA_D_OUT(); /* 设置SDA为输出方向 */
HAL_Delay(10);
CH455_SCL_SET;
HAL_Delay(10);
CH455_SDA_SET; /*发送I2C总线结束信号*/
HAL_Delay(10);
CH455_SDA_D_IN(); /* 设置SDA为输入方向 */
//ENABLE_KEY_INTERRUPT;
} void CH455_I2c_WrByte( uint8_t dat ) //写一个字节数据
{
uint8_t i;
CH455_SDA_D_OUT(); /* 设置SDA为输出方向 */
for( i = 0; i != 8; i++ ) // 输出8位数据
{
if( dat & 0x80 )
{
CH455_SDA_SET;
}
else
{
CH455_SDA_CLR;
}
HAL_Delay(10);
CH455_SCL_SET;
dat <<= 1;
HAL_Delay(10); // 可选延时
CH455_SCL_CLR;
}
CH455_SDA_D_IN(); /* 设置SDA为输入方向 */
CH455_SDA_SET;
HAL_Delay(10);
CH455_SCL_SET; // 接收应答
HAL_Delay(10);
CH455_SCL_CLR;
} uint8_t CH455_I2c_RdByte( void ) //读一个字节数据
{
uint8_t dat,i;
CH455_SDA_SET;
CH455_SDA_D_IN(); /* 设置SDA为输入方向 */
dat = 0;
for( i = 0; i != 8; i++ ) // 输入8位数据
{
HAL_Delay(10); // 可选延时
CH455_SCL_SET;
HAL_Delay(10); // 可选延时
dat <<= 1;
if( CH455_SDA_IN ) dat++; // 输入1位
CH455_SCL_CLR;
}
CH455_SDA_SET;
HAL_Delay(10);
CH455_SCL_SET; // 发出无效应答
HAL_Delay(10);
CH455_SCL_CLR;
return dat;
} void CH455_Write( uint16_t cmd ) //写命令
{
CH455_I2c_Start(); //启动总线
CH455_I2c_WrByte(((uint8_t)(cmd>>7)&CH455_I2C_MASK)|CH455_I2C_ADDR);
CH455_I2c_WrByte((uint8_t)cmd); //发送数据
CH455_I2c_Stop(); //结束总线
} uint8_t CH455_Read( void ) //读取按键
{
uint8_t keycode;
CH455_I2c_Start(); //启动总线
CH455_I2c_WrByte((uint8_t)(CH455_GET_KEY>>7)&CH455_I2C_MASK|0x01|CH455_I2C_ADDR);
keycode=CH455_I2c_RdByte(); //读取数据
CH455_I2c_Stop(); //结束总线
return keycode;
}
IO口模拟IIC
主函数开启中断和键盘:
HAL_ADC_Start_IT(&hadc1);
CH455_Write( CH455_7SEG_ON );// 开启显示和键盘,8段显示方式
写完回调函数,即可打印输出键码:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
RX_AD = HAL_ADC_GetValue(&hadc1);
if(RX_AD == 0)
{
RX_CH455 = CH455_Read();
printf("键码:%x\r\n",RX_CH455);
}
}
完了给大伙看看按键打印结果:

需要程序的记得留言打赏哦
STM32与CH455g通信测试(仅键盘)的更多相关文章
- STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)
本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可. 1.键盘原理图: 原理举例:先把 F0-F7 内部拉高,这样 ...
- Tkinter 鼠标键盘事件(二)
一个Tkinter主要跑在mainloop进程里.Events可能来自多个地方,比如按键,鼠标,或是系统事件. Tkinter提供了丰富的方法来处理这些事件.对于每一个控件Widget,你都可以为其绑 ...
- python tkinter教程-事件绑定
一个Tkinter主要跑在mainloop进程里.Events可能来自多个地方,比如按键,鼠标,或是系统事件. Tkinter提供了丰富的方法来处理这些事件.对于每一个控件Widget,你都可以为其绑 ...
- [FreeRTOS入门] 1.CubeMX中FreeRTOS配置参数及理解
1.有关优先级 1.1 Configuration --> FreeRTOS MAX_PRIORITIES 设置任务优先级的数量:配置应用程序有效的优先级数目.任何数量的任务都可以共享一个优先级 ...
- python tkinter中的事件绑定
一个Tkinter主要跑在mainloop进程里.Events可能来自多个地方,比如按键,鼠标,或是系统事件. Tkinter提供了丰富的方法来处理这些事件.对于每一个控件Widget,你都可以为其绑 ...
- 【STM32学习笔记】STM32f407 使用4*4矩阵键盘
作者:李剀 出处:https://www.cnblogs.com/kevin-nancy/ 欢迎转载,但也请保留上面这段声明.谢谢! 写在前面: 这是本人第一次开始写博客,可能写的不是很好,也请大家谅 ...
- ARM开发(3)基于STM32的矩阵键盘控制蜂鸣器
一 矩阵键盘控制蜂鸣器原理: 1.1 本实验实现8*7矩阵键盘上按键控制蜂鸣器响. 1.2 实验思路:根据电路图原理,找出矩阵键盘行列所对应的引脚,赋予对应的按键值,然后控制蜂鸣器响. 1.3 ...
- stm32 hid 键盘描述
/* USB Standard Device Descriptor */ const uint8_t Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DES ...
- stm32矩阵键盘扫描数据通过USB发送
Keyboard.c #include "keyboard.h"#include "my_usb.h"#include " ...
随机推荐
- google protocol buffer——protobuf的编码原理二
这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...
- k8s部署mysql主从复制
Mysql主从 准备环境 一,准备软件 官方docker_image :Mysql5.7.28 Docker Version: 19.03.4 K8s api-version: ...
- LeetCode 95 | 构造出所有二叉搜索树
今天是LeetCode专题第61篇文章,我们一起来看的是LeetCode95题,Unique Binary Search Trees II(不同的二叉搜索树II). 这道题的官方难度是Medium,点 ...
- Java/后端学习路线
点赞再看,养成习惯,微信搜一搜[三太子敖丙]关注这个喜欢写情怀的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系 ...
- python笔记-正则表达式
什么是正则表达式: 正则表达式是一个特殊的字符序列,能帮助我们方便的检查一个字符串是否与某种模式匹配(定义往往都很枯燥) 也称之为”模式“,即可用于检查一个给定的字符串是否符合某种模式 举例: 我们定 ...
- Animator.SetFloat(string name,float value,float dampTime,float deltaTime)详解
一般来说,我们用到的是这个API: animator.SetFloat("Speed",2.0f); 但是这个还有一个重载的方法,叫做: Animator.SetFloat(str ...
- python学习第八天
解析库之bs4的基本使用方法 ''' pip install beautifulsoup4#安装bs4 pip install lxml#安装lxml ''' html_doc = "&qu ...
- HDU - 5775-Bubble Sort(权值线段树)
P is a permutation of the integers from 1 to N(index starting from 1). Here is the code of Bubble So ...
- 520是秀恩爱吃狗粮,521才是真正的告白日,- Python告白神器用起来 !
网络情人节是信息时代的爱情节日,定于每年的5月20日和5月21日,该节日源于歌手范晓萱的<数字恋爱>中“520”被喻成“我爱你” ,以及音乐人吴玉龙的网络歌曲中“我爱你”与“网络情人”的紧 ...
- C#操作Excel开发报表系列整理
C#操作Excel进行报表开发系列共写了八篇,也已经有很久没有新东西了,现在整理一下,方便以后查阅,如果有写新的,会同时更新.需要注意的是因为Office的版本不同,实际的代码可能会有所不同,但是都是 ...