CH552 USB HID键盘

时间:2024-10-20 07:36:07

客制化键盘制作V1——CH552工程

目前正在客制化一个小键盘,计划8月中旬在咸鱼上售卖,功能包括:

  1. 蓝牙有线双模,蓝牙
    5.0(nrf52810),低功耗模式
  2. 按键+旋钮
  3. 自定义按键,可设置组合键和多媒体键,专用软件设置
  4. WS2812灯效
    看到很多人有私信问我,目前我做的是CH583蓝牙双模键盘(半成品,已无限期搁置),已经完成的有CH552G旋钮键盘和CH579的数字键盘,可以去我的网站 找找思路哦。

一、CH552简介

CH552是一款包含USB功能的单片机,还包含多个外设,如ADC、PWM、串口、SPI等,可以通过USB外设实现HID键盘和模仿CH340进行串口通信。
CH552输入可以5.0V,无需外部晶振即可工作,使用5.0V电压时,仅需要2个退耦电容。

二、CH552与蓝牙芯片通信

通信可以使用串口、SPI以及其它方法,为方便通信,本次只计划使用串口进行通信。通信波特率选择115200,在这个频率下,可以实现接近1000Hz的通信次数。
当然也可以选择更高的波特率,但是网上资料显示,更高的波特率可能会出现错误。

三、CH552的功能及方案

1. 功能介绍

由于键盘的其它功能都是由蓝牙芯片NRF52810实现,因此仅在有线模式和自定义按键设置时需要该芯片。

有线模式:识别为HID键盘,接收串口的数据,并使用USB发送出去。需要对串口的数据进行校验,发送或接收错误时会串口返回错误码。
自定义按键设置模式:识别为CH340芯片,与电脑进行虚拟串口通信,原封不动地将数据通过串口与蓝牙芯片交换。

2. 方案

模式变化:以上两种模式通过一个外部引脚(检测引脚)进行控制(实际上是通过拨动开关实现),当该引脚为高阻态时进入有线模式,为高电平时进入 自定义按键模式。
识别:当CH552上电时,设置检测引脚为高电平,再为低电平,然后检测引脚状态。注意检测结束后要及时将引脚转换为高电平。实际上,CH552并没有输入模式,他检测高低电平的原理是利用高电平无驱动能力试下的,即将单片机引脚设置为高电平,虽然电压检测引脚是高电平,但实际上是没有向外部输出电流的能力的,如果直接将该引脚接地,也不会有电流输出,但引脚读取的时候,就会读取到低电平。但引脚有灌入电流,当引脚设置为低电平的时候,接高电平的时候电流会有45mA的样子,虽然正常使用,但一段时间后芯片确实有点发热。(由于电路设计不合理,只能暂时这样操作)。

3. 串口数据校验

在有线模式下,需要接收来自蓝牙芯片的串口数据,为了防止数据错误和不同数据类型识别,需要对数据进行封装。封装包括:起始位,数据,校验位和截至位。

起始位A:检测为普通数据,数据位共7Bytes,校验位和截至位没问题时直接发送该7Bytes数据。
起始位B:检测为媒体数据,数据为4Bytes,校验位和截至位没问题时直接发送;但发送前需要检测上一次普通数据是否清零,未清零需要先发送清零的普通数据再发送多媒体数据。
失败:校验位失败则串口返回失败码ERROR。

4. 流程

  1. 上电,检测引脚检测,根据情况配置不同USB模式

5. 已完成代码

  1. 通过引脚判断模式
  2. 通过不同的描述符,配置USB为HID设备或CH340设备
  3. HID设备时,接收串口数据,进行校验后发送出去,包括普通按键和多媒体按键,不做任何处理。
  4. CH340设备实现串口通信一直失败,无法实现单片机与蓝牙模块的串口通信,后来通过官方其它例程,才发现是串口中断没有打开,就很离谱。还以为是HID例程中的函数导致的串口中断问题。

四、CH552单芯片版本(有线单模)

蓝牙键盘焊接后,出现了各种问题,包括整体功耗大,自己焊接的陶瓷天线信号微弱等,由于博主目前无太多精力解决上述问题,因此打算转向单模有线版本。
芯片仍然使用CH552,这是目前了解到的最便宜的带USB功能的芯片了。并没有采用qmk,以及其推荐芯片ATMega型号,打算自己从0开始编写。
以下为最新的键盘情况:旋钮控制音量和播放暂停;按键控制上下曲,以及某些软件的快捷键。

键盘图片

1. 按键读取、EC11旋钮读取

  1. 按键读取方式为间隔2ms读取一次引脚,当连续5次为低电平时,定义该引脚按下。EC11旋钮则引脚A为连续两次为低电平时,读取B引脚,如果为高电平为逆时针选择,否则为顺时钟旋转。
  2. 上述的连续几次读取是软件滤波,可以去除按键抖动的情况,实际体验并没有出现延迟的情况。但旋钮在旋转很快的时候,会出现读取错误,会被认为逆时针和顺时针交替,但一般旋转不影响。

2. CH552 ws2812实现

  1. 虽然ch552拥有PWM,之前使用过STM32和NRF52芯片,均使用PWM+DMA的方式驱动WS2812。但是考虑到CH552性能不佳,还是直接通过操作引脚实现,通过nop进行操作,当系统频率为24MHZ时,每个nop的时间差不多为65us,按照WS2812手册进行编写即可。
  2. 但发现ws2812显示会出现错误数据的情况,排查后发现是上面按键读取中的2ms中断导致的:程序中有一个2ms的定时器中断,用于指示按键读取一次,虽然在中断中只进行了3次赋值操作,但影响很大。解决方法为,在WS2812操作前关闭定时器中断,完成后打开定时器中断,由于WS2812操作,因此不影响。以下查看键盘最新图片:

3. 键鼠多媒体键盘

  1. 一个好的键盘,不仅能够实现普通键盘的功能,还应该集合鼠标、多媒体按键的功能,实现键鼠多媒体按键。另外,传统的HID键盘,由于其报告描述符限制,只能实现6键无冲。
  2. 解决方法:增加设备接口数量,第一个接口为键鼠合集,第二个接口为多媒体按键;或者键鼠多媒体都使用一个接口,使用一个报告描述符。
  3. 测试结果:成功实现键盘、鼠标、多媒体按键功能为一体,并且解决无冲键数量只有6的限制。具体操作为主页中的另一篇博客,但我隐藏了,看情况公开。

4. 自定义按键存取问题

  1. 按键要自定义,首先要保证自定义的数据能够断电存储,但是CH552不像stm32等“高端芯片”那样,可以直接读取内部的flash,有个网友是说CH552利用的是iflash,存取次数只有200次,所以芯片才这么便宜。具体是不是200次,我等之后不断烧录代码测试下。
  2. 添加外部flash或eeprom是一个方法,选择eeprom,价格更加便宜,但是引来另一个问题,即CH552引脚不够。虽然考虑过使用按键扫描芯片,但其只能检测单按键;或移位寄存器,但需要添加二极管防止引脚同时按下的短路。采用矩阵按键,也需要添加按键,电路也更加复杂,放弃。
  3. 解决方法:按键选两个引脚出来,连接到eeprom中。因为存取数据的次数不多,只需要保证这个过程中,没按键按下即可。当然,写入的数据需要校验码验证,防止意外的错误。

5. 在线实时修改参数

  1. 一个好的客制化键盘,需要能够用户自己修改按键的值以及其他参数,如WS2812灯效等。不能让用户重新烧录,一方面麻烦,另一方面也透露了自己的代码(虽然之后我会开源代码)。
  2. 开始思考的方法是键盘通电时选择模式为HID模式,或模仿为ch340串口芯片,当为串口模式时,用户可以通过串口给单片机传输数据。这个已经实现了,但是发现过于占用CH552为数不多的资源,也比较麻烦。
  3. 在看到键鼠多媒体键盘的实现思路之后,想到一个方法:即再加入一个接口,多一个用户自定义的HID设备,通过这个HID设备进行数据通信。目前已经完成了该接口的数据收发,对键盘的LED灯进行实时修改,但仍有一个小问题,出现了数组内存移位的问题,需要之后验证。但该方法就需要上位机访问到该设备,相比于串口通信,需要的步骤更为复杂,也更为底层,因此需要使用到C++语言进行编写。博主C++本来就不佳,上次写C++应用程序还是3年前的大学一门课上。原来python早已封装好了库,使用pywinusb即可。
  4. 之前测试发送单片机接收sub数据正常,但是发送数据出现数据移位的问题,开始还不知道为什么,原来是启动数据的发送和接收,那么单片机端的数据发送存放的buf地址,需要在接收buf地址之后,两个buf并不是互用的。因此发送的时候,需要将待发送buf加上最大地址长度,即可试下正常的数据收发。