ESP32开发板+TB6612 x 2 四电机小车笔记

目录

一、依照本测试的电子常识(不定期补充)

  • MCU(Microcontroller Unit) :单片机 / 微控制器
    ESP32,就是一块 MCU。
  • GPIO(General-Purpose Input/Output) :通用数字引脚/通用输入输出引脚
    ESP32 上那些 D2、D4、D5、D13... 所有 D 开头的引脚就是,只不过是简写了。
  • 电源、电池、模块供电 :绝对不能接反,接反必烧
  • 电机两根线:不分正负,接反只是反转,不烧
  • 串联 :电压相加,电流不变
  • 并联 :电压不变,容量相加
  • 共用地线(GND/Ground/负极) :所有模块ESP32、TB6612、电源、传感器GND 必须连在一起(共地)
  • ESP32 输出电压 :ESP32 只能输出 3.3V,不能直接控制 高于电压的 设备,必须用驱动板中转。
    • 注意:电机驱动模块 并不是升压、不是加压,它只是 "开关 + 通道"。
      比如:TB6612 输入多少 V 电机电压,输出就是多少 V,不会升高电压!驱动模块上VM 引脚上接了多少V电压,电机两端就是多少V电压,不过还是要注意驱动模块和电机最高能承受多少电压。
  • PWM调速 :PWM并不是真实电压 ,是快速开关模拟出来的
  • 高/低电平 :ESP32 就是靠 不断输出(GPIO) 高 / 低 来告诉 TB6612去驱动电机 转 / 不转 / 正转 / 反转 / 速度多少。
    • esp32的高电平 = 3.3V = 有电 = 1
    • esp32的低电平 = 0V = 没电 = 0
  • ESP32开发板供电/输电
    • 外部供电:通常接 5V(USB / 电池),板载稳压芯片会把 5V 降到 3.3V 给 ESP32 芯片用
    • 所有 GPIO 引脚输出电压:只有 3.3V(高电平 = 3.3V,低电平 = 0V),没有 5V 输出
    • 引脚输入耐压:只能接≤3.3V 的信号,直接接 5V 会烧引脚

二、ESP32开发板

引脚解释

非 D 类引脚(电源、使能、串口)
丝印 功能说明
VIN 电源输入引脚,可接 5V 电源(USB/外部 5V),板载稳压为 3.3V 给 ESP32 供电
GND 电源地(负极),所有 GND 引脚内部连通
EN 芯片使能引脚,高电平(3.3V)运行,低电平(0V)复位/休眠
3V3 3.3V 稳压输出,可给外部传感器/模块供电(限小电流负载)
RX0 GPIO3,UART0 RX(串口0接收,用于烧录/调试日志)
TX0 GPIO1,UART0 TX(串口0发送,用于烧录/调试日志)
D 开头引脚(支持 PWM)
丝印 功能说明
D2 GPIO2,通用数字 IO,支持 PWM/ADC/I2C 等
D4 GPIO4,通用数字 IO,支持 PWM/ADC/I2C 等
D5 GPIO5,通用数字 IO,支持 PWM/SPI 等,上电电平影响启动模式
D12 GPIO12,通用数字 IO,上电电平影响启动模式,谨慎用作关键输入,支持 PWM
D13 GPIO13,通用数字 IO,支持 PWM/ADC/SPI 等
D14 GPIO14,通用数字 IO,支持 PWM/ADC/SPI/I2C 等
D15 GPIO15,通用数字 IO,上电电平影响启动模式,谨慎用作关键输入,支持 PWM
D16 GPIO16,通用数字 IO,可作 UART2 RX,支持 PWM
D17 GPIO17,通用数字 IO,可作 UART2 TX,支持 PWM
D18 GPIO18,通用数字 IO,支持 PWM/SPI/I2C 等
D19 GPIO19,通用数字 IO,支持 PWM/SPI/I2C 等
D21 GPIO21,通用数字 IO,I2C SDA(数据总线),支持 PWM
D22 GPIO22,通用数字 IO,I2C SCL(时钟总线),支持 PWM
D23 GPIO23,通用数字 IO,支持 PWM/SPI 等
D25 GPIO25,通用数字 IO,支持 ADC/PWM/I2S 等
D26 GPIO26,通用数字 IO,支持 ADC/PWM 等
D27 GPIO27,通用数字 IO,支持 ADC/PWM 等
D32 GPIO32,通用数字 IO,支持 ADC/PWM 等
D33 GPIO33,通用数字 IO,支持 ADC/PWM 等
补充:部分引脚上电电平影响启动模式

ESP32 接通电源(上电)的瞬间,部分引脚(如 D5/D12/D15)的电平高低(0V 或 3.3V),会决定 ESP32 进入哪种启动模式,这是 ESP32 硬件设计的固有特性。

模式 触发条件(以上电时引脚电平为准) 用途
正常运行模式 GPIO0(BOOT)= 高电平、GPIO12(D12)= 高电平/悬空 日常运行烧录好的程序(你小车代码的正常工作模式)
下载/烧录模式 GPIO0(BOOT)= 低电平 烧录新程序到 ESP32(需要按住 BOOT 按键上电)
SD 卡启动模式 GPIO12(D12)= 低电平 从外接 SD 卡读取程序运行(极少用到)
D 开头引脚(不支持 PWM,仅输入)
丝印 功能说明
D34 GPIO34,仅输入引脚,支持 ADC,不可输出电平
D35 GPIO35,仅输入引脚,支持 ADC,不可输出电平
VP GPIO36(SENSOR_VP),仅输入引脚,支持 ADC,不可输出电平
VN GPIO39(SENSOR_VN),仅输入引脚,支持 ADC,不可输出电平
特殊引脚
EN 引脚与按键说明

EN 是 Enable(使能)引脚,板上既有按键也有外部焊盘。

  • 电平逻辑:高电平(3.3V)时芯片正常运行,低电平(0V)时芯片复位或进入休眠。
  • 按键作用 :按下 EN 按键会把引脚拉低,让 ESP32 重启(复位),松开后恢复高电平,芯片继续运行。
  • 外部使用:可以外接开关或其他 MCU,来远程复位 ESP32 或实现低功耗唤醒。

注意:不要长期把 EN 引脚拉低,否则芯片会一直处于复位状态,无法正常工作。

BOOT 引脚与按键说明

BOOT 是 Download(下载)引脚,对应芯片的 GPIO0,板上有按键和外部焊盘(部分板丝印为 DOWNLOAD)。

  • 电平逻辑:正常运行时为高电平,进入下载模式时需要拉低。

  • 按键作用:专门用来进入固件下载模式(一般IDE会自动处理),操作步骤是:

    1. 先按住 BOOT 按键不放;
    2. 短按一下 EN 按键(让芯片复位);
    3. 松开 EN 按键,继续按住 BOOT 按键 1~2 秒后松开;
    4. 此时 ESP32 进入 UART 下载模式,电脑就可以通过串口给它烧录新程序。
  • 外部使用:可以外接按键或自动下载电路,让烧录操作更方便。

注意:正常运行时 BOOT 引脚保持高电平,拉低只用于烧录程序,不会影响正在运行的代码。

三、TB6612双路直流电机驱动模块

TB6612FNG 是东芝推出的直流电机驱动芯片,做成模块后可以同时控制 2 个直流电机,支持正反转、PWM 调速、刹车和停止功能。

TB6612FNG 是东芝这款电机驱动芯片的完整型号,FNG 是型号后缀,代表封装与版本信息。

  • TB6612:芯片系列与功能编号(双路 H 桥直流电机驱动)
  • F:封装类型(SSOP,小外形封装)
  • N:引脚数 / 封装规格(24 引脚 SSOP)
  • G:版本 / 批次标识(东芝内部版本代号)

简单说:FNG 就是告诉你 "这颗芯片是 SSOP24 封装的 TB6612 版本"。

特点

  • 可同时驱动 2 路直流电机
  • 电机供电电压:2.2V ~ 13.5V
  • 每路电机连续电流:1.2A,峰值 3.2A
  • 支持 PWM 调速(0~100%占空比)
  • 内置:过流保护、过热保护
  • 效率高、发热量很小
  • 支持 3.3V / 5V 逻辑电平,兼容 ESP32、STM32、Arduino

引脚解释

引脚丝印 功能类型 详细说明 电压/接线
VM 电机电源输入 给电机供电,范围 2.2V~13.5V(常用6~12V) 接电机电源正极
VCC 逻辑电源输入 给芯片内部逻辑供电,2.7V~5.5V(与MCU一致,3.3V/5V) 接MCU 3.3V/5V
GND 逻辑地 芯片逻辑地,必须与MCU、电机电源共地 接系统负极
PGND1/PGND2 功率地 电机驱动大电流地,内部与GND连通 接电源负极
STBY 待机控制 高电平(H)= 正常工作;低电平(L)= 待机(关输出) 接MCU GPIO(默认下拉,需主动拉高)
AIN1 通道A方向输入1 控制电机A正反转 接MCU GPIO
AIN2 通道A方向输入2 控制电机A正反转 接MCU GPIO
PWMA 通道A PWM调速 接收PWM信号控制电机A转速(占空比越大越快) 接MCU PWM引脚
BIN1 通道B方向输入1 控制电机B正反转 接MCU GPIO
BIN2 通道B方向输入2 控制电机B正反转 接MCU GPIO
PWMB 通道B PWM调速 接收PWM信号控制电机B转速 接MCU PWM引脚
AO1 通道A输出1 电机A接线端1 接电机A一端
AO2 通道A输出2 电机A接线端2 接电机A另一端
BO1 通道B输出1 电机B接线端1 接电机B一端
BO2 通道B输出2 电机B接线端2 接电机B另一端

VCC(Voltage Common Collector) :驱动模块自己上面也有芯片(类似ESP32开发板上的esp32芯片),芯片只能用小功率来驱动,给芯片内部逻辑 / 大脑供电(小功率)。
VM(Voltage Motor) :给电机供电(大功率)

电机A控制逻辑(AIN1/AIN2)
AIN1 AIN2 PWMA 电机A状态
H L PWM 正转(速度由PWM决定)
L H PWM 反转
H H × 刹车(短接电机两端)
L L × 停止(自由滑行)

电机 B(BIN1/BIN2)逻辑完全相同。

与 L298N双路直流电机驱动模块 对比

项目 TB6612FNG L298N
驱动类型 双 H 桥 MOSFET 驱动 双 H 桥 双极型晶体管驱动
可驱动电机数量 2 路直流电机 / 1 路 4 线步进电机 2 路直流电机 / 1 路 4 线步进电机
电机工作电压 2.2V ~ 13.5V 6V ~ 46V
单路持续电流 1.2A 2A
单路峰值电流 3.2A 3A
逻辑电压 3.3V / 5V 都支持 5V
效率 高(MOS 管,压降小) 低(晶体管,压降大)
发热情况 几乎不发热 很大,必须加散热片
功耗 低,省电 高,耗电快
控制方式 IN1/IN2 方向 + PWM 调速 IN1/IN2 方向 + PWM 调速
功能 正转、反转、刹车、滑行 正转、反转、刹车
体积 很小,贴片式模块 大,厚重
价格 便宜 便宜
适合场景 智能小车、机器人、小电机 大功率电机、大扭矩、12V 以上系统
补充:H 桥

一种可以让电机正转、反转、刹车的电路结构 。因此双 H 桥就是一个芯片 / 模块里集成了两套 H 桥,可以同时独立控制 2 个电机。

所以:

  • TB6612 = 双 H 桥驱动
  • L298N = 双 H 桥驱动

它们都能驱动 2 个直流电机,适合两轮小车。
另外还有四H桥驱动模块,常见驱动模块有:L293D、DRV8833 四电机版、四路电机驱动板等。

四、小车接线

接线类别 连接起点 连接终点 接线顺序 线数/拆分方式 功能说明
动力供电(正极) 锂电池正极 ESP32 DEV Board - VIN 1 1股(总正极线拆分) 给ESP32主板供电
动力供电(正极) 锂电池正极 TB6612 FNG 1 - VM 2 1股(总正极线拆分) 左驱动板电机动力供电
动力供电(正极) 锂电池正极 TB6612 FNG 2 - VM 3 1股(总正极线拆分) 右驱动板电机动力供电
控制供电(3.3V) ESP32 - 3.3V引脚 TB6612 FNG 1 - VCC 4 1股(3.3V线拆分) 左驱动板控制信号供电
控制供电(3.3V) ESP32 - 3.3V引脚 TB6612 FNG 1 - STBY 5 1股(3.3V线拆分) 左驱动板待机使能(必须接)
控制供电(3.3V) ESP32 - 3.3V引脚 TB6612 FNG 2 - VCC 6 1股(3.3V线拆分) 右驱动板控制信号供电
控制供电(3.3V) ESP32 - 3.3V引脚 TB6612 FNG 2 - STBY 7 1股(3.3V线拆分) 右驱动板待机使能(必须接)
左前轮控制 ESP32 - 18引脚 TB6612 FNG 1 - AIN1 8 单独1根线 左前轮正/反转控制
左前轮控制 ESP32 - 19引脚 TB6612 FNG 1 - AIN2 9 单独1根线 左前轮正/反转控制
左前轮控制 ESP32 - 23引脚 TB6612 FNG 1 - PWMA 10 单独1根线 左前轮转速调节(PWM)
左后轮控制 ESP32 - 22引脚 TB6612 FNG 1 - BIN1 11 单独1根线 左后轮正/反转控制
左后轮控制 ESP32 - 21引脚 TB6612 FNG 1 - BIN2 12 单独1根线 左后轮正/反转控制
左后轮控制 ESP32 - 25引脚 TB6612 FNG 1 - PWMB 13 单独1根线 左后轮转速调节(PWM)
右前轮控制 ESP32 - 14引脚 TB6612 FNG 2 - AIN1 14 单独1根线 右前轮正/反转控制
右前轮控制 ESP32 - 12引脚 TB6612 FNG 2 - AIN2 15 单独1根线 右前轮正/反转控制
右前轮控制 ESP32 - 13引脚 TB6612 FNG 2 - PWMA 16 单独1根线 右前轮转速调节(PWM)
右后轮控制 ESP32 - 5引脚 TB6612 FNG 2 - BIN1 17 单独1根线 右后轮正/反转控制
右后轮控制 ESP32 - 4引脚 TB6612 FNG 2 - BIN2 18 单独1根线 右后轮正/反转控制
右后轮控制 ESP32 - 2引脚 TB6612 FNG 2 - PWMB 19 单独1根线 右后轮转速调节(PWM)
左前轮电机 TB6612 FNG 1 - A01 左前轮电机 - 引脚1 20 单独1根线 左前轮电机动力输出
左前轮电机 TB6612 FNG 1 - A02 左前轮电机 - 引脚2 21 单独1根线 左前轮电机动力输出
左后轮电机 TB6612 FNG 1 - B01 左后轮电机 - 引脚1 22 单独1根线 左后轮电机动力输出
左后轮电机 TB6612 FNG 1 - B02 左后轮电机 - 引脚2 23 单独1根线 左后轮电机动力输出
右前轮电机 TB6612 FNG 2 - A01 右前轮电机 - 引脚1 24 单独1根线 右前轮电机动力输出
右前轮电机 TB6612 FNG 2 - A02 右前轮电机 - 引脚2 25 单独1根线 右前轮电机动力输出
右后轮电机 TB6612 FNG 2 - B01 右后轮电机 - 引脚1 26 单独1根线 右后轮电机动力输出
右后轮电机 TB6612 FNG 2 - B02 右后轮电机 - 引脚2 27 单独1根线 右后轮电机动力输出
接地(负极) 锂电池负极 ESP32 - 任意GND引脚 28 单独1根线 总接地起点,所有设备共地
接地(负极) ESP32 - 另一GND引脚 TB6612 FNG 1 - GND 29 单独1根线 左驱动板接地
接地(负极) TB6612 FNG 1 - 另一GND TB6612 FNG 2 - GND 30 单独1根线 右驱动板接地

1. 供电总结构

bash 复制代码
锂电池(+) ──┬──> ESP32  VIN
            ├──> TB6612_1  VM
            └──> TB6612_2  VM

ESP32  3.3V ─┬──> TB6612_1  VCC
             ├──> TB6612_1  STBY
             ├──> TB6612_2  VCC
             └──> TB6612_2  STBY

锂电池(-) ───> ESP32  GND  ──> TB6612_1 GND ──> TB6612_2 GND

2. 左边驱动板 TB6612_1(控制左前轮、左后轮)

bash 复制代码
ESP32 18 → AIN1
ESP32 19 → AIN2
ESP32 23 → PWMA

AO1、AO2 → 左前轮电机

ESP32 22 → BIN1
ESP32 21 → BIN2
ESP32 25 → PWMB

BO1、BO2 → 左后轮电机

3. 右边驱动板 TB6612_2(控制右前轮、右后轮)

bash 复制代码
ESP32 14 → AIN1
ESP32 12 → AIN2
ESP32 13 → PWMA

AO1、AO2 → 右前轮电机

ESP32  5 → BIN1
ESP32  4 → BIN2
ESP32  2 → PWMB

BO1、BO2 → 右后轮电机

3. 极简总框图

bash 复制代码
                锂电池 (+)
                   │
       ┌──────────┼──────────┐
       │          │          │
       ▼          ▼          ▼
ESP32 ~ VIN    TB6612(1)~VM   TB6612(2)~VM


                ESP32 ~ 3.3V
                     │
       ┌────────────┼────────────┬────────────┐
       │            │            │            │
       ▼            ▼            ▼            ▼
TB6612(1)~VCC   TB6612(1)~STBY   TB6612(2)~VCC   TB6612(2)~STBY


                锂电池 (-)
                    │
                    ▼
              ESP32 ~ GND
                    │
                    ▼
              TB6612(1) ~ GND
                    │
                    ▼
              TB6612(2) ~ GND

五、烧录

  1. 安装Arduino IDE
  2. 国内用户添加国内开发板管理器镜像地址
  3. 安装ESP32开发板适配包(ESP32 by Espressif Systems)【乐鑫(ESP32 芯片原厂)维护】
    • Arduino IDE 本身只支持 Arduino 官方板卡(如 Uno、Nano),要烧录 ESP32 代码,必须通过「开发板管理器」安装 ESP32 的适配包。如果不装 ESP32 专属的驱动(适配包),IDE 根本不认识 ESP32,自然没法给它烧录代码。
    • 注意:不要安装Arduino ESP32 Boards by Arduino,只有 Arduino Nano ESP32 这一款(就是 Arduino 自己出的那个小 ESP32 板子)才可以用。
  4. 选择对应开发板、选择对应数据端口
  5. 编译烧录
  6. 打开串口监控器选择对应代码日志波特率,查看测试日志

测试代码

cpp 复制代码
// 左前
#define AIN1_LF 18
#define AIN2_LF 19
#define PWMA_LF 23

// 左后
#define BIN1_LR 22
#define BIN2_LR 21
#define PWMB_LR 25

// 右前
#define AIN1_RF 14
#define AIN2_RF 12
#define PWMA_RF 13

// 右后
#define BIN1_RR 5
#define BIN2_RR 4
#define PWMB_RR 2

void setup() {
  Serial.begin(115200);

  pinMode(AIN1_LF, OUTPUT);
  pinMode(AIN2_LF, OUTPUT);
  pinMode(PWMA_LF, OUTPUT);

  pinMode(BIN1_LR, OUTPUT);
  pinMode(BIN2_LR, OUTPUT);
  pinMode(PWMB_LR, OUTPUT);

  pinMode(AIN1_RF, OUTPUT);
  pinMode(AIN2_RF, OUTPUT);
  pinMode(PWMA_RF, OUTPUT);

  pinMode(BIN1_RR, OUTPUT);
  pinMode(BIN2_RR, OUTPUT);
  pinMode(PWMB_RR, OUTPUT);

  delay(1000);

  // 开始逐个测试轮子
  Serial.println("=== 左前轮 转 2秒 ===");
  digitalWrite(AIN1_LF, HIGH);
  digitalWrite(AIN2_LF, LOW);
  analogWrite(PWMA_LF, 180);
  delay(2000);
  stopAll();

  Serial.println("=== 左后轮 转 2秒 ===");
  digitalWrite(BIN1_LR, HIGH);
  digitalWrite(BIN2_LR, LOW);
  analogWrite(PWMB_LR, 180);
  delay(2000);
  stopAll();

  Serial.println("=== 右前轮 转 2秒 ===");
  digitalWrite(AIN1_RF, HIGH);
  digitalWrite(AIN2_RF, LOW);
  analogWrite(PWMA_RF, 180);
  delay(2000);
  stopAll();

  Serial.println("=== 右后轮 转 2秒 ===");
  digitalWrite(BIN1_RR, HIGH);
  digitalWrite(BIN2_RR, LOW);
  analogWrite(PWMB_RR, 180);
  delay(2000);
  stopAll();

  Serial.println("=== 测试完成 ===");
}

void loop() {
  // 这里空着,只跑一次测试
}

void stopAll() {
  digitalWrite(AIN1_LF, LOW);
  digitalWrite(AIN2_LF, LOW);
  digitalWrite(BIN1_LR, LOW);
  digitalWrite(BIN2_LR, LOW);
  digitalWrite(AIN1_RF, LOW);
  digitalWrite(AIN2_RF, LOW);
  digitalWrite(BIN1_RR, LOW);
  digitalWrite(BIN2_RR, LOW);
  analogWrite(PWMA_LF, 0);
  analogWrite(PWMB_LR, 0);
  analogWrite(PWMA_RF, 0);
  analogWrite(PWMB_RR, 0);
  delay(100);
}

简易WIFI网页遥控版本

cpp 复制代码
#include <WiFi.h>
#include <WebServer.h>

// ====================== 改成你家的 WiFi ======================
const char* ssid     = "xxx";
const char* password = "xxx";
// ============================================================

#define AIN1_LF 18
#define AIN2_LF 19
#define PWMA_LF 23

#define BIN1_LR 22
#define BIN2_LR 21
#define PWMB_LR 25

#define AIN1_RF 14
#define AIN2_RF 12
#define PWMA_RF 13

#define BIN1_RR 5
#define BIN2_RR 4
#define PWMB_RR 2

WebServer server(80);

void stopAll() {
  digitalWrite(AIN1_LF, 0); digitalWrite(AIN2_LF, 0); analogWrite(PWMA_LF, 0);
  digitalWrite(BIN1_LR, 0); digitalWrite(BIN2_LR, 0); analogWrite(PWMB_LR, 0);
  digitalWrite(AIN1_RF, 0); digitalWrite(AIN2_RF, 0); analogWrite(PWMA_RF, 0);
  digitalWrite(BIN1_RR, 0); digitalWrite(BIN2_RR, 0); analogWrite(PWMB_RR, 0);
}

void forward() {
  stopAll();
  digitalWrite(AIN1_LF, 1); digitalWrite(AIN2_LF, 0); analogWrite(PWMA_LF, 180);
  digitalWrite(BIN1_LR, 1); digitalWrite(BIN2_LR, 0); analogWrite(PWMB_LR, 180);
  digitalWrite(AIN1_RF, 1); digitalWrite(AIN2_RF, 0); analogWrite(PWMA_RF, 180);
  digitalWrite(BIN1_RR, 1); digitalWrite(BIN2_RR, 0); analogWrite(PWMB_RR, 180);
  server.send(200, "text/plain", "ok");
}

void backward() {
  stopAll();
  digitalWrite(AIN1_LF, 0); digitalWrite(AIN2_LF, 1); analogWrite(PWMA_LF, 180);
  digitalWrite(BIN1_LR, 0); digitalWrite(BIN2_LR, 1); analogWrite(PWMB_LR, 180);
  digitalWrite(AIN1_RF, 0); digitalWrite(AIN2_RF, 1); analogWrite(PWMA_RF, 180);
  digitalWrite(BIN1_RR, 0); digitalWrite(BIN2_RR, 1); analogWrite(PWMB_RR, 180);
  server.send(200, "text/plain", "ok");
}

void left() {
  stopAll();
  digitalWrite(AIN1_LF, 0); digitalWrite(AIN2_LF, 1); analogWrite(PWMA_LF, 150);
  digitalWrite(BIN1_LR, 0); digitalWrite(BIN2_LR, 1); analogWrite(PWMB_LR, 150);
  digitalWrite(AIN1_RF, 1); digitalWrite(AIN2_RF, 0); analogWrite(PWMA_RF, 150);
  digitalWrite(BIN1_RR, 1); digitalWrite(BIN2_RR, 0); analogWrite(PWMB_RR, 150);
  server.send(200, "text/plain", "ok");
}

void right() {
  stopAll();
  digitalWrite(AIN1_LF, 1); digitalWrite(AIN2_LF, 0); analogWrite(PWMA_LF, 150);
  digitalWrite(BIN1_LR, 1); digitalWrite(BIN2_LR, 0); analogWrite(PWMB_LR, 150);
  digitalWrite(AIN1_RF, 0); digitalWrite(AIN2_RF, 1); analogWrite(PWMA_RF, 150);
  digitalWrite(BIN1_RR, 0); digitalWrite(BIN2_RR, 1); analogWrite(PWMB_RR, 150);
  server.send(200, "text/plain", "ok");
}

void stopCar() {
  stopAll();
  server.send(200, "text/plain", "ok");
}

void handleRoot() {
  String html = R"HTML(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小车遥控</title>
<style>
  * {
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }
  body {
    text-align: center;
    margin-top: 40px;
  }
  button {
    width: 220px;
    height: 110px;
    font-size: 36px;
    margin: 10px;
    border-radius: 10px;
    background: #4CAF50;
    color: white;
    border: none;
  }
</style>
</head>
<body>
<h1>小车遥控</h1>

<button
  touchstart="fetch('/forward')"
  touchend="fetch('/stop')"
  mousedown="fetch('/forward')"
  mouseup="fetch('/stop')"
>
前进
</button><br>

<button
  touchstart="fetch('/backward')"
  touchend="fetch('/stop')"
  mousedown="fetch('/backward')"
  mouseup="fetch('/stop')"
>
后退
</button><br>

<button
  touchstart="fetch('/left')"
  touchend="fetch('/stop')"
  mousedown="fetch('/left')"
  mouseup="fetch('/stop')"
>
左转
</button>

<button
  touchstart="fetch('/right')"
  touchend="fetch('/stop')"
  mousedown="fetch('/right')"
  mouseup="fetch('/stop')"
>
右转
</button><br>

<button onclick="fetch('/stop')">停止</button>

<script>
// 给按钮绑定触摸事件
document.querySelectorAll('button').forEach(btn => {
  btn.addEventListener('touchstart', (e) => {
    e.preventDefault();
    eval(btn.getAttribute('touchstart'));
  });
  btn.addEventListener('touchend', (e) => {
    e.preventDefault();
    eval(btn.getAttribute('touchend'));
  });
});
</script>
</body>
</html>
)HTML";
  server.send(200, "text/html; charset=utf-8", html);
}

void setup() {
  Serial.begin(115200);
  delay(500);

  pinMode(AIN1_LF, OUTPUT);
  pinMode(AIN2_LF, OUTPUT);
  pinMode(PWMA_LF, OUTPUT);
  pinMode(BIN1_LR, OUTPUT);
  pinMode(BIN2_LR, OUTPUT);
  pinMode(PWMB_LR, OUTPUT);
  pinMode(AIN1_RF, OUTPUT);
  pinMode(AIN2_RF, OUTPUT);
  pinMode(PWMA_RF, OUTPUT);
  pinMode(BIN1_RR, OUTPUT);
  pinMode(BIN2_RR, OUTPUT);
  pinMode(PWMB_RR, OUTPUT);

  stopAll();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi 连接成功!");
  Serial.print("控制地址:");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/forward", forward);
  server.on("/backward", backward);
  server.on("/left", left);
  server.on("/right", right);
  server.on("/stop", stopCar);

  server.begin();
}

void loop() {
  server.handleClient();
}

esp32小车测试

相关推荐
A923A2 小时前
【Vue3大事件 | 项目笔记】第五天
前端·vue.js·笔记·前端项目
1104.北光c°2 小时前
双令牌机制:让认证更安全、体验更流畅
java·开发语言·笔记·后端·安全·token·双令牌
阿拉斯攀登2 小时前
第 10 篇 RK 平台安卓驱动实战 3:PWM 驱动开发,实现 LED 呼吸灯 + 电机调速
驱动开发·嵌入式硬件·pwm·瑞芯微·嵌入式驱动·rk3576·嵌入式安卓
集芯微电科技有限公司2 小时前
氮化镓GaN FET/GaN HEMT功率驱动器选型一览表
人工智能·单片机·嵌入式硬件·深度学习·神经网络·生成对抗网络
7yewh11 小时前
jetson_yolo_deployment 01_linux_dev_env
linux·嵌入式硬件·yolo·机器人·嵌入式
WinstonMao12 小时前
STM32上电不能开机运行问题排查
stm32·单片机·嵌入式硬件
杨小扩16 小时前
OpenAI Codex CLI 命令行参考笔记
人工智能·笔记
csg110716 小时前
PIC单片机高阶实战(四):PIC32MX串口与4G模块通信
单片机·嵌入式硬件·物联网
做cv的小昊16 小时前
大语言模型系统:【CMU 11-868】课程学习笔记06——Transformer学习(Transformer)
笔记·学习·语言模型