我的征尘是星辰大海。。。
The dirt and dust from my pilgrimage forms oceans of stars...
-------当记忆的篇章变得零碎,当追忆的图片变得模糊,我们只能求助于数字存储的永恒的回忆
作者:黄教授
手机视频列表
一个嵌入式开发门外汉的感悟
视频
音频
原始脚本
从 CH9329的坑到 Arduino 的光,一位嵌入式门外汉的 USB 输入设备,顿悟之旅。 最近这两天的折腾,像是一场沉浸式的嵌入式启蒙课。 从抱着 CH9329+CH470模块满怀期待,到最终转向 Arduino Pro Micro,过程里踩过的坑、绕不过的弯,以及最终豁然开朗的认知。 让我突然读懂了 USB 输入设备的底层逻辑,也读懂了嵌入式平民化背后的深层意义。 这段经历无关高深的代码技巧,无关复杂的协议细节,而是关于如何理解设备与系统的对话,关于技术门槛的本质,更关于一次从想当然到懂本质的认知蜕变。 最初听到 CH9329,我和很多新手一样,把它当成一个万能捷径。 淘宝上的详细让我感觉它是串口转 USB 键鼠的完美方案。 无需复杂的底层开发,只需通过官方工具修改配置,就能实现串口指令到 USB 键鼠信号的转换。 我甚至天真的以为,这就是嵌入式开发的轻量化捷径,预期20分钟搞定。 这种想当然很快就被现实狠狠打脸,我有两个想当然的谬误。 首先是对绝对鼠标相对鼠标的认知错误。 我一直以为这两种模式就像开关一样,通过修改串口包的某个模式就能动态切换,就像调节台灯的亮度、切换风扇的档位一样简单。 第二个错误的认知以为这个是需要依赖不同的桌面系统的支持,以为桌面系统才能告知鼠标它的绝对坐标。 首先一个输入设备自己的能力,就像人与人之间的对话,第一句话必须说清楚我们说的是中文还是法语。 操作系统与 USB 设备的握手,本质上也是一次语言定义。 在设备插入的瞬间,枚举阶段,USB 设备必须一次性向操作系统宣告自己的身份。 我是相对鼠标,我发送的是增量坐标,dx、dy。 我是绝对鼠标,我发送的是归一化坐标,0~32767,0~32767。 这个宣告写在 HID 报告描述符,Report Descriptor 里,一旦枚举完成,就再也无法修改。 就像我们一旦约定了对话的语言,就不可能中途突然切换成另一种语言,否则对方只会一脸茫然。 其次,绝对坐标就是输入设备自己维护的一个内部的数据结构。 它是输入设备的选择,桌面系统自己的内部坐标,不可能也没必要告诉输入设备。 这是我认知的输入设备的角色反转。 在此之前,我一直有一个错误的认知,桌面系统是主人,输入设备是仆人。 我以为鼠标的位置由桌面决定,所以绝对坐标是由桌面告诉。 实际上,输入设备才是说话的人,操作系统是听话的人。 就像键盘的逻辑,键盘敲下的是物理按键的扫描码,而不是直接的字符。 如果不告诉操作系统我是美式键盘,它就无法把扫描码0×1一翻译成 A,反而会翻译成法语键盘的 Q,这就是鸡同鸭讲。 同理,绝对鼠标内部维护着0~32767的坐标体系。 它告诉桌面,我现在在100,200,桌面就必须按这个坐标移动指针。 相对鼠标告诉桌面,我向左移动了10个单位,桌面就必须按增量叠加指针位置。 操作系统没有资格纠正输入设备的指令,它唯一的职责是解码和执行。 这个认知的反转是我这两天最深刻的顿悟。 原来我们日常使用的鼠标和键盘从来不是被动接收指令的工具。 而是主动输出信号的独立设备,它们的逻辑核心是自我定义,而非服从安排。 C H 9329的黑盒特性恰恰让我无法直观体会这个核心逻辑,我看不到它内部的坐标计算,看不到它的 HID 描述符定义。 只能依赖第三方工具,这种隔靴搔痒的体验让我对输入设备的理解始终停留在表面。 也正是在这个时候,我开始重新审视 Arduino,这个之前被我当成小孩子玩具的东西。 我对 Arduino 的偏见源于对嵌入式开发的刻板印象。 嵌入式开发是专业门槛极高的领域,需要精通 C C 加加编译器工具链、Bootloader 配置、USB 协议栈,需要调试器、烧录工具、底层驱动开发能力,这些都是普通程序员难以触及的高山。 而 Arduino 作为开发板,是把这些复杂的底层逻辑封装起来,变成了乐高积木,让十几岁的孩子也能做出简单的电子项目。 他把原本需要专业工程师花数月时间功课的 Bootloader 配置、USB 协议栈实现、HID 描述符编写、串口通信调试全部封装成了简单的 API 接口。 更让我震撼的是 Arduino 的原验证价值 正如我之前感慨的,嵌入式开发的核心痛点从来不是代码实现,而是环境配置和底层调试。 一个普通的嵌入式项目,前期80%的时间都花在搭建编译环境、调试驱动、解决兼容性问题上。 而真正用于实现功能的时间只有20%。 但 Arduino 彻底改变了这个比例,它的开发环境一键搭建,烧录方式简单便捷,直接 USB 连接,生态丰富完善,几乎所有的底层问题都被官方解决了。 这让 Arduino 成为了完美的概念验证平台。 无论是验证串口转 USB 的逻辑,还是测试绝对鼠标的坐标映射,亦或是验证 Linux 下,Dev Input 事件的监听,而 do no 都能让我在短短几分钟内完成从想法到实物的转化。 它就像一个嵌入式开发的脚手架,让我们可以专注于核心功能的实现。 它的伟大之处在于打破了嵌入式开发的精英垄断。 在 Arduino 出现之前,嵌入式开发是少数专业工程师的专属领域。 普通程序员甚至爱好者很难触及底层的 USB HID 驱动开发,而 Arduino 用乐高化的开发模式,让每个人都能参与到嵌入式项目中,让硬件动起来变成了一件像写代码一样简单的事情。 这两天的经历也让我对技术通用性有了新的理解。 USB HID 协议作为通用的输入设备协议,看似复杂,本质上是一套通用语言规则。 无论是 CH9329这样的专用芯片,还是 Arduino 这样的开发板,亦或是未来的其他嵌入式设备,都必须遵守这套规则。 技术的通用性本质是规则的统一性。 所有的设备无论多么复杂,最终都要在枚举阶段完成一次语言定义。 这是 USB 协议的铁律,也是输入设备与操作系统对话的基础。 CH9329的坑让我看到了黑盒硬件的局限性,我们无法看透它的内部逻辑,只能依赖官方工具,一旦出现问题往往束手无策。 而 Arduino 的优势恰恰在于它的开源透明,我们可以通过代码看到它的 HID 描述符,看到它的串口通信逻辑,每一个细节都清晰可控。 这种可控性对于技术探索来说,比便捷性更重要。 现在回头看,这两天的折腾其实是一次非常宝贵的认知升级。 我从 CH9329的黑河迷雾中走出来,终于理解了 USB 输入设备的核心逻辑。 输入设备是语言的定义者,操作系统是语言的解码者。 HID 协议是通用的语言规则,枚举阶段的一次性声明是不可违背的铁律。 技术学习从来不是一蹴而就的,而是需要亲手实践的。 很多时候我们对一个技术的误解源于只闻其名,未见其实。 纸上得来终觉浅,踩过坑后悟才深。 说到底,技术的魅力从来不是高深莫测,而是触手可及。
修正脚本
从 CH9329的坑到 Arduino 的光,一位嵌入式门外汉的 USB 输入设备顿悟之旅。 最近这两天的折腾,像是一场沉浸式的嵌入式启蒙课。 从抱着 CH9329+CH470模块满怀期待,到最终转向 Arduino Pro Micro,过程里踩过的坑、绕不过的弯,以及最终豁然开朗的认知。 让我突然读懂了 USB 输入设备的底层逻辑,也读懂了嵌入式平民化背后的深层意义。 这段经历无关高深的代码技巧,无关复杂的协议细节,而是关于如何理解设备与系统的对话,关于技术门槛的本质,更关于一次从想当然到懂本质的认知蜕变。 最初听到 CH9329,我和很多新手一样,把它当成一个万能捷径。 淘宝上的详情让我感觉它是串口转 USB 键鼠的完美方案。 无需复杂的底层开发,只需通过官方工具修改配置,就能实现串口指令到 USB 键鼠信号的转换。 我甚至天真地以为,这就是嵌入式开发的轻量化捷径,预期20分钟搞定。 这种想当然很快就被现实狠狠打脸,我有两个想当然的谬误。 首先是对绝对鼠标、相对鼠标的认知错误。 我一直以为这两种模式就像开关一样,通过修改串口包的某个模式就能动态切换,就像调节台灯的亮度、切换风扇的档位一样简单。 第二个错误的认知是,以为这需要依赖不同的桌面系统的支持,以为桌面系统才能告知鼠标它的绝对坐标。 首先,一个输入设备自己的能力,就像人与人之间的对话,第一句话必须说清楚我们说的是中文还是法语。 操作系统与 USB 设备的握手,本质上也是一次语言定义。 在设备插入的瞬间,枚举阶段,USB 设备必须一次性向操作系统宣告自己的身份。 我是相对鼠标,我发送的是增量坐标,dx、dy。 我是绝对鼠标,我发送的是归一化坐标,0~32767,0~32767。 这个宣告写在 HID 报告描述符,Report Descriptor 里,一旦枚举完成,就再也无法修改。 就像我们一旦约定了对话的语言,就不可能中途突然切换成另一种语言,否则对方只会一脸茫然。 其次,绝对坐标就是输入设备自己维护的一个内部的数据结构。 它是输入设备的选择,桌面系统自己的内部坐标,不可能也没必要告诉输入设备。 这是我认知的输入设备的角色反转。 在此之前,我一直有一个错误的认知,桌面系统是主人,输入设备是仆人。 我以为鼠标的位置由桌面决定,所以绝对坐标是由桌面告诉输入设备。 实际上,输入设备才是说话的人,操作系统是听话的人。 就像键盘的逻辑,键盘敲下的是物理按键的扫描码,而不是直接的字符。 如果不告诉操作系统我是美式键盘,它就无法把扫描码0×01翻译成 A,反而会翻译成法语键盘的 Q,这就是鸡同鸭讲。 同理,绝对鼠标内部维护着0~32767的坐标体系。 它告诉桌面,我现在在100,200,桌面就必须按这个坐标移动指针。 相对鼠标告诉桌面,我向左移动了10个单位,桌面就必须按增量叠加指针位置。 操作系统没有资格纠正输入设备的指令,它唯一的职责是解码和执行。 这个认知的反转是我这两天最深刻的顿悟。 原来我们日常使用的鼠标和键盘从来不是被动接收指令的工具。 而是主动输出信号的独立设备,它们的逻辑核心是自我定义,而非服从安排。 CH9329的黑盒特性恰恰让我无法直观体会这个核心逻辑,我看不到它内部的坐标计算,看不到它的 HID 描述符定义。 只能依赖第三方工具,这种隔靴搔痒的体验让我对输入设备的理解始终停留在表面。 也正是在这个时候,我开始重新审视 Arduino,这个之前被我当成小孩子玩具的东西。 我对 Arduino 的偏见源于对嵌入式开发的刻板印象。 嵌入式开发是专业门槛极高的领域,需要精通 C、C++ 编译器工具链、Bootloader 配置、USB 协议栈,需要调试器、烧录工具、底层驱动开发能力,这些都是普通程序员难以触及的高山。 而 Arduino 作为开发板,是把这些复杂的底层逻辑封装起来,变成了乐高积木,让十几岁的孩子也能做出简单的电子项目。 它把原本需要专业工程师花数月时间攻克的 Bootloader 配置、USB 协议栈实现、HID 描述符编写、串口通信调试全部封装成了简单的 API 接口。 更让我震撼的是 Arduino 的原型验证价值,正如我之前感慨的,嵌入式开发的核心痛点从来不是代码实现,而是环境配置和底层调试。 一个普通的嵌入式项目,前期80%的时间都花在搭建编译环境、调试驱动、解决兼容性问题上。 而真正用于实现功能的时间只有20%。 但 Arduino 彻底改变了这个比例,它的开发环境一键搭建,烧录方式简单便捷,直接 USB 连接,生态丰富完善,几乎所有的底层问题都被官方解决了。 这让 Arduino 成为了完美的概念验证平台。 无论是验证串口转 USB 的逻辑,还是测试绝对鼠标的坐标映射,亦或是验证 Linux 下,Dev Input 事件的监听,而 Arduino 都能让我在短短几分钟内完成从想法到实物的转化。 它就像一个嵌入式开发的脚手架,让我们可以专注于核心功能的实现。 它的伟大之处在于打破了嵌入式开发的精英垄断。 在 Arduino 出现之前,嵌入式开发是少数专业工程师的专属领域。 普通程序员甚至爱好者很难触及底层的 USB HID 驱动开发,而 Arduino 用乐高化的开发模式,让每个人都能参与到嵌入式项目中,让硬件动起来变成了一件像写代码一样简单的事情。 这两天的经历也让我对技术通用性有了新的理解。 USB HID 协议作为通用的输入设备协议,看似复杂,本质上是一套通用语言规则。 无论是 CH9329这样的专用芯片,还是 Arduino 这样的开发板,亦或是未来的其他嵌入式设备,都必须遵守这套规则。 技术的通用性本质是规则的统一性。 所有的设备无论多么复杂,最终都要在枚举阶段完成一次语言定义。 这是 USB 协议的铁律,也是输入设备与操作系统对话的基础。 CH9329的坑让我看到了黑盒硬件的局限性,我们无法看透它的内部逻辑,只能依赖官方工具,一旦出现问题往往束手无策。 而 Arduino 的优势恰恰在于它的开源透明,我们可以通过代码看到它的 HID 描述符,看到它的串口通信逻辑,每一个细节都清晰可控。 这种可控性对于技术探索来说,比便捷性更重要。 现在回头看,这两天的折腾其实是一次非常宝贵的认知升级。 我从 CH9329的黑盒迷雾中走出来,终于理解了 USB 输入设备的核心逻辑。 输入设备是语言的定义者,操作系统是语言的解码者。 HID 协议是通用的语言规则,枚举阶段的一次性声明是不可违背的铁律。 技术学习从来不是一蹴而就的,而是需要亲手实践的。 很多时候我们对一个技术的误解源于只闻其名,未见其实。 纸上得来终觉浅,踩过坑后悟才深。 说到底,技术的魅力从来不是高深莫测,而是触手可及。
英文翻译
From the pitfalls of CH9329 to the light of Arduino: An embedded novice's epiphany on USB input devices. The past two days of tinkering have felt like an immersive introductory lesson in embedded systems. From eagerly anticipating the CH9329+CH470 module to eventually switching to the Arduino Pro Micro, every pitfall I stumbled into, every detour I had to take, and finally the sudden clarity of understanding— all of it suddenly made me grasp the underlying logic of USB input devices and the deeper significance of democratizing embedded systems. This experience is not about advanced coding techniques or complex protocol details; it's about understanding the dialogue between devices and systems, the essence of technical barriers, and above all, a cognitive transformation from assumption to true comprehension. When I first heard of the CH9329, like many beginners, I saw it as a universal shortcut. The product descriptions on Taobao made it seem like the perfect solution for UART-to-USB keyboard and mouse conversion. No need for complex low-level development; just modify the configuration using the official tool, and you could convert serial commands into USB keyboard/mouse signals. I even naively thought this was the lightweight shortcut for embedded development, expecting to get it done in 20 minutes. This assumption was quickly slapped down by reality, revealing two flawed misconceptions. First, a misunderstanding of absolute versus relative mouse modes. I always thought these two modes were like a switch, dynamically toggleable by modifying some mode field in the serial packet—as simple as adjusting a lamp's brightness or switching a fan's speed. The second misconception was thinking that this depended on support from different desktop operating systems, believing that only the desktop could inform the mouse of its absolute coordinates. First of all, a device's own capabilities are like a conversation between two people: the first sentence must clearly state whether we are speaking Chinese or French. The handshake between an operating system and a USB device is essentially a language definition. At the instant the device is plugged in, during the enumeration phase, the USB device must declare its identity to the operating system in a single, one-time statement. "I am a relative mouse; I send incremental coordinates, dx, dy." "I am an absolute mouse; I send normalized coordinates, 0~32767, 0~32767." This declaration is written into the HID Report Descriptor. Once enumeration is complete, it can never be modified. Just as once we agree on a language for conversation, we cannot suddenly switch to another language halfway—otherwise the other party would be completely confused. Second, absolute coordinates are an internal data structure maintained by the input device itself. It is the input device's choice; the desktop system's own internal coordinates cannot—and need not—be told to the input device. This represents a role reversal in my understanding of input devices. Prior to this, I had a persistent misconception: the desktop system is the master, and the input device is the servant. I thought the mouse's position was determined by the desktop, so absolute coordinates came from the desktop to the input device. In reality, the input device is the speaker; the operating system is the listener. It's like the keyboard logic: the keyboard sends the scan code of the physical key, not the direct character. If you don't tell the operating system "I am a US keyboard," it cannot translate scan code 0x01 into 'A'; instead, it would translate it into the French keyboard's 'Q'. That's like a dialogue of the deaf. Similarly, an absolute mouse internally maintains a coordinate space from 0 to 32767. It tells the desktop, "I am now at (100, 200)," and the desktop must move the pointer to that coordinate. A relative mouse tells the desktop, "I moved left by 10 units," and the desktop must add that increment to the pointer position. The operating system has no right to correct the input device's instructions; its only duty is to decode and execute. This cognitive reversal is the most profound epiphany I've had in the past two days. So the mouse and keyboard we use daily are never passive tools that receive commands. Instead, they are independent devices that actively output signals; their logical core is self-definition, not obedience to arrangement. The black-box nature of the CH9329 precisely prevented me from intuitively experiencing this core logic. I couldn't see its internal coordinate calculations or its HID descriptor definitions. I could only rely on third-party tools—this superficial experience kept my understanding of input devices at the surface level. It was at this moment that I began to re-evaluate the Arduino, something I had previously dismissed as a children's toy. My prejudice against Arduino stemmed from a stereotype of embedded development: Embedded development is a field with extremely high professional thresholds, requiring mastery of C, C++ compiler toolchains, Bootloader configuration, USB protocol stacks, debuggers, programming tools, and low-level driver development—mountains that ordinary programmers can hardly scale. Arduino, as a development board, encapsulates these complex underlying logics into Lego-like building blocks, allowing even teenagers to create simple electronic projects. It packages everything that would normally take a professional engineer months to conquer—Bootloader configuration, USB protocol stack implementation, HID descriptor writing, serial communication debugging—into simple API interfaces. What struck me even more was Arduino's value for prototype validation. As I lamented earlier, the core pain point of embedded development has never been code implementation, but environment configuration and low-level debugging. For an ordinary embedded project, 80% of the early time is spent setting up the compilation environment, debugging drivers, and solving compatibility issues. Only 20% is actually spent on implementing functionality. Arduino completely flips this ratio. Its development environment can be set up in one click, the programming method is simple and convenient (direct USB connection), and its ecosystem is rich and complete—almost all underlying issues are solved by the official team. This makes Arduino the perfect concept verification platform. Whether it's verifying the logic of serial-to-USB conversion, testing the coordinate mapping of an absolute mouse, or listening for Dev Input events under Linux, Arduino can turn an idea into a real product in just a few minutes. It's like scaffolding for embedded development, allowing us to focus on implementing core functionality. Its greatness lies in breaking the elitist monopoly of embedded development. Before Arduino, embedded development was the exclusive domain of a few professional engineers. Ordinary programmers and even hobbyists could hardly touch low-level USB HID driver development. Arduino, with its Lego-like development model, allows everyone to participate in embedded projects, making hardware "come alive" as simple as writing code. These two days of experience have also given me a new understanding of technical universality. The USB HID protocol, as a universal input device protocol, may seem complex, but it is essentially a set of universal language rules. Whether it's a dedicated chip like the CH9329, a development board like Arduino, or any other embedded device in the future, they all must follow these rules. The essence of technical universality is the uniformity of rules. No matter how complex a device is, it must complete a language definition during the enumeration phase. This is an iron law of the USB protocol and the foundation of the dialogue between input devices and operating systems. The pitfalls of the CH9329 showed me the limitations of black-box hardware. We cannot see through its internal logic; we can only rely on official tools. Once a problem arises, we are often helpless. Arduino's advantage, on the other hand, lies in its open-source transparency. Through the code, we can see its HID descriptors, its serial communication logic—every detail is clear and controllable. This controllability is even more important than convenience for technical exploration. Now looking back, these two days of tinkering have been an extremely valuable cognitive upgrade. I emerged from the black-box fog of the CH9329 and finally understood the core logic of USB input devices. The input device defines the language; the operating system decodes it. The HID protocol is the universal language rule, and the one-time declaration during enumeration is an inviolable iron law. Technical learning is never achieved overnight; it requires hands-on practice. Many times, our misunderstanding of a technology stems from only hearing its name without seeing its reality. Knowledge from books is shallow; only after stepping into pitfalls does understanding become deep. After all, the charm of technology is never about being unfathomable, but about being within reach.
back to top