深色模式
附录 B:风扇(H 桥)控制失效的常见原因与排查
本附录以 D3 小车的风扇为例(正转 GP18、反转 GP19)。使用《跬步少年编程基础教具包》的学员请注意:教具包的风扇接 GP16(反转)与 GP17(正转),引脚号不同,但原理和排查方法完全一样,对照着换两个引脚号即可。
一、什么叫"失效"
程序让风扇正转,它不正转;让它停,它不停;让它转慢一点,它却全速狂转……总之,电机的实际表现和程序的设计目的对不上,都叫失效。
遇到失效先别急着怀疑代码写错了。按下面两类原因顺序排查,九成问题都能解决。
二、原因一:线松了(GND / INA / INB 任一断路)
H 桥模块一共接四根线:VCC、GND、INA、INB。失效时电机往往还在转(只是不受控),这说明 VCC 通常是通的,重点排查剩下三根:GND、INA(D3 接 GP18)、INB(D3 接 GP19)——任意一根接触不良或断路,控制信号就会异常。
排查方法(需要万用表)
1. 查 GND:万用表红笔接 Pico 扩展板的 VCC 输出,黑笔接 H 桥模块的 GND 引脚。显示 3.3V 或 5V,说明 GND 回路正常。
2. 查 GP18(INA):上传下面这段测试程序(GP18 输出高电平、GP19 输出低电平),红笔接 GP18、黑笔接 GND,显示 3.3V,说明 GP18 线路连通。
cpp
void setup() {
pinMode(18, OUTPUT);
pinMode(19, OUTPUT);
}
void loop() {
digitalWrite(18, HIGH);
digitalWrite(19, LOW);
}3. 查 GP19(INB):换一段程序,让 GP19 输出高电平、GP18 输出低电平,同样方法测 GP19。
cpp
void setup() {
pinMode(18, OUTPUT);
pinMode(19, OUTPUT);
}
void loop() {
digitalWrite(18, LOW);
digitalWrite(19, HIGH);
}排查通断只需要输出固定的高/低电平,不用测 PWM。哪根线不通,重新插紧或换一根杜邦线即可。
三、原因二:引脚模式"挂挡"失败(用米思齐 Mixly 的学员高发)
先看两张图找不同
同样是"正转 5 秒 → 停 2 秒 → 反转 5 秒"的积木程序,分别用 Mind+ 和米思齐(Mixly)来自动生成 Arduino 代码:


对比可以看出:积木一模一样,生成的代码却有一处关键差异:米思齐在 setup() 里自动多写了 pinMode(18, OUTPUT); pinMode(19, OUTPUT); 两行,Mind+ 则没有。
别小看这两行——它就是风扇失效的根源。米思齐生成的程序上传到 Pico 后,风扇会出现全速乱转、该停时不停等失效现象;Mind+ 生成的程序没有这两行,运行完全正常。
原理:引脚"挂挡"后不会自动换挡
Pico 用的 RP2040 芯片,每个引脚像一辆手动挡汽车,同一个引脚可以挂在不同的"挡位"上工作:
| 挡位 | 功能 | 谁用它 |
|---|---|---|
GPIO_FUNC_SIO | 普通数字输入/输出 | pinMode()、digitalWrite() |
GPIO_FUNC_PWM | 硬件 PWM 输出 | analogWrite() |
第一次调用哪个函数,引脚就挂到哪个挡位,这一步核心库会自动完成。问题在于:挂上挡之后,再想换到另一个挡,核心库不会自动完成切换。
- 先执行
pinMode(18, OUTPUT),引脚被挂到数字口(SIO 挡)。之后analogWrite(18, 200)想输出 PWM 时,引脚还卡在数字口上,PWM 信号根本送不到物理引脚——引脚停在固定电平,相当于一直给 H 桥发送"正转"或"停止"的固定指令,于是风扇全速乱转、该停不停,连analogWrite(18, 0)都关不掉它; - 反过来也一样:先
analogWrite挂到 PWM 挡,再用digitalWrite就切不回去了,引脚输出的还是 PWM 信号。
米思齐生成的代码正是踩了第一个坑:一上电就用 pinMode 把 GP18、GP19 挂到了数字口,后面 loop() 里的 analogWrite 全部失效。
解决办法
一个引脚全程只用一种写法,不要混用。
风扇的正转、停止、反转全部用 analogWrite 实现:
cpp
void setup() {
// 这里什么都不用写,尤其不要写 pinMode
}
void loop() {
analogWrite(18, 200); // 正转
analogWrite(19, 0);
delay(5000);
analogWrite(18, 0); // 停止(占空比为 0)
analogWrite(19, 0);
delay(2000);
analogWrite(18, 0); // 反转
analogWrite(19, 200);
delay(5000);
}记住一条:analogWrite() 不需要先调用 pinMode()。在 Pico 上,先写 pinMode() 反而会把 PWM 废掉。
- 米思齐用户:上传前把
setup()里自动生成的pinMode(18, OUTPUT); pinMode(19, OUTPUT);两行删掉或注释掉; - Mind+ 用户:生成的代码本来就没有这两行,无需处理;
- MicroPython(Python 模式)用户:
PWM(Pin(18))是显式创建 PWM 对象的写法,不存在这种隐式抢挡的问题。
进阶:确实需要混用时(了解即可)
如果程序逻辑真的需要在同一个引脚上交替使用 PWM 和数字输出,那就得用 gpio_set_function() 手动换挡:
cpp
#include <Arduino.h>
void setup() {
gpio_set_function(18, GPIO_FUNC_PWM); // 手动挂到 PWM 挡
gpio_set_function(19, GPIO_FUNC_PWM);
}
void loop() {
analogWrite(18, 200); // 正转
analogWrite(19, 0);
delay(3000);
gpio_set_function(18, GPIO_FUNC_SIO); // 手动换回数字口挡
gpio_set_function(19, GPIO_FUNC_SIO);
digitalWrite(18, LOW); // 停止
digitalWrite(19, LOW);
delay(3000);
}<Arduino.h> 已经包含了 Pico SDK 的头文件,gpio_set_function() 可以直接用,不用额外 #include。
注意:analogWrite(pin, 0) 只是把 PWM 占空比调到 0%,引脚还停在 PWM 挡,并没有切回数字口。要彻底切换,必须用 gpio_set_function()。
四、快速排查清单
风扇不听话时,对照下表从上往下查:
| 检查项 | 正常标准 |
|---|---|
| GND 线路 | 万用表红笔接 VCC、黑笔接 GND,显示 3.3V / 5V |
| GP18 线路 | 测试程序输出高电平,红笔接 GP18、黑笔接 GND,显示 3.3V |
| GP19 线路 | 测试程序输出高电平,红笔接 GP19、黑笔接 GND,显示 3.3V |
| 程序初始化 | setup() 里没有 pinMode(18, OUTPUT) 和 pinMode(19, OUTPUT) |
| 调速与停止 | 用 analogWrite(pin, 0) 实现,不借助 digitalWrite() 或 pinMode() |
| 写法一致性 | 一个引脚全程 analogWrite,或全程 digitalWrite,不混用 |
