
教学目标: 理解 PWM 舵机控制,验证舵机硬件正常
教师讲解引入:
"在让摇杆控制舵机之前,我们先单独测试舵机是否正常。舵机通过 PWM(脉冲宽度调制)信号控制角度,0.5ms 脉宽对应 0°,2.5ms 对应 180°。"
教师新增代码(引入库并测试舵机):
#include <ESP32Servo.h> // 引入舵机控制库// [保留之前的引脚定义]// 创建舵机对象Servo myServo;void setup() { Serial.begin(115200); pinMode(JOY_SW_PIN, INPUT_PULLUP); // 附加舵机到指定引脚 // ESP32 的 PWM 引脚几乎任意 GPIO 都可用,这里用 GPIO13 myServo.attach(SERVO_PIN); Serial.println("舵机测试模式"); // 开机自检:让舵机从 0° 扫到 180° 再返回,确认硬件正常 Serial.println("自检:0° -> 180°"); myServo.write(0); delay(500); // 等待舵机到位(机械运动需要时间) myServo.write(180); delay(500); myServo.write(90); // 回到中位 delay(500); Serial.println("自检完成,准备接受指令");}void loop() { // 简单的自动扫描测试(先不接手柄) static int angle = 0; // static 变量保持数值 static int direction = 1; // 1=增加, -1=减少 angle += direction * 5; // 每次增加或减少 5 度 // 到达边界则反转方向 if (angle >= 180) { angle = 180; direction = -1; } else if (angle <= 0) { angle = 0; direction = 1; } myServo.write(angle); // 发送角度指令 Serial.print("当前角度: "); Serial.println(angle); delay(50); // 50ms 更新一次,形成平滑扫描}观察要点:
故障排查(教师准备):
教学目标: 理解 map() 函数,实现输入到输出的映射
教师讲解引入:
"现在把前两个里程碑结合起来:摇杆的 0-4095 映射到舵机的 0-180°。这就像一个比例尺转换。"
教师编写核心代码(修改 loop):
#include <ESP32Servo.h>// [保留引脚定义和对象创建]void setup() { Serial.begin(115200); pinMode(JOY_SW_PIN, INPUT_PULLUP); myServo.attach(SERVO_PIN); Serial.println("摇杆控制舵机 - 核心功能");}void loop() { // === 第 1 步:读取输入 === int xValue = analogRead(JOY_X_PIN); // === 第 2 步:数值映射(关键代码)=== // map(值, 输入最小, 输入最大, 输出最小, 输出最大) // 将 0-4095 线性映射到 0-180 int angle = map(xValue, 0, 4095, 0, 180); // === 第 3 步:安全限制(防御性编程)=== // constrain() 确保 angle 永远在 0-180 之间,即使传感器异常 angle = constrain(angle, 0, 180); // === 第 4 步:输出到执行器 === myServo.write(angle); // === 第 5 步:调试信息(表格形式更易读)=== Serial.print("Raw:"); Serial.print(xValue); Serial.print(" -> Angle:"); Serial.print(angle); Serial.print("° "); // 打印角度条(可视化) int bars = angle / 5; // 每 5 度一个星号 for (int i = 0; i < bars; i++) Serial.print("*"); Serial.println(); delay(20); // 20ms = 50Hz 刷新率,人眼感觉流畅且不会抖动}课堂互动测试:
进阶讨论(如果时间允许):
// 问:如果摇杆装反了(左是 180°,右是 0°),怎么办?// 答:交换 map 的输出范围int angle = map(xValue, 0, 4095, 180, 0); // 注意这里交换了 180 和 0教学目标: 理解条件判断、软件消抖、中断处理基础
教师讲解引入:
"实际设备通常需要一个'复位'或'紧急停止'功能。我们利用摇杆的按键,让舵机无论在哪里都立即回到 90°(中位)。"
教师编写代码(新增按键处理逻辑):
#include <ESP32Servo.h>// [保留引脚定义]Servo myServo;// 新增:按键状态变量(用于消抖)bool lastButtonState = HIGH; // 上次按键状态(上拉默认 HIGH)bool currentButtonState = HIGH; // 当前按键状态unsigned long lastDebounceTime = 0; // 上次状态变化时间const unsigned long debounceDelay = 50; // 消抖延时 50msvoid setup() { Serial.begin(115200); pinMode(JOY_SW_PIN, INPUT_PULLUP); myServo.attach(SERVO_PIN); Serial.println("系统就绪:推动摇杆控制角度,按下按键回中");}void loop() { // === 摇杆读取与映射(保留之前的代码)=== int xValue = analogRead(JOY_X_PIN); int angle = map(xValue, 0, 4095, 0, 180); angle = constrain(angle, 0, 180); // === 按键处理(带软件消抖)=== // 1. 读取当前按键状态 int reading = digitalRead(JOY_SW_PIN); // 2. 如果状态变了,重置计时器(消抖核心逻辑) if (reading != lastButtonState) { lastDebounceTime = millis(); // 记录状态变化时刻 } // 3. 只有当状态稳定超过 debounceDelay 时间才确认 if ((millis() - lastDebounceTime) > debounceDelay) { // 确认状态确实变了 if (reading != currentButtonState) { currentButtonState = reading; // 按键按下(低电平有效) if (currentButtonState == LOW) { Serial.println(">>> 按键触发:执行回中!"); angle = 90; // 强制覆盖摇杆值 // 视觉反馈:让 LED 闪烁(如果板子有 LED) // digitalWrite(LED_BUILTIN, HIGH); } } } // 4. 保存当前状态供下次比较 lastButtonState = reading; // === 输出到舵机 === myServo.write(angle); // 调试信息(带状态指示) Serial.print("Angle:"); Serial.print(angle); Serial.print("° "); if (currentButtonState == LOW) { Serial.print("[按键按下]"); } else { Serial.print("[跟随摇杆]"); } Serial.println(); delay(20);}消抖原理解释(重点):
为什么需要消抖?机械按键按下时,触点会弹跳几次(几毫秒到几十毫秒),导致电信号在 0 和 1 之间抖动,程序会误以为按了多次。解决方案:记录按键状态变化的时刻,只有当状态稳定保持 50ms 以上,才认为是有效按键,忽略中间的抖动。测试流程:
本文标签:#少儿编程 #科创 #电子爱好者 #物联网 #arduino #ESP32
![]() | ![]() | ![]() |
关注我们,方便学习和答疑