对于现在的电脑来说,USB是外部通讯的不二选择,通过这个接口可以引出键盘鼠标等等外部设备。这次尝试使用国产的 CH55X 系列单片机来做一个 USB 提醒器,通过这个设备能够做到LED 发光提示还有蜂鸣器声音提示。
首先介绍一下 CH55X 系列芯片是南京沁恒(WCH)出品的带有USB功能的系列单片机【参考1】,提起这家公司的名称大多数人会感到陌生,但是如果提起CH340/CH341芯片大家都会非常熟悉,这款低成本的USB串口转换芯片就是这家公司的产品。这次设计用到的 CH552 和 CH551/CH554 是同一个系列。他们主要的差别是:CH551 是最低端的,工作频率是 24Mhz,FLASH 有 10K (可以看作是单片机的 ROM),内存是 512+256字节,只能做 USB Device;CH552比前者配置稍微高了一些,FLASH空间有16K,内存有1K+256字节,只能做 USB Device;CH554比前面都高级,FLASH 和 内存和 CH552 相同,但是可以当作 USB Host 使用能够实现解析USB 键盘鼠标这样设备的工作。可以看出,相比 Atmel 的 32U4 (Arduino Leonardo),主要缺点是内存太小。但是胜在价格便宜,引脚简单(这样容易焊接)。在立创商城上面的芯片价格如下(CH552/4 不同封装引脚数量不同,所以价格是在一个范围内)
CH551G 2.475元
CH552 2.7-2.78元
Ch554 5.43-7.03元
32u4 23.51元
因此,如果CH55X 系列芯片能够满足你的需求,能够大大降低成品的成本。同时, CH55X 系列单片机对于外围元件要求极低,无须晶振,只要合适的贴片电容即可工作起来。
这次设计使用CH552G芯片是 SOP16 封装,同样的 CH554 也有SOP16封装可以直接替换(CO-Layout)

电路设计如下:

这个芯片使用C1/C2 两个 0.1uF 的电容即可工作,5V 供电,从 VCC/VDD 引脚进入。上图中 V33 经过 R1 (10K)连接到 USB+引脚上,其中的 PAD1无须上键在这里作为开关使用用于控制芯片进入 Bootloader Mode。
板子上还有一个 WS2812B MINI(3.5×3.5mm) 用于提供灯光提示,同样的这个元件无须外围配合,直接用CH55X P1.5即可控制:

外围有一个蜂鸣器,因为CH55X 引脚提供电流有限,所以使用S8050这个三极管扩流,同时外加R3用于限流,主要是避免声音太大。CH55X P3.4 Pin 用于控制蜂鸣器开关。因为该引脚是 PWM 引脚,因此这里即可以使用有源蜂鸣器和无源蜂鸣器。有源蜂鸣器的含义是“内部有震荡源”,类似于电动机,有了供电就能发声;与其相反,无源蜂鸣器含义是“内部没有震荡源”,因此需要用引脚电流变换来驱动它。对于有源蜂鸣器,P3.4 当作普通的GPIO 即可;对于无源蜂鸣器,需要设定为 PWM 然后给他设置占空比和频率(默认即可)。

PCB 设计如下:

切换为 3D 模式预览如下(这次设计的 Symbol使用的都是嘉立创的,所以自带了 3D 模型,非常直观):


拿到手的 PCB和焊接后的照片如下:

接下来就开始软件设计了。这个芯片原本设计使用 C51 来进行变成,用户可以通过 Keil 这样的集成开发环境进行编程,但是对于我们来说C51还是过于复杂。这里使用 Github上的一个开源项目:ch55xduino【参考2】,能够让我们像开发 Arduino 一样为 CH551/2/4 进行开发。
首先介绍一下项目的安装:和其他的所有的第三方板卡一样, 在 Preferences –> Additional Boards Manager URLs 中加入这个板卡的地址https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json

之后打开 Boards Manager

搜索这个项目

Install 安装之后在 Boards Manager 中能够看到这个板卡,编译时,CH551使用 CH551 Board, CH552/4 使用 CH552 Board

接下来就是如何编译一个程序,可以在 Example 中看到专用的例子,比如下面就是关于 USB 设备的例子:

打开一个例子尝试编译,完成后就需要做上传的准备工作了。刚拿到手 ,板子上没有Bootloader,需要短接板子背面 PAD 处(电路图中是0.1uF电容,实际上不上件预留为空),这样V33会通过10K 电阻后进入 D+ Pin,板子会进入 Bootloader Mode。


属性如下:

使用 Zadig 给他安装一个驱动,勾选 Edit

重命名为 USB Module

安装之后:

编译后会自动搜索名为 “USB Module”的设备并且上传

需要注意的是:如果你的代码没有实现 USB 串口,那么只能短接PAD 让板子进入 BootLoader Mode再次上传。
了解了上面的知识,即可着手设计代码实现提醒器的功能。我们设计了2种提醒方式:LED 和蜂鸣器,分别通过2个命令进行设置,形式如下:
- [cRGB] R/G/B 分别是红绿蓝的取值,例如,命令 [c123] (ASCII) 5B 63 31 32 33 5D (十六进制)会将 LED RGB 分别设置为 0x31 0x32 0x33;命令 5B 63 FF 00 00 5D (十六进制)会设置为全红;
- [bThighTlow] Vhigh和 Vlow 分别是设置的时间高位和地位,例如, 命令 [b12] (ASCII) 5B 62 31 32 5D (十六进制)将会设置蜂鸣器在 0x32 * 0x10 +0x32=0x342 (834秒)后响起来;命令5B 62 01 00 5D (十六进制)将会设置蜂鸣器在 0x01 * 0x100 +0x00=0x100 (256秒)后响起来;可以看出,可以设置最大 0xFFFF (65535秒)后响起来。
完整代码如下:
#define BEEPERPIN 34
#define LEDPIN 15
#define TX(LedColor) {\
if (((LedColor)&0x80)==0) {\
XdigitalWriteFast(1,5,HIGH);\
(LedColor)=(LedColor)<<1;\
XdigitalWriteFast(1,5,LOW);\
XdigitalWriteFast(1,5,LOW);\
XdigitalWriteFast(1,5,LOW);\
}else{\
XdigitalWriteFast(1,5,HIGH);\
XdigitalWriteFast(1,5,HIGH);\
XdigitalWriteFast(1,5,HIGH);\
XdigitalWriteFast(1,5,HIGH);\
XdigitalWriteFast(1,5,HIGH);\
XdigitalWriteFast(1,5,HIGH);\
XdigitalWriteFast(1,5,HIGH);\
(LedColor)=(LedColor)<<1;\
XdigitalWriteFast(1,5,LOW);\
XdigitalWriteFast(1,5,LOW);\
XdigitalWriteFast(1,5,LOW);\
XdigitalWriteFast(1,5,LOW);\
XdigitalWriteFast(1,5,LOW);\
}\
}
#ifndef USER_USB_RAM
#error "This example needs to be compiled with a USER USB setting"
#endif
#include "src/userUsbCdc/USBCDC.h"
void setup() {
// 设置蜂鸣器Pin 为Low (停止发声)
pinMode(BEEPERPIN,OUTPUT);
digitalWrite(BEEPERPIN,LOW);
// 设置LED 控制Pin
pinMode(LEDPIN,OUTPUT);
digitalWrite(LEDPIN,LOW);
USBInit();
}
byte Status=0;
byte RValue,GValue,BValue;
byte THigh=0,TLow=0;
unsigned long CounterDown=0xFFFFFFFF;
void loop() {
while (USBSerial_available()) {
// 接收来自USB串口的字符
char serialChar = USBSerial_read();
if ((serialChar == '[')&&(Status==0)) { Status=1; continue;}
if ((serialChar == 'c')&&(Status==1)) {Status=2; continue;}
if (Status==2) {RValue=serialChar; Status=3; continue;}
if (Status==3) {GValue=serialChar; Status=4; continue;}
if (Status==4) {BValue=serialChar; Status=5; continue;}
if (Status==5) {
if (serialChar == ']') {Status=6;continue;}
else {Status=0; continue;}
}
if ((serialChar == 'b')&&(Status==1)) {Status=7; continue;}
if (Status==7) {THigh=serialChar; Status=8; continue;}
if (Status==8) {TLow=serialChar; Status=9; continue;}
if (Status==9) {
if (serialChar == ']') {Status=10; continue;}
else {
// 如果最后收到的字符不是 [ 那么需要重新开始
Status=0; continue;
}
}
}
// 根据收到的 cRGB 设置 LED 颜色
if (Status==6) {
USBSerial_println_s("RGB");
USBSerial_println_i(RValue);
USBSerial_println_i(GValue);
USBSerial_println_i(BValue);
USBSerial_flush();
// 设置 WS2812 颜色, 特别注意这里和时许非常相关,具体数值都是示波器测量取得
//Send Green value from Bit7 to 0
TX(GValue);TX(GValue);TX(GValue);TX(GValue);TX(GValue);TX(GValue);TX(GValue);TX(GValue);
//Send Red value from Bit7 to 0
TX(RValue);TX(RValue);TX(RValue);TX(RValue);TX(RValue);TX(RValue);TX(RValue);TX(RValue);
//Send Blue value from Bit7 to 0
TX(BValue);TX(BValue);TX(BValue);TX(BValue);TX(BValue);TX(BValue);TX(BValue);TX(BValue);
// 重新设置为状态 0
Status=0;
}
// 根据设置的延时开始倒计时
if (Status==10) {
if ((THigh==0)&&(TLow==0)) {
digitalWrite(BEEPERPIN,LOW);
}
// 设置触发时间
else CounterDown=(THigh*256+TLow)*1000UL+millis();
Status=0;
}
// 如果当前处于状态 0 并且设置的触发时间小于当前时间,那么就开始响
if ((Status==0)&&(CounterDown<millis())) {
// 对应 Pin 拉高,蜂鸣器开始发声
digitalWrite(BEEPERPIN,HIGH);
// 拉高之后会一直发声
CounterDown=0xFFFFFFFF;
}
}
特别提一句:WS2812 有很多版本,彼此之间在时序上有差别。比如,下面两种从Datasheet看就是有差别的,前者的代码(CH55xDuino)在后者(这次设计使用的)上会有问题:
WS2812D-F8 | WS2812B-Mini | |
T0H | 400±150ns | 300±80ns |
T0L | 850±150ns | 790±210ns |
T1H | 850±150ns | 790±210ns |
T1L | 400±150ns | 300±80ns |
RES | >50us | >280us |
所以,我在代码上重写了 WS2812 相关部分,因为对时序要求很高,所以最好使用汇编语言,但是因为我对 C51汇编很陌生,于是只能写成宏的方式。有兴趣的朋友可以尝试修改CH55xduino的库文件。
BOM 如下,不包括PCB 在10元左右,可以看到这个芯片在制作 USB 相关设备方面很有竞争力:

虽然CH55X系列芯片有诸多好处,但是还存在如下缺点:
- 进入 BootLoader后,在 USB 3.0 的 USB口上经常会出现 Yellow Bang 的情况。可以尝试 Disable再Enable 看看能否消除之。如果始终不行,推荐将板子使用一个 USB2.0 HUB和 USB 3.0 相连,这个应该时芯片本身的 Bug(作为 USB 普通设备,不会遇到这个问题);如果一直存在这个问题,那么可以先卸载,然后再重新安装驱动试试;
- 淘宝有很多CH552 开发板,强烈建议在动手实验之前入手一个作为开发板,上面会有按钮,按下后插入USB端口直接进入 BootLoader模式,方便调试;
- 淘宝购买后,拿到手请及时检查芯片,我在Taobao 购买的 CH554 开发板拿到手几个月后再用时发现上面竟然是 CH552的芯片,因为他们封装相同,所以当时没有注意,再去找售后时发现店铺竟然已经关门。
参考:
- http://www.wch.cn/products/category/5.html 单片机系列芯片选项指南
- https://github.com/DeqingSun/ch55xduino
- https://atta.szlcsc.com/upload/public/pdf/source/20190620/C114583_ECCAEB884D1CBA01F5696FFC90F90D84.pdf WS2812B-Mini DataSheet
- https://item.szlcsc.com/150447.html WS2812D-F8 DataSheet\
========================================
因为 GitHub 在访问上可能存在的问题,所以我在这里放一个 json 文件,就是说你可以在 Preferences –> Additional Boards Manager URLs 中使用下面这个地址:
http://www.lab-z.com/wp-content/uploads/2021/05/package_ch55xduino_mcs51_index.json
——————————————————————
CH55x Programmer by VNPro
——————————————————————
Load file as hex
Loaded 7338 bytes between: 0000 to 1CD7
Found no CH55x USB
上传项目出错
USB Moudle 设备也正常。就是上传失败。
要不你试试他们家的工具上传看看?
另外,参考一下这个文章 https://blog.csdn.net/sxhexin/article/details/115350043
VNPro is compatible with libUSB driver. So you can use Zadig to use the libUSB driver for the boot loader mode instead of WinUSB. From my testing, it is a lot more reliable than WinUSB on Windows
Thanks a lot.
You are most welcome 🙂
I have been trying to solve the “Yellow Bang” issue you mentioned when using the Windows WinUSB driver. Using your suggested method of a USB hub does help in one Windows10 Laptop (The others just have a success rate of < 20%). So just would like to check with you if you have any success on that matter. Thanks.
I have tried to reach out to the WCH company (technical support), they are not being too helpful 🙁
嗯,我也联系过 WCH, 后来发现他们家的 Driver 不会有这样的问题,然后对方也没有什么办法了。