使用CH9329和CH340发送串口数据控制鼠标键盘(鼠标控制篇-发送数据包的构成)(详细讲解)

CH9329简介(来自官方文档):

CH9329 是一款串口转标准USB HID设备(键盘、鼠标、自定义HID)芯片,根据不同的工作模式,
在电脑上可被识别为标准的USB键盘设备、USB鼠标设备或自定义HID类设备。该芯片接收客户端发
送过来的串口数据,并按照HID类设备规范,将数据先进行打包再通过USB口上传给计算机。

CH9329工作原理
官方文档难免说的太官方,翻译过来就是:当你把它插在电脑上的时候,它可以接收你发送的串口数据,它会把你发送给它的串口数据翻译成鼠标键盘操作的数据(标准USB设备的数据),然后进行打包,在通过CH340发送给电脑。电脑接收到数据,以为是人为操作鼠标,鼠标发送的数据,就会傻傻的去执行.

简单理解就是说:它可以模拟鼠标键盘进行操作。

至于如何模拟鼠标和键盘进行操作,我们需要发送什么样的数据,它才可以翻译,就是今天我要说的。

注意:本片文章面会尽我最大努力详细讲解,不懂的地方可以留言,可以私信。

要想向CH9329发送数据,我们要知道它接收什么样的数据。

通信方式说明(来自官方文档):

通信以帧为单位,即以数据包的形式发送,每帧数据都带有帧头字节、地址码、命令码、
后续数据长度、后续数据以及累加和。

简单说就是它接收的数据是一个数据包,这些数据包中包含了一些特定数据。今天主要讲解对于鼠标的控制。所以我们来看控制鼠标发送的数据包的格式:
鼠标命令包格式(图片来自官方文档)
看不懂没关系,我来给你们分析一下,我提取了几个要素:

  • 帧头: 0x57 0xAB
  • 地址码:0x00
  • 命令码:0x04
  • 后续数据长度 7 ,也就是对后续数据长度的说明, 可以表示为 0x07(16进制)
  • 需要我们编写7个字节的后续数据
  • 最后一位是 前面数据的累加和(为1个字节)

好,现在我们知道要想控制CH3929进行模拟鼠标操作,我们要向它发送一个数据包

而每一个数据包又包括

  • 帧头
  • 地址码
  • 命令码
  • 后续数据长度(对发送数据长度的说明,就是说你要发送多长的数据,长度一般是官方规定)
  • 后续数据 (要发送的数据)
  • 累加和 (所有数据累加和)

数据包格式梳理:

数据包的构成:
    帧头 + 地址码 + 命令码 + 发送数据长度声明 + 要发送的数据 + 前面数据的总和
    
    帧头:               0x570xAB
    地址码:              0x00
    命令码:              0x04
    发送数据长度声明:      0x07
    要发送的数据:         0x000x000x000x000x000x000x00  # 假设发送的数据不对鼠标有任何操作
    
    前面数据的总和:        暂时不知道

知道这些以后,我们就可以构造数据进行发送了。

字节大小的解释

我们知道,发送的数据有7个字节。一个字节有多大呢?

计算机最小的单位是Byt,1Byt只能表示 0 或者 1 两种状态,你可以把 1Byt 想象成一个灯泡,这个灯泡亮了就表示 1 灭了就表示 0

1字节 就是 8Byt ,相当于 8 个 灯泡。这 8 个灯泡可以表示 256 种状态 0-255

进制的解释

计算机有4种进制

  • 二进制
  • 八进制
  • 十进制
  • 16进制

所谓进制,就是逢几进位,我们平时最常用的是 10进制,逢10进1,以此类推

二进制逢2进1,八进制逢8进1,16进制逢16进1(是 不是

二进制 :0-1
八进制:0-7
16进制:0-F (10:A,11:B,12:C,13:D,14:E,15:F)

二进制用 0b或者0B修饰 比如说 0b1001,0B1001
八进制用 0o或者0O修饰 比如说 0o11,0O11
16进制用 0x或者0X修饰 比如说 0x9,0X9

上面举例数字都在表示十进制的数字 9

我们知道了 1字节8Byt

用1个字节表示进制的范围:
二进制 0b00000000-0b11111111
八进制 0o000-0o377
十进制 0-255
16进制 0x00-0xFF

知道了字节的大小和进制,我们开始构造要发送的数据。

构造发送数据

数据有7位,我来分别说一下每一位代表什么:

        第一位:固定写法 0x02
        
        第二位:鼠标按键控制位
            [0x00]:释放所有按键
            [0x01]:鼠标左键按下
            [0x02]:鼠标右键按下
            [0x04]:鼠标滚轮按下  # 至于为什么不是 [0x03]后面会说。
            
            
        第三位, 第四位, 第五位, 第六位:鼠标绝对移动的 x, y 轴坐标
            x 坐标是: 第三位, 第四位
            y 坐标是: 第五位, 第六位
            设备默认屏幕分辨率为 4096*4096, 我们需要根据自身屏幕分辨率进行公式计算
                输出x = (用户需要移动的x坐标 * 4096) / 用户屏幕分辨率x
                输出y = (用户需要移动的y坐标 * 4096) / 用户屏幕分辨率y
                然后, 将 输出x, 输出y 转换成 16 进制, 低位在前, 高位在后
            例子: 假设用户屏幕分辨率是 1920 * 1080, 想将鼠标移动到 500, 500 位置:
            输出x = (500 * 4096) / 1920 = 1066  转到 16 进制就是 42A
            输出y = (500 * 4096) / 1080 = 1896  转到 16 进制就是 768
            # 可以在计算器上转换结果
            
            低位在前, 高位在后
            	42A 低位是 2A, 高位是 4
            	768 低位是 68, 高位是 7
                输出x = 0x2A, 0x04
                输出y = 0x68, 0x07
            
            第三位:0x2A 第四位:0x04 第五位:0x68 第六位:0x07
            
        第七位:鼠标滚轮滚动齿数
            [0x00]:表示不滚动
            [0x01-0x7F]:表示上滚动  换算成十进制整数 1-127
            [0x81-0xFF]:表示下滚动  换算成十进制整数 129-255

这是每个字节数据代表的意思,下面,我举个例子理解一下:

假设,我的电脑分辨率是 1920*1080 现在,我想让鼠标移动到 桌面 (x=460, y=480) 坐标的位置,鼠标的按键不做操作,
首先,第一位是固定写法 0x02, 第二位由于鼠标按键不做操作,所以是 0x00

鼠标移动的坐标 x=460,
第三位, 第四位 是鼠标x坐标的数据
套入公式:输出x = (用户需要移动的x坐标 * 4096) / 用户屏幕分辨率x
可以得出:输出x = (460 * 4096) / 1920 = 981 = 0x3D5
第三位是低位,0x3D5的低位是 0xD5,所以,第三位是 0xD5
第四位是高位,0x3D5的高位是 0x03,所以,第四位是 0x03

继续计算第五位,第六位
鼠标移动的坐标 y=480,
第五位, 第六位 是鼠标y坐标的数据
套入公式:输出y = (用户需要移动的y坐标 * 4096) / 用户屏幕分辨率y
可以得出:输出y = (480 * 4096) / 1080 = 1820 = 0x71C
第五位是低位,0x71C的低位是 0x1C,所以,第三位是 0x1C
第六位是高位,0x71C的高位是 0x07,所以,第四位是 0x07

第七位是鼠标滚轮操作,由于鼠标滚轮不做任何操作,所以是 0x00

7个字节的数据包为:

"0x02", "0x00", "0xD5", "0x03", "0x1C", "0x07", "0x00"

我们知道,一个完整数据包的格式

数据包的构成:
	帧头 + 地址码 + 命令码 + 发送数据长度声明 + 要发送的数据 + 前面数据的总和

下面将我们构造的数据加上 帧头 + 地址码 + 命令码 + 发送数据长度声明

"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x00", "0xD5", "0x03", "0x1C", "0x07", "0x00"

最后在算所有数据的和,结果为 0x20A ,但是最后一位只有一个字节,所以取低位 0x0A 作为最后一位。

最后数据包为:

	"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x00", "0xD5", "0x03", "0x1C", "0x07", "0x00", "0x0A"

这样,我们就构造了一个 CH9329 可以翻译的数据包(官方文档称一个数据包为一帧)

例子(包含鼠标按键,鼠标滚轮,鼠标移动)

鼠标移动

假设,我的电脑分辨率是 1920*1080 现在,我想让鼠标移动到 桌面 (x=800, y=800) 坐标的位置,鼠标的按键不做操作。
完整数据包:

"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x00", "0xAA", "0x06", "0xDA", "0x0B", "0x00", "0xA4"

鼠标按键

假设,我的电脑分辨率是 1920*1080 现在,我想让鼠标移动到 桌面 (x=500, y=300) 坐标的位置,鼠标的右键单击。

分析下,首先要有鼠标移动的数据包,还要有鼠标右键按下的数据包,最后还要鼠标右键弹起的数据包。
完整数据包:

# 鼠标移动的数据包
"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x00", "0x2A", "0x04", "0x72", "0x04", "0x00", "0xB3"

# 鼠标右键按下的数据包
"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x02", "0x00", "0x00", "0x00", "0x00", "0x00", "0x11"

# 鼠标右键弹起的数据包
"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x00", "0x00", "0x00", "0x00", "0x00", "0x00", "0x0F"

鼠标滚轮滚动

假设,我现在想让鼠标滚轮向下滚动 1 个齿数 其他不操作。
完整数据包:

# 注意:1-127 是向上滚动,129-255 是向下滚动 
# 1 表示向上滚动1个齿数, 2 表示向上滚动2个齿数
# 255 表示向下滚动1个齿数, 254表示向下滚动2个齿数
"0x57", "0xAB", "0x00", "0x04", "0x07", "0x02", "0x00", "0x00", "0x00", "0x00", "0x00", "0xFF", "0x0E"

思考一下

可不可以发送一个数据包,包含鼠标移动,鼠标按键按下呢?

关于鼠标滚轮按下数据为 0x04 而不是 0x03 的解释

看这张图
鼠标滚轮数据
我们知道,二个字节表示鼠标按键状态,那么,请问:一个字节有多大呢?

没错,一个字节有 8 Byt 也就是 8 个灯泡…

上面这张图也是 8 个Byt。
可以表示为下面这个二进制数:
0 0 0 0 0 0 0 0

这八个0 ,就对应图上面的 BIT7 - BIT0

当 BIT2 为1 的时候,表示 中键,也就是滚轮按下,
可以表示为:
0 0 0 0 0 1 0 0

那么请问:0 0 0 0 0 1 0 0 的十进制是多少呢?

推一下:

  • 0 = 0
  • 1 = 1
  • 2 = 10
  • 3 = 11
  • 4 = 100
  • 5 = 101

可以看出,4 的二进制是 100,也就是 0 0 0 0 0 1 0 0
以此类推:
左键按下是 0 0 0 0 0 0 0 1 也就是 1, 1的十六进制是:0x01
滚轮按下是 0 0 0 0 0 0 1 0 也就是 2, 4的十六进制是:0x02
滚轮按下是 0 0 0 0 0 1 0 0 也就是 4, 4的十六进制是:0x04

到这里,关于向CH9329发送数据控制鼠标就说完了,有些地方可能说的不够明白,希望大家理解,不清除的也可以私信,留言,我看到都会回复。

后续会有键盘控制篇-发送数据包的构成使用Python实现发送数据包基于Python控制CH3929实现的简易自动化控制

关于基于Python控制CH3929实现的简易自动化控制这一篇,希望大家有简单的项目可以推荐,简单为主,(逻辑复杂的一两句话说不明白)主要是对控制鼠标键盘做一个总结。

注意: 文中仅为个人观点,如有错误,还请多多包涵,也希望我没有说明白的地方,给我留言,私信。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐