文章目录
- 智能小车
- 电机驱动模块L9110S介绍
-
- [1. L9110S型号介绍](#1. L9110S型号介绍)
- [2. L9110S参数及引脚介绍](#2. L9110S参数及引脚介绍)
- 思考?【为什么左转时,左轮全设置为高电平,而不是低电平?】
- 循迹模块TCRT5000
-
- [1. 模块介绍](#1. 模块介绍)
-
- [1.1 型号介绍](#1.1 型号介绍)
- [1.2 工作参数及引脚介绍](#1.2 工作参数及引脚介绍)
- [1.3 通信示意图](#1.3 通信示意图)
- [1.3 TCRT5000工作原理](#1.3 TCRT5000工作原理)
- 测速模块
-
- [1. 测速模块介绍](#1. 测速模块介绍)
-
- [1.1 测速模块型号介绍](#1.1 测速模块型号介绍)
- [1.2 测速模块参数及引脚介绍](#1.2 测速模块参数及引脚介绍)
- [2. 使用逻辑](#2. 使用逻辑)
- 4G模块
-
- [1. 内网穿透](#1. 内网穿透)
- [2. 花生壳配置【借助该工具生成IP地址】](#2. 花生壳配置【借助该工具生成IP地址】)
- [3. 4G模块配置](#3. 4G模块配置)
- 项目1:让小车动起来
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
-
- [3.1 框架搭建](#3.1 框架搭建)
- [3.2 小车内容](#3.2 小车内容)
- 项目2:串口控制小车
-
- 1.项目需求
- [2. 构思环节](#2. 构思环节)
-
- [2.1 框架搭建](#2.1 框架搭建)
- [2.2 功能处理](#2.2 功能处理)
- 项目3:蓝牙控制小车
- 项目4:小车点动控制
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
- [4. 实验结果](#4. 实验结果)
- 项目5:PWM调速小车
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
- [4. 实验结果](#4. 实验结果)
- 项目6:循迹小车
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
-
- [3.1 框架搭建](#3.1 框架搭建)
- [3.2 循迹模块修改](#3.2 循迹模块修改)
- [3.3 主函数](#3.3 主函数)
- 循迹+pwm调速功能实现
- 项目7:跟随小车
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
- [4. 实验结果](#4. 实验结果)
- 项目8:避障小车
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
- [4. 出现的问题](#4. 出现的问题)
- [5. 实验结果](#5. 实验结果)
- 项目9:测速小车
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
-
- [1. 测速](#1. 测速)
- [2. 速度显示在OLED屏幕上,并通过蓝牙模块传输到手机上](#2. 速度显示在OLED屏幕上,并通过蓝牙模块传输到手机上)
- [4. 实验结果](#4. 实验结果)
- 项目10:Wifi控制小车并发送速度
-
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
- [4. 出现的问题](#4. 出现的问题)
- [5. 实验结果](#5. 实验结果)
- [项目11: 4G 控制小车](#项目11: 4G 控制小车)
- [项目12 :语音控制小车](#项目12 :语音控制小车)
-
- 语音模块:SU-03T
-
- [1. 语音模块介绍](#1. 语音模块介绍)
-
- [1.1 型号介绍](#1.1 型号介绍)
- [1.2 工作参数及引脚介绍](#1.2 工作参数及引脚介绍)
- [2. 通信示意图](#2. 通信示意图)
- [3. SU-03T 配置](#3. SU-03T 配置)
- [4. 如何烧录?](#4. 如何烧录?)
- [1. 项目需求](#1. 项目需求)
- [2. 硬件接线](#2. 硬件接线)
- [3. 构思环节](#3. 构思环节)
- [4. 实验结果](#4. 实验结果)
智能小车
电机驱动模块L9110S介绍
1. L9110S型号介绍
L9110S有二路和四路两种,二路可以驱动2个直流电机,或者1个4线2相式步进电机;四路可以驱动4个直流电机,或者2个4线2相式步进电机。
二路和四路

2. L9110S参数及引脚介绍
L9110S参数:
- 双L9110S芯片的电机驱动
- 模块供电电压:2.5V~12V
- 工作温度:0℃~80℃
- 适合的电机范围:电机工作电压2.5V~12V之间,最大工作电流0.8A
- 可以同时驱动2个直流电机,或者1个4线2相式步进电机
- PCB板尺寸:2.8cm*2.1cm超小体积,适合组装
- 设有固定安装孔,直径:3mm

| STM32 | 电机驱动L9110S | 备注 |
|---|---|---|
| 任意GPIO口 | A-1A | 控制电机 |
| 任意GPIO口 | A-1B | 控制电机 |
| 任意GPIO口 | B-1A | 控制电机 |
| 任意GPIO口 | B-1B | 控制电机 |
| VCC | 外接电源正极(2.5~12V) | |
| GND | 外接电源负极 |
用杜邦线可以直接插进模块绿色的接口,其他的线用螺丝刀调整接口大小即可接入。
接通VCC、GND,模块电源指示灯(红)灯亮。
以驱动2个直流电机为例:
A-1A输入高电平,A-1B输入低电平,MotorA电机正转;
A-1A输入低电平,A-1B输入高电平,MotorA电机反转;
B-1A输入高电平,B-1B输入低电平,MotorB电机正转;
B-1A输入低电平,B-1B输入高电平,MotorB电机反转;
思考?【为什么左转时,左轮全设置为高电平,而不是低电平?】
如果在左转时把左轮两个引脚都设为高电平。
- 左轮会瞬间急刹,不仅导致车身剧烈抖动,转弯极不平稳
- 瞬间短路电流极大,会导致电源电压剧烈波动(可能复位单片机),甚至烧毁电机驱动芯片的MOS管。
循迹模块TCRT5000
在自动驾驶和机器人技术领域,循迹模块是至关重要的组成部分。它能够使车辆或机器人沿着预定的路径精确行驶,从而实现各种复杂任务。
1. 模块介绍
1.1 型号介绍
TCRT5000 不断发射红外信号,当红外信号:
- 有反射回来,DO 输出低电平,开关指示灯(绿灯)亮。
- 没反射回来,DO 输出高电平,开关指示灯(绿灯)灭。
TCRT5000 常见用途:
- 电度表脉冲数据采样
- 传真机碎纸机纸张检测
- 障碍检测
- 黑白线检测(包含循迹小车)

1.2 工作参数及引脚介绍
TCRT5000红外循迹模块工作参数:
- 工作电压:DC 3.3V ~ 5V
- 检测反射距离:1mm ~ 25mm适用(不同厂家会略有差异)

模拟中蓝色的电位器用于调节灵敏度,顺时针旋转,灵敏度变高;
逆时针越小,灵敏度变低。
上电后电源指示灯(红灯)亮
接线如下:
| TCRT5000 | STM32 | 备注 |
|---|---|---|
| VCC | 3.3/5V | 电源正极 |
| GND | GND | 电源负极 |
| DO | 任意GPIO口 | 数字输出 |
| AO | 有ADC功能的引脚 | 模拟输出(一般不用) |
1.3 通信示意图
这个小案例的应用场景可以应用在工业自动化,当物体或人在禁止区域或危险区域时,红灯亮起以提醒离开此区域。

1.3 TCRT5000工作原理
简述:
有障碍物,DO输出低电平,开关指示灯亮
无障碍物,DO输出高电平,开关指示灯灭
测速模块
测速是现代化测控系统中不可或缺的一部分,它通过精确测量物体或现象的速度,为众多应用领域提供了关键的数据支持。
1. 测速模块介绍
1.1 测速模块型号介绍
测速模块常见用途:
- 电机转速检测
- 脉冲计数
- 位置限位
- 工件计数
常见的测速模块有以下三款,大同小异,都是接三个引脚(四引脚的那款AO引脚不起作用),除了正负极就是数字输出(OUT)。

1.2 测速模块参数及引脚介绍
测速模块参数:
- 使用进口槽型光耦传感器,槽宽度10mm
- 有遮挡,输出高电平;无遮挡,输出低电平
- 有输出状态指示灯,输出高电平灯灭,输出低电平灯亮
- 使用宽电压LM393比较器
- 比较器输出,信号干净,波形好,驱动能力强,超过15mA
- 工作电压:3.3V ~ 5V
- 输出形式:数字开关量输出(0和1)
- 设有固定螺栓孔,方便安装
- 小板PCB尺寸:2.3cm × 2cm

参考接线:
| 测速模块 | STM32 | 备注 |
|---|---|---|
| VCC | 3.3/5V | 电源正极 |
| OUT | 任意GPIO口 | 数字输出 |
| GND | GND | 电源负极 |
OUT连接:
- 与单片机IO口直接相连,检测传感器是否有遮挡,如用电机码盘则可检测电机的转速。
- 与继电器相连,组成限位开关等功能。
- 与有源蜂鸣器模块相连,组成报警器。
2. 使用逻辑
- 测速模块槽汇总无遮挡时,输出低电平,灯亮;遮挡时,输出高电平,灯灭;
- 圆周长C = 2 × 3.14 × r = 3.14 × d
以TT马达和配套轮胎(直径6.5cm)、码盘(20个格子)为例:
- 码盘每经过一个格子,会遮挡(高电平)和不遮挡(低电平);
- 20格的码盘转一圈会经历20个下降沿中断,一个下降沿中断就是圆的周长÷20 = 3.14 × 6.5 / 20 = 1.0205 cm, 约等于一个中断走1 cm。
测速模块测距离:计算中断次数,即距离
测速模块测速度:利用定时器,1秒内接收多少个外部中断,即每秒速度。
使用逻辑:
-
如何计算中断次数?
对GPIO口进行配置,接着对测速模块的引脚计算产生多少中断,在中断中进行++,算出距离
-
单位时间内测算距离?
定时器定时1秒,观察中断几次,将中断里的变量拿出来。
其他轮胎或码盘可套用公式:
测距离 = 3.14×直径/码盘格子×中断次数。
测速度 = 定时器每秒输出 3.14×直径/码盘格子×中断次数,记得重置中断次数。
4G模块
局域网:可理解为设备连接到同一个路由器
1. 内网穿透
简单说,连接到一个路由器的为一个内网;路由器以外是外网,两个路由器是外网。
如何用外网访问内网?
------内网穿透

如何实现内网穿透?
借助花生壳工具 实现内网穿透

2. 花生壳配置【借助该工具生成IP地址】


用网络调试助手,外网方式访问(内网穿透)

外网与内网通信:

内网之间也可以通信:

3. 4G模块配置
接线图:

4G模块:可理解为自带网络
相关参数:

注意:上述表格中"DATA与LINK"的后面介绍反了
4g模块支持AT指令,可通过EC05配置上位机:

上位机配置:
- 选择端口号(根据自己的端口选择)
- 选择波特率(默认115200)
- 打开串口
- 点击进入配置,上位机会自动发送AT指令进行配置
- 读取参数,此命令可以读取4G模块的详细信息,并打印带有基本信息栏(这一步很重要,否则第九步时会出现问题)
- 选择链路
- 默认是连接亿佰特的服务器,需要修改成我们自己的,具体从花生壳获取(是一串域名,或者IP地址,他都支持,根据自己获取到的填写就可以)
- 输入从花生壳获取的端口号
- 点击保存配置(对应第五步,我们很多配置需要获取到模块默认配置,保存时才会不改变)
- 点击重启(重启后默认进入透传模式,无需在做其他操作,直接链接到串口助手上即可发送与接收信息)

上位机配置完成,接下来开始发送数据,可通过串口调试助手发送
串口调试助手相当于4G模块

心跳包 :每隔10秒钟发送一次

进入AT指令,发送+++不用换行,收\r\n+OK\r\n,即进入到
项目1:让小车动起来
1. 项目需求
让小车动起来,实现小车前进、后退、左转、右转功能。
2. 硬件接线
| STM32 | 电机驱动 |
|---|---|
| PB1 | A-1A |
| PB0 | A-1B |
| PB10 | B-1A |
| PB2 | B-1B |
电机由电池供电;
上官二号由ST-Link供电;
3. 构思环节
3.1 框架搭建
- 创建智能小车项目文件夹
- 将串口打印功能实验的文件夹改名为"让小车动起来"
- 在BSP文件夹中创建motor文件夹
- 打开keil软件,将motor文件加载进来
3.2 小车内容
motor.c
c
#include "motor.h"
void motor_init(void)
{
1. 打开时钟
2. 引脚【多个引脚】
3. 推挽输出
4. 上拉
5. 高速
HAL_GPIO_Init(GPIOB, 句柄);
6. 小车停止 // 小车上电后,处于停止状态
}
void motor_go_forward(void)
{
// 左轮 PB0和PB1是左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
// 右轮 PB2和PB10是右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
}
void motor_go_backward(void)
{
// 左轮 PB0和PB1是左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
// 右轮 PB2和PB10是右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
}
// 左转时,左轮不动,右轮动
void motor_go_left(void)
{
// 左轮 PB0和PB1是左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
// 右轮 PB2和PB10是右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
}
// 右转时,右轮不动左轮动
void motor_go_right(void)
{
// 左轮 PB0和PB1是左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
// 右轮 PB2和PB10是右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
}
void motor_stop(void)
{
// 左轮 PB0和PB1是左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
// 右轮 PB2和PB10是右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
}
main.c
- 初始化
- 实现前进后退左转右转
c
while(1)
{
motor_go_forward();
delay_ms(2000);
motor_go_backward();
delay_ms(2000);
motor_go_left();
delay_ms(2000);
motor_go_right();
delay_ms(2000);
motor_go_stop();
delay_ms(2000);
}
项目2:串口控制小车
1.项目需求
串口控制小车
2. 构思环节
2.1 框架搭建
- 在让小车动起来实验基础上做该项目
- 在BSP文件夹中加入蓝牙bluetooth文件夹
- 先注释while循环中的代码
- 加载蓝牙模块进来,msp函数加入串口2,因为蓝牙要用到
2.2 功能处理
蓝牙控制小车实现效果:
发送M1,前进
发送M2,后退
发送M3,左转
发送M4,右转
蓝牙模块,是在串口2中断服务函数中获取数据,接收串口收到的数据,接下来对串口的数据进行处理:
- 比对接收到的数据和**"M1"**, 前进
c
if(strcmp((char *)uart2_rx_buf, "M1") == 0)
motor_go_forward();
else if(strcmp((char *)uart2_rx_buf, "M2") == 0)
motor_go_backward();
else if(strcmp((char *)uart2_rx_buf, "M3") == 0)
motor_go_left();
else if(strcmp((char *)uart2_rx_buf, "M4") == 0)
motor_go_right();
else
motor_stop();
- 主函数
main.c
c
bt_init(9600);
- 硬件上
插上串口2
串口2发送M1,串口1接收到M1,小车前进
串口2发送M2,串口1接收到M2,小车后退
串口2发送M3,串口1接收到M3,小车左转
串口2发送M4,串口1接收到M4,小车右转
项目3:蓝牙控制小车
本节项目不涉及代码,直接从项目2串口控制小车中,串口2换成蓝牙模块,通过手机HC蓝牙助手软件发送M1、M2、M3、M4,观察结果。
该小车目前通过ST-Link供电,如何让上官二号通过电池供电,实现小车自己跑?
1个电池1.5V,4个电池6V
找一个公对母的杜邦线,一边接面包板正极,一边接主板的5V
项目4:小车点动控制
1. 项目需求
利用HC蓝牙助手软件,按下前进按键,小车前进一下,实现点动控制小车。
2. 硬件接线
硬件接线上,拔掉蓝牙模块,插入串口2,同时去掉上一个实验的5V杜邦线
3. 构思环节
- 在串口控制小车实验基础上做
- 实现环节
main.c
c
while(1)
{
motor_stop();
}
初始化时,处于stop状态;
串口接收数据时,小车动起来
bluetooth.c
在中断函数这,对小车的前进后退左转右转进行延时
c
delay_ms(10);
4. 实验结果
利用串口2循环发"M1",实现点动效果

项目5:PWM调速小车
1. 项目需求
小车控速,不一直以最快速度跑。

2. 硬件接线
| STM32 | 电机驱动 |
|---|---|
| PA0 | A-1A |
| PB1 | A-1B |
| PA1 | B-1A |
| PB10 | B-1B |
3. 构思环节
- 在项目1基础上做该项目
- 复制呼吸灯实验的pwm文件夹
- 一系列加载动作,不具体说明【HAL库的定时器记得也加载起来】
- pwm修改
pwm.c
c
pwm_init()
{
// 时基单元
修改定时器为TIM2
// 配置
Pluse = 0
高电平
配置为通道1和通道2
开启通道1和通道2
}
msp函数
1. 修改引脚为PA0和PA1
2. 推挽输出
3. 上拉
4. 高速
修改CCR值的函数
// 左轮
void pwm_left_motor_set(uint16_t val)
{
__HAL_TIM_SET_COMPARE(&pwm_handle, TIM_CHINNEL_1, val);
}
// 右轮
void pwm_right_motor_set(uint16_t val)
{
__HAL_TIM_SET_COMPARE(&pwm_handle, TIM_CHINNEL_2, val);
}
main.c
c
pwm_init(20 - 1, 72 - 1);
// 调速
while(1)
{
pwm_left_motor_set(8);
pwm_right_motor_set(8);
delay_ms(1000);
pwm_left_motor_set(10);
pwm_right_motor_set(10);
delay_ms(1000);
pwm_left_motor_set(15);
pwm_right_motor_set(15);
delay_ms(1000);
}
如何实现左轮快,右轮慢?
c
pwm_left_motor_set(8);
pwm_right_motor_set(15);
delay_ms(1000);
pwm_left_motor_set(15);
pwm_right_motor_set(8);
delay_ms(1000);
4. 实验结果
上电后,小车左轮先慢后快,右轮先快后慢。
项目6:循迹小车
1. 项目需求
实现小车按跑道路线行驶。
2. 硬件接线
| STM32 | 电机驱动 | 循迹模块 |
|---|---|---|
| PB0 | A-1A | |
| PB1 | A-1B | |
| PB2 | B-1A | |
| PB10 | B-1B | |
| PB13 | DO(左) | |
| PB14 | DO(右) |
3. 构思环节
3.1 框架搭建
- 在项目1【让小车动起来】实验基础上做该项目
- 先复制智能台灯项目中的ia_sensor文件夹,并添加到该项目的BSP文件夹中,改名为track。
3.2 循迹模块修改
- 修改引脚PB13和PB14
- 功能:
左边循迹模块是否踩到黑线,踩到则输出一个值;未踩到输出另一个值
c
uint8_t track_left_flag(void)
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET)
return TRUE;
else
return FALSE;
}
uint8_t track_right_flag(void)
{
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
return TRUE;
else
return FALSE;
}
3.3 主函数
main.c
c
track_init();
while(1)
{
1. 判断循迹模块返回的是true还是false
2. 如果为false,踩到黑线,需左转或右转
if(track_left_flag() == TRUE && track_right_flag() == TRUE)
motor_go_forward();
// 车头往右,所以要左转来回正
else if (track_left_flag() == FALSE && track_right_flag() == TRUE)
motor_go_left();
else if (track_left_flag() == TRUE && track_right_flag() == FALSE)
motor_go_right();
else if (track_left_flag() == FALSE && track_right_flag() == FALSE)
motor_stop();
}
小车在跑道上拐弯后,冲出跑道,如何解决?
小车降速;电池换成锂电池,重量减轻。
循迹+pwm调速功能实现
在pwm调速小车实验基础上做搞项目
接线与pwm调速项目接线一致
| STM32 | 电机驱动 |
|---|---|
| PB10 | A-1A |
| PA0 | A-1B |
| PB1 | B-1A |
| PA1 | B-1B |
主函数
main.c
c
// 因为设置10过快,设置9过慢,所以修改arr和psc的值
pwm_init(200 - 1, 720 - 1);
track_init();
while(1)
{
if(track_left_flag() == TRUE && track_right_flag() == TRUE)
{
pwm_left_motor_set(95);
pwm_right_motor_set(95);
}
else if(track_left_flag() == FALSE && track_right_flag() == TRUE)
{
pwm_left_motor_set(0);
pwm_right_motor_set(95);
}
else if(track_left_flag() == TRUE && track_right_flag() == FALSE)
{
pwm_left_motor_set(95);
pwm_right_motor_set(0);
}
else if(track_left_flag() == FALSE && track_right_flag() == FALSE)
{
pwm_left_motor_set(0);
pwm_right_motor_set(0);
}
}
出现的问题:占空比太低,带不动右轮
解决:
可修改arr和psc的值;
也可以先加速调速,判断是否为占空比低导致的
项目7:跟随小车
1. 项目需求
使用红外模块,
左边红外模块检测到有物体,左转【右轮动】,追随物体;
右边红外模块检测到有物体,右转【左轮动】,追随物体;
如果物体过大,左右红外模块同时检测到物体,小车一直前进,追随物体。
2. 硬件接线
| STM32 | 电机驱动 | 跟随模块 |
|---|---|---|
| PB10 | A-1A | |
| PB2 | A-1B | |
| PB1 | B-1A | |
| PB0 | B-1B | |
| PB5 | OUT(左) | |
| PB6 | OUT(右) |
3. 构思环节
- 在项目1【让小车动起来】基础上做该实验
- 复制循迹模块文件夹,添加到该项目的BSP文件夹中,改名为follow。
- 内容修改
c
修改引脚
- main函数
c
follow_init();
while(1)
{
if(follow_left_flag() == TRUE && follow_right_flag() == TRUE)
motor_go_forward();
else if(follow_left_flag() == TRUE && follow_right_flag() == FALSE)
motor_go_left();
else if(follow_left_flag() == FALSE && follow_right_flag() == TRUE)
motor_go_right();
else if(follow_left_flag() == TRUE && follow_right_flag() == FALSE)
motor_stop();
}
4. 实验结果
跟着障碍物路线走
项目8:避障小车
1. 项目需求
超声波传感器测距,小于某个值就是障碍物,小车遇到障碍物之后,小车停下,判断左转还是右转,
这时超声波传感器左转,测量左边距离,再转回中间;
接下来超声波传感器右转,测量右边距离;
判断左边与右边的距离,
如果左边距离<右边距离,左边障碍物距离更近,往右转;
反之,则左转。
2. 硬件接线
| STM32 | 电机驱动 | 舵机 | 超声波 |
|---|---|---|---|
| PB10 | A-1A | ||
| PB2 | A-1B | ||
| PB1 | B-1A | ||
| PB0 | B-1B | ||
| PA6 | 橙线 | ||
| PA12 | Trig | ||
| PA11 | Echo |
3. 构思环节
- 在项目1【让小车动起来】基础上做搞项目
- 在BSP文件夹添加sg90文件夹、hcsr04文件夹,并加载进来,将HAL库的定时器加载进来。
- sg90模块内容【摇头】
c
1. 左转
void sg90_turn_left(void)
{
sg90_angle_set(180);
}
2. 居中
void sg90_turn_middle(void)
{
sg90_angle_set(90);
}
3. 右转
void sg90_turn_right(void)
{
sg90_angle_set(0);
}
- main函数
c
sg90_init();
while(1)
{
sg90_turn_left();
delay_ms(1000);
sg90_turn_middle();
delay_ms(1000);
sg90_turn_right();
delay_ms(1000);
}
- hcsr40【测距】
main.c
c
hcsr04_init();
while(1)
{
printf("dis: %.2f\r\n", hcsr04_get_length());
delay_ms(1000);
}
- 测距+摇头
c
double dis_left = 0, dis_middle = 0, dis_right = 0;
// 传感器初始化时,为居中状态
sg90_turn_middle();
// 开始测量
while(1)
{
// 先测量中间数据
dis_middle = hcsr04_get_length();
如果大于某个距离
if(dis_middle > 35)
motor_go_forward();
else if(dis_middle < 15)
motor_go_backward();
else
{
1. 先停下
motor_stop();
2. 向左看,并测量左侧距离
sg90_turn_left();
delay_ms(500);
dis_left = hcsr04_get_length();
3. 居中
sg90_turn_middle();
delay_ms(500);
4. 向右看,并测量右边距离
sg90_turn_right();
delay_ms(500);
dis_right = hcsr04_get_length();
5. 根据距离判断是左转还是右转
if(dis_left < dis_right)
motor_go_right();
else
motor_go_left();
delay_ms(200);
motor_stop();
sg90_turn_middle();
}
delay_ms(100);
}
4. 出现的问题
小车在判断转向时,小车并不左转还是右转,而是一直原地转。
c
if(dis_left < dis_right)
sg90_turn_right();
else
sg90_turn_left();
解决:【自己对小车理解错误】
5. 实验结果
链接:https://live.csdn.net/v/537461?spm=1001.2014.3001.5501
项目9:测速小车
1. 项目需求
串口输出电机旋转距离(cm)和速度(cm/s);
速度显示在OLED屏幕上,并通过蓝牙模块传输到手机上;
2. 硬件接线
| STM32 | 电机驱动 | 测速模块 | OLED |
|---|---|---|---|
| PB0 | A-1A | ||
| PB1 | A-1B | ||
| PB2 | B-1A | ||
| PB10 | B-1B | ||
| PB12 | OUT | ||
| PB8 | SCL | ||
| PB9 | SDA | ||
| 3.3V | VCC | VCC | VCC |
| GND | GND | GND | GND |
⚠️注意:测速模块、蓝牙模块、OLED模块,都需要接到3.3V电源!
3. 构思环节
1. 测速
- 在项目2【串口控制小车】基础上做该项目
- 新建speed文件夹,加入相关.c和.h文件,用来测速;别忘记加入HAL库中的定时器
- 测速模块内容
speed.c
c
#include "speed.h"
#include "stdio.h"
用来接收产生多少个中断
uint16_t speed_cnt = 0;
void speed_gpio_init(void)
{
参考中断代码
1. 引脚PB12
2. 无上拉下拉
3. 中断时10~15
}
// 中断处理函数
void EXTI_IRQHandler(void)
{
修改引脚
}
// 中断服务函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
修改引脚
speed_cnt++;
printf("speed: %d\r\n", speed_cnt);
}
void speed_time_init(void)
{
}
void speed_init(void)
{
speed_gpio_init();
}
main.c
c
speed_init();
motor_go_forward();
先测试,串口的速度一直在一个格子的增加,说明在数格子,即成功
接下来,加入定时器,定时1秒钟,1秒钟数了多少个格子
speed.c
c
void speed_time_init(psc,arr)
{
参考之前定时器中断点灯代码
定时器2
}
msp函数
中断服务函数
更新中断回调函数:功能实现
printf("speed: %d\r\n", speed_cnt);
speed_cnt = 0; // 清空,否则出现影响下一次计数
测试模块初始化
void speed_init(void)
{
speed_gpio_init();
speed_time_init(10000 - 1, 7200 - 1);
}
测试:如果速度在30~60多,说明正确。
2. 速度显示在OLED屏幕上,并通过蓝牙模块传输到手机上
- 在测速小车实验基础上做
- 在BSP文件夹中,添加OLED文件夹【在以前实验中复制过来最简单】
- main函数中进行初始化
- 在speed.c中的中断回调函数里,已经获取到速度的值,接下来要把这个值显示在oled屏幕上,实现如下:
oled引脚也需要修改
c
#include "string.h"
#include "oled.h"
char speed_str[24] = {0};
void HAL_TIM_PeriodElapsedCalback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
printf("speed: %d\r\n", speed_cnt);
先进行清空
memset(speed_str, 0, sizeof(speed_str));
sprintf(speed_str, "speed: %2d cm/s", speed_cnt);
oled_show_string(10, 2, speed_str, 16);
蓝牙模块
bt_send(speed_str);
bt_send("\r\n");
speed_cnt = 0;
}
}
oled.c
修改oled引脚
oled修改
c
oled_init(void)
{
最后要清屏,否则全是雪花
oled_fill(0x00);
}
这时,蓝牙收到的速度可能会有点异常
bt_send函数中,发送数据函数修改
HAL_UART_Transmit(&uart2_handle, send_buf, strlen((char *)send_buf), 100);
4. 实验结果
oled屏幕显示速度:

蓝牙模块显示速度:

项目10:Wifi控制小车并发送速度
1. 项目需求
通过Wifi模块控制小车前进后退,测速模块测量到的数据传递到上位机中,电脑可查看小车速度。
2. 硬件接线
将蓝牙模块的接线换成ESP8266 Wifi模块,注意VCC一定要接3.3V,否则会烧坏板子
3. 构思环节
- 在项目10【测速小车OLED显示并上传蓝牙】基础上做该实验,wifi控制小车并发送速度
- 添加esp8266文件夹,并加载;去掉蓝牙模块代码
- esp8266内容
WIFI账号和密码
TCP_SERVER_IP:电脑上架设的服务器
服务器通过网络调试助手,选择TCP服务器,本地主机地址通过ipconfig查找

main.c
c
esp8266_init();
蓝牙模块使用空闲中断,而esp8266只用到接收中断
- 通过esp8266 wifi模块收发数据
speed.c
c
在更新中断回调函数中
esp8266_send_data(speed_str); // 数据通过esp8266发出去
在哪里接收数据呢?
main.c
c
char recv_data[ESP8266_RX_BUF_SIZE]
while(1)
{
eps8266_receive_data(recvive_data);
1. 如果发送"M1",前进
if(strstr(recvive_data, "M1") != NULL)
motor_go_forward();
2. 如果发送"M2",后退
else if(strstr(recvive_data, "M2") != NULL)
motor_go_backward();
3. 如果发送"M3",左转
else if(strstr(recvive_data, "M3") != NULL)
motor_go_left();
4. 如果发送"M4",右转
else if(strstr(recvive_data, "M4") != NULL)
motor_go_right();
else
motor_stop();
delay_ms(10);
}
4. 出现的问题

因为中断这里加了延时导致的发送"M1"后前进,到发送"M2",不能立即执行小车后退。之前的实验是为了消抖,所以加入了延时,在这里不需要。
5. 实验结果
- 通过串口打印到串口调试助手;
- oled屏幕显示速度
- 通过esp8266将数据传递到上位机【网络调试助手】 ,网络调试助手可以发送"M1、M2、M3、M4"控制小车。





项目11: 4G 控制小车
-
用花生壳搭建服务器【第146~149课】
花生壳做内网穿透
-
配置4G模块
使用指令工具配置,填写服务器地址和端口
-
4G模块接线
将esp8266模块替换为4G模块
VCC------接到USB转TTL上的5V引脚
GND------GND
-
代码直接使用项目9
修改bt_init(115200), 4G波特率为115200,蓝牙模块波特率为9600。
-
实验效果:
打开网络调试助手和串口调试助手
网络调试助手发送"M1",小车前进,串口调试助手和oled屏幕显示速度;
网络调试助手发送"M2",小车后退,串口调试助手和oled屏幕显示速度;
网络调试助手发送"M3",小车左转,串口调试助手和oled屏幕显示速度;
网络调试助手发送"M4",小车右转,串口调试助手和oled屏幕显示速度。
⚠️4G模块重点在于配置部分,内网穿透、花生壳配置等。
项目12 :语音控制小车
语音模块:SU-03T
语音模块结合了语音识别和控制技术,使得我们可以通过简单的口令来轻松操控灯光等设备,实现更智能化的生活体验。
1. 语音模块介绍
1.1 型号介绍
SU-03T,是一款低成本、小体积的高性价比离线语音识别模块。
直接语音控制,无需联网,无需手机;
AI智能语音芯片,反应灵敏。
SU-03T板载一个高灵敏度咪头,一个8Ω的喇叭和四个继电器。
可以用于产品原型测试验证功能,DIY自己的语音控制设备,改装各种小家电。
支持自定义开机播报、唤醒词、命令词等。

产品特性:
- 32bit RISC内核,运行频率240M
- 支持DSP指令集以及FPU浮点运算单元
- FFT加速器:最大支持1024点复数FFT/IFFT运算,或者是2048点的实数FFT/IFFT运算
- 内置高速SRAM,内置2MB FLASH
- 支持1路驻极体麦
- 支持 I2S input/output
- 支持 5V 电源输入
- 内置 5V 转 3.3V,3.3V 外部负载不超过 150mA
- RC 12MHz 时钟源和 PLL 锁相环时钟源
- 内置 POR(Power on Reset),低电压检测和看门狗
- 所有 GPIO 均可配置为外部中断输入和唤醒源
- 1个标准 SPI Master 接口,最高速率 30MHz
- 1个 SPI Slave 接口最高速率 30MHz
- 1个全双工 UART 最高速率 3Mbps
- 1个 I2C 主/从控制器最高速率 400kHz
- 2个 PWM 输出
- 1个 12-bit SAR-ADC 最大 450Khz 采样率
1.2 工作参数及引脚介绍
工作温度:-20 ~ 85℃
工作电压:3.6V ~ 5.5V,一般5V供电
供电电流:>200mA
| SU-03T | 说明 |
|---|---|
| VCC | 5V供电 |
| GND | 接地 |
| 3V3 | 芯片内部LDO输出3.3V,外部负载不能超过150mA |
| B8 | 打印信息引脚,不用可悬空 |
| B7 | ADC13 / UART1_TXD / I2C_SCL |
| B6 | ADC12 / UART1_RXD / I2C_SDA |
| B2 | UART1_TXD / I2C_SCL / TIM3_PWM |
| MIC- | 驻极体麦负极 |
| MIC+ | 驻极体麦正极 |
| B3 | UART1_RXD / I2C_SDA / TIM4_PWM |
| A27 | ADC6 / SPIS_MOSI / SPIM_MOSI / I2S0_DO / DMIC1_CLK / TIM3_PWM |
| A26 | ADC5 / SPIS_CLK / SPIM_CLK / I2S0_BCLK / I2S1_BCLK / DMIC0_CLK |
| A25 | ADC4 / SPIS_MISO / SPIM_MISO / I2S0_LRCLK / I2S1_LRCLK / DMIC_DAT |
| B0 | UART0_TXD / I2C_SCL / TIM3_PWM |
| B1 | UART0_RXD / I2C_SDA / TIM4_PWM |
| GND | 接地 |
| SPK- | 喇叭负极 |
| SPK+ | 喇叭正极 |
注意:UART0串口B0、B1引脚是调试器的烧录口,串口烧录使用UART1(B6、B7脚)。
2. 通信示意图
实现目标:有一个三色LED灯,说【打开红灯】,红灯亮;说【关闭红灯】,红灯灭;说【打开绿灯】,绿灯亮;说【关闭绿灯】,绿灯灭;说【反转黄灯】,黄灯状态反转。
3. SU-03T 配置
网站:搜索"智能公元"
-
注册 → 登录
-
产品管理 → 所有产品 → 创建产品 → 选择SU-03T

-
前端信号处理

-
Pin脚配置
功能:GPIO A25、A26、A27,默认低电平
上电记忆:工作过程到断电之前,一直处于高电平,如果勾上上电记忆,下一次上电为高电平
-
唤醒词自定义【自己随便添加】

-
命令词自定义



这里的A25、A26、A27,是语音模块的引脚,而不是STM32的引脚
将这三个引脚接到STM32的某个引脚,
检测GPIO的状态,如果识别到A27是低电平,其他两个是高电平,即进入到循迹模式;
其他模式同理。

-
右上角的发布版本
生成一个SDK【大概10~30分钟】,下载并烧录。

-
下载固件 → jx_firm.tar.gz压缩包,这是一个镜像,将它烧录到板子上

4. 如何烧录?
烧录工具:

接线图:根据手册,交叉接线
| USB转TTL | SU-03T语音模块 |
|---|---|
| 5V | VCC |
| GND | GND |
| TXD | B6 |
| RXD | B7 |

bin文件解压出来,放到随意一个英文目录下,不要中文目录

烧录成功

1. 项目需求
语音输出,循迹模式、避障模式、跟随模式,三种模式的切换。
2. 硬件接线
| STM32 | 电机驱动 | OLED | 循迹模块 | 跟随模块 | 舵机 | 超声波 | SU-03T |
|---|---|---|---|---|---|---|---|
| PB0 | A-1A | ||||||
| PB1 | A-1B | ||||||
| PB2 | B-1A | ||||||
| PB10 | B-1B | ||||||
| PB8 | SCL | ||||||
| PB9 | SDA | ||||||
| PB13 | DO(左) | ||||||
| PB14 | DO(右) | ||||||
| PB5 | OUT(左) | ||||||
| PB6 | OUT(右) | ||||||
| PA6 | 橙线 | ||||||
| PA12 | Trig | ||||||
| PA11 | Echo | ||||||
| PA0 | A25 | ||||||
| PA1 | A26 | ||||||
| PA2 | A27 |
3. 构思环节
- 在项目1【让小车动起来】基础上做该项目,语音控制小车
- 在BSP文件夹中添加track文件夹【循迹】、follow【跟随】、【避障】sg90和hcsr04文件夹,在前面的项目中找这些文件夹,将HAL库中的定时器加载进来,常规操作,不细说
- 主函数中加入各模块的初始化函数【4个】
- 将各模块进行模式封装 main.c
c
1. 循迹模式:
void track_mode(void)
{
if(track_left_flag() == TRUE && track_right_flag() == TRUE)
motor_go_forward();
else if(track_left_flag() == FALSE && track_right_flag() == TRUE)
motor_go_left();
else if(track_left_flag() == TRUE && track_right_flag() == FALSE)
motor_go_right();
else if(track_left_flag() == FALSE && track_right_flag() == FALSE)
motor_stop();
}
2. 跟随模式:
void follow_mode(void)
{
if(follow_left_flag() == TRUE && follow_right_flag() == TRUE)
motor_go_forward();
else if(follow_left_flag() == TRUE && follow_right_flag() == FALSE)
motor_go_left();
else if(follow_left_flag() == FALSE && follow_right_flag() == TRUE)
motor_go_right();
else if(follow_left_flag() == FALSE && follow_right_flag() == FALSE)
motor_stop();
}
3. 避障模式:
void avoidance_mode(void)
{
// 先测量中间数据
dis_middle = hcsr04_get_length();
// 如果大于某个距离,就前进
if(dis_middle > 35)
motor_go_forward();
else if(dis_middle < 15)
motor_go_backward();
else
{
// 1.先停下
motor_stop();
// 2. 向左看,并测量左侧距离
sg90_turn_left();
delay_ms(500);
dis_left = hcsr04_get_length();
// 3. 居中
sg90_turn_middle();
delay_ms(500);
// 4. 向右看,并测量右边距离
sg90_turn_right();
delay_ms(500);
dis_right = hcsr04_get_length();
// 5. 根据距离判断是左转还是右转
if(dis_left < dis_right)
motor_go_right();
else
motor_go_left();
delay_ms(200);
// 停下
motor_stop();
// 居中
sg90_turn_middle();
}
delay_ms(100);
}
while(1)
{
track_mode();
follow_mode();
avoidance_mode();
}
- 通过语音控制这三种模式
BSP文件夹中创建一个voice文件夹,增加voice.c和voice.h文件
c
void voice_init(void)
{
1. 初始化3个引脚PA0、PA1、PA2
2. 输入模式
3. 无上拉
4. 高速
HAL_GPIO_Init(GPIOA, 句柄);
}
voice.h
c
// 宏定义
#define TRACK_PIN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2)
#define AVIODANCE_PIN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1)
#define FOLLOW_PIN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)
main.c
c
voice_init();
while(1)
{
语音模块有三个引脚,低电平时进入模式
if(TRACK_PIN == GPIO_PIN_RESET FOLLOW_PIN == GPIO_PIN_SET && AVIODANCE_PIN == GPIO_PIN_SET)
{
track_mode();
}
else if(TRACK_PIN == GPIO_PIN_SET && FOLLOW_PIN == GPIO_PIN_RESET && AVIODANCE_PIN == GPIO_PIN_SET)
follow_mode();
else if(TRACK_PIN == GPIO_PIN_SET && FOLLOW_PIN == GPIO_PIN_SET && AVIODANCE_PIN == GPIO_PIN_RESET)
avoidance_mode();
}
4. 实验结果
语音输出三种模式,切换到各种模式。
