在有些情况下,比如:功耗测试。我们需要让系统一直处于S0 状态,最好的方法莫过于摇晃鼠标。这次的作品就是一款基于Dell 廉价鼠标的扩展方案,它每隔10秒摇晃一次鼠标,让你的系统不会休眠。 整体方案设计思路非常简单:鼠标的USB进入CH334 USBHUB 芯片之后,转出来2路USB信号,一路给PAW3515芯片,这是一个鼠标芯片;另外一路给CH552。我们通过编程,让Ch552将自身模拟为鼠标和键盘设备。Ch552键盘设备用于接收主机发过来的键盘LED控制信号;Ch552鼠标设备则是用于模拟鼠标的动作。 电路图如下,左上角是PAW3515鼠标的最小系统,右上角是Ch334USB Hub芯片的最小系统,下方则是Ch552的最小系统。
PCB 设计如下:
这个的尺寸和戴尔MS116-T 的有线光电鼠标内部的PCB完全相同,用我们的这个PCB替换掉原版即可。焊接之后如下:
编写代码如下:
- #ifndef USER_USB_RAM
- #error "This example needs to be compiled with a USER USB setting"
- #endif
-
- #include "src/userUsbHidKeyboardMouse/USBHIDKeyboardMouse.h"
-
- // 10秒触发一次
- #define INTERVAL 10000UL
- // 每次动作间隔 20ms
- #define ACTION 50
-
- // 触发计时
- unsigned long int Elsp = 0;
- // 记录当前是否已经触发过
- boolean StageAssert[4] = {false, false, false, false};
-
- uint8_t LastLed;
- unsigned long LEDAssertElsp = 0;
- // 触发状态标志
- boolean StartWaken = false;
-
- void setup() {
- USBInit();
- Serial0_begin(115200);
- delay(3000);
- Serial0_println("start");
- LastLed = LedStatus;
- }
-
- // 判断是否满足条件
- boolean MoveCondition(byte stage) {
- // 条件1. 大于 INTERVAL 给出的时间
- // 条件2. 小于 INTERVAL + (stage + 1)*ACTION 给出的时间
- // 条件3. 之前没有触发过
- if ((millis() - Elsp > INTERVAL + stage * ACTION) &&
- (millis() - Elsp < INTERVAL + (stage + 1)*ACTION) &&
- (StageAssert[stage] == false)) {
- // 标记已经触发过
- StageAssert[stage] = true;
- return true;
- }
- return false;
- }
-
-
- void loop() {
- // 如果发生了 LED 切换
- if (LastLed != LedStatus) {
- Serial0_println("B");
- // 如果 1秒内发生了切换
- if (millis() - LEDAssertElsp < 1000) {
- // 触发状态反转
- StartWaken = !StartWaken;
- Serial0_print(StartWaken);
- Serial0_println("C");
- if (StartWaken == false) {
- // 重置
- for (byte i = 0; i < 4; i++) {
- StageAssert[i] = false;
- }
- } else {
- Elsp = millis();
- }
- }
- // 记录切换时间
- LEDAssertElsp = millis();
- LastLed = LedStatus;
- Serial0_println("E");
-
- }
- if (StartWaken != false) {
- if (MoveCondition(0) == true) {
- // 向右移动
- Mouse_move(100, 0);
- } else if (MoveCondition(1) == true) {
- // 向下移动
- Mouse_move(0, 100);
- } else if (MoveCondition(2) == true) {
- // 向左移动
- Mouse_move(-100, 0);
- } else if (MoveCondition(3) == true) {
- // 向上移动
- Mouse_move(0, -100);
- // 重置
- for (byte i = 0; i < 4; i++) {
- StageAssert[i] = false;
- }
- Elsp = millis();
- }
- }
- }
复制代码
对应的功能有一个开关,使用连续按下键盘上的Caps/NumLock/Scroll 两次即可触发。这里使用到了USB键盘的一个有趣的特性:操作系统会在全部的键盘中进行同步。比如,系统中有3个USB键盘,当你在其中一个键盘按下Caps 按键之后,操作系统会通知其余两个键盘要求更改Caps LED。使用USB抓包软件可以看到,下图就是Windows主机端用于通知Ch552 键盘要求更改LED的命令,我按下2次,Byte0 是ReportID, Byte1 是键盘LED的状态。
对应的代码在 \Ch552MSWaken\src\userUsbHidKeyboardMouse\USBHIDKeyboardMouse.c,收到来自EndPoint 1 的 Out 数据后,会更改 LedStatus 数值,以便主程序进行处理。 - void USB_EP1_OUT() {
- //Serial0_println("A");
- LedStatus=Ep1Buffer[1]; //LABZ_Debug
- if (U_TOG_OK) // Discard unsynchronized packets
- {
- }
- }
复制代码
经过改造,你得到的是一个表面上看起来和正经鼠标一摸一样的鼠标,同时它也有着和正经鼠标一摸一样的功能,但是当你触发之后,它会每隔10秒晃动一次。
工作的视频:
|