zoologist 发表于 2021-1-16 13:32:43

创客造|国产主控芯片打造 USB 提醒器

本帖最后由 zoologist 于 2021-5-10 15:08 编辑

对于现在的电脑来说,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.5x3.5mm) 用于提供灯光提示,同样的这个元件无须外围配合,直接用CH55X P1.5即可控制:

外围有一个蜂鸣器,因为CH55X引脚提供电流有限,所以使用S8050这个三极管扩流,同时外加R3用于限流,主要是避免声音太大。CH55XP3.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个命令进行设置,形式如下:1.   R/G/B分别是红绿蓝的取值,例如,命令 (ASCII)5B 63 31 32 33 5D (十六进制)会将 LED RGB 分别设置为 0x31 0x32 0x33;命令5B 63 FF 00 00 5D (十六进制)会设置为全红;2.   Vhigh和 Vlow 分别是设置的时间高位和地位,例如, 命令 (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-F8WS2812B-Mini
T0H400±150ns300±80ns
T0L850±150ns790±210ns
T1H850±150ns790±210ns
T1L400±150ns300±80ns
RES>50us>280us

所以,我在代码上重写了 WS2812 相关部分,因为对时序要求很高,所以最好使用汇编语言,但是因为我对 C51汇编很陌生,于是只能写成宏的方式。有兴趣的朋友可以尝试修改CH55xduino的库文件。
BOM 如下,不包括PCB在10元左右,可以看到这个芯片在制作 USB 相关设备方面很有竞争力:

虽然CH55X系列芯片有诸多好处,但是还存在如下缺点:1.      1.进入 BootLoader后,在 USB 3.0 的 USB口上经常会出现 Yellow Bang 的情况。可以尝试 Disable再Enable看看能否消除之。如果始终不行,推荐将板子使用一个 USB2.0 HUB和USB 3.0 相连,这个应该时芯片本身的 Bug(作为 USB 普通设备,不会遇到这个问题);如果一直存在这个问题,那么可以先卸载,然后再重新安装驱动试试;2.      2.淘宝有很多CH552开发板,强烈建议在动手实验之前入手一个作为开发板,上面会有按钮,按下后插入USB端口直接进入 BootLoader模式,方便调试;3.      3.淘宝购买后,拿到手请及时检查芯片,我在Taobao购买的 CH554 开发板拿到手几个月后再用时发现上面竟然是 CH552的芯片,因为他们封装相同,所以当时没有注意,再去找售后时发现店铺竟然已经关门。
参考:1.   1. http://www.wch.cn/products/category/5.html单片机系列芯片选项指南2.   2. https://github.com/DeqingSun/ch55xduino3.      3.https://atta.szlcsc.com/upload/public/pdf/source/20190620/C114583_ECCAEB884D1CBA01F5696FFC90F90D84.pdfWS2812B-Mini DataSheet4.      4.https://item.szlcsc.com/150447.htmlWS2812D-F8 DataSheet


zoologist 发表于 2021-1-16 13:38:29

工作的视频:
https://www.bilibili.com/video/BV1Tz4y1S72F

本文提到的完整代码。


本文提到的硬件设计文档


页: [1]
查看完整版本: 创客造|国产主控芯片打造 USB 提醒器