基于 STM32F103C8 的超声波循迹送药机器人 Proteus 仿真
基于 STM32F103C8 的超声波循迹送药机器人 Proteus 仿真
前言
本设计以 STM32F103C8 为控制核心,完成四轮送药机器人的循迹行驶、超声波避障、货物状态检测、RFID 状态检测和 OLED 信息显示。
系统使用两组 L298 驱动四个直流电机。PB0、PB1 接收两路循迹信号,HC-SR04 检测机器人前方距离,PA1 采集压力传感器模拟电压,PB5接收 RFID 状态信号。OLED 实时显示距离、RFID、行驶方向和货物状态。
本设计使用 Keil MDK 编写 STM32 标准外设库程序,使用 Proteus 完成电路搭建和功能仿真。
完整工程资料免费获取
点赞 + 收藏本文,并在评论区留言“超声波送药机器人”,即可免费获取完整工程网盘链接。
工程资料包含:Keil 源码、Proteus 仿真文件、可直接加载的 HEX 文件和项目演示视频。
闲鱼店铺:大嘴花电子
专注单片机仿真与实物定制,支持 STM32、51 单片机、Arduino、Proteus 仿真等。
有需要仿真文件、代码程序、实物制作的朋友都可以咨询。
价格优惠,沟通好需求后定制方案,谢谢支持!
一、系统运行效果

图 1 系统运行总图
图 1 中的系统处于正常直行状态,运行数据如下:
| 检测项目 | 当前数据 |
|---|---|
| HC-SR04 距离 | 111 cm |
| RFID 状态 | yes |
| 行驶状态 | straight |
| 货物状态 | NO |
| PA1 输入电压 | 0.725993 V |
PA1 电压低于程序设定的 2.0 V 阈值,因此 OLED 显示 cargo:NO。HC-SR04 测得距离为 111 cm,高于 100 cm 避障阈值,机器人按照 PB0、PB1 的输入状态执行直行。
二、系统功能
本设计实现以下功能:
- HC-SR04 实时测量机器人前方距离;
- 前方距离小于 100 cm 时停止四个电机;
- PB0、PB1 控制直行、左转、右转和停止;
- PA1 采集压力传感器模拟电压;
- PA1 电压高于 2.0 V 时判定有货;
- PB10 输出货物检测结果;
- PB5 接收 RFID 识别状态;
- OLED 显示距离、RFID、行驶状态和货物状态;
- 两组 L298 分别驱动左侧和右侧四个电机。
系统控制顺序为:
读取超声波距离
↓
读取压力传感器电压
↓
读取 PB0、PB1 循迹信号
↓
读取 PB5 RFID 状态
↓
执行避障或循迹控制
↓
刷新 OLED 显示
避障控制优先于循迹控制。距离小于 100 cm 时,程序直接调用 Car_Stop(),PB0、PB1 的状态不再控制电机。
三、硬件组成
| 模块 | 数量 | 功能 |
|---|---|---|
| STM32F103C8 | 1 | 系统控制核心 |
| HC-SR04 | 1 | 超声波距离检测 |
| 0.96 英寸 OLED | 1 | 系统数据显示 |
| L298 | 2 | 四路电机方向控制 |
| 直流电机 | 4 | 左前、左后、右前、右后车轮 |
| 压力传感器模拟输入 | 1 | 货物状态检测 |
| RFID 状态开关 | 1 | RFID 识别结果输入 |
| 循迹状态开关 | 2 | 左右循迹信号输入 |
| LED | 1 | PB10 货物状态输出指示 |
| 复位电路 | 1 | STM32 手动复位 |
| 晶振电路 | 1 | STM32 外部时钟 |
四、STM32 最小系统与压力检测

图 2 STM32 最小系统与压力检测电路
STM32F103C8 最小系统由主控芯片、复位电路、外部晶振和电源连接组成。
4.1 复位电路
NRST 引脚通过 10 kΩ 电阻连接高电平,按键按下后将 NRST 拉低,完成系统复位。电容 C3 用于上电复位。
4.2 外部晶振
外部晶振 X1 连接 PD0 和 PD1,两端分别连接 22 pF 电容。系统程序按照 72 MHz 主频配置 SysTick 和 TIM2。
4.3 压力传感器输入
RV1 模拟压力传感器输出,滑动端连接 PA1。PA1 对应 ADC1 通道 1。
ADC 为 12 位转换,参考电压为 3.3 V。2.0 V 对应的 ADC 阈值为:
2.0 ÷ 3.3 × 4095 = 2481.8
程序使用整数阈值 2482:
#define ADC_THRESHOLD_2V (2482U)
货物状态判断代码如下:
u8 ADC_CargoOut_UpdateByPA1_2V(void)
{
u16 adc = ADC_ReadAverage(ADC_Channel_1, 10);
if (adc > ADC_THRESHOLD_2V)
{
GPIO_SetBits(GPIOB, GPIO_Pin_10);
return 1;
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_10);
return 0;
}
}
程序连续采样 10 次并计算平均值。ADC 值大于 2482 时,PB10 输出高电平,OLED 显示 cargo:YES;ADC 值不大于 2482 时,PB10 输出低电平,OLED 显示 cargo:NO。
图 1 中 PA1 电压为 0.725993 V,货物检测结果为 cargo:NO。
五、四轮电机驱动电路

图 3 两组 L298 与四个直流电机
系统使用两组 L298 控制四个直流电机。
5.1 左侧电机
| 电机 | L298 输入 | STM32 引脚 |
|---|---|---|
| 左前轮 | IN1、IN2 | PA2、PA3 |
| 左后轮 | IN3、IN4 | PA4、PA5 |
5.2 右侧电机
| 电机 | L298 输入 | STM32 引脚 |
|---|---|---|
| 右前轮 | IN1、IN2 | PA8、PA9 |
| 右后轮 | IN3、IN4 | PA10、PB6 |
L298 的 ENA、ENB 接高电平,四个电机由输入端控制前进和停止。
单个电机的控制关系如下:
| IN-A | IN-B | 电机状态 |
|---|---|---|
| 0 | 0 | 停止 |
| 1 | 0 | 前进 |
电机底层控制函数如下:
static inline void Motor_Stop_2IN(GPIO_TypeDef *port,
uint16_t inA,
uint16_t inB)
{
GPIO_ResetBits(port, inA);
GPIO_ResetBits(port, inB);
}
static inline void Motor_Fwd_2IN(GPIO_TypeDef *port,
uint16_t inA,
uint16_t inB)
{
GPIO_SetBits(port, inA);
GPIO_ResetBits(port, inB);
}
整车动作表如下:
| 行驶动作 | 左侧电机 | 右侧电机 |
|---|---|---|
| 停止 | 停止 | 停止 |
| 直行 | 前进 | 前进 |
| 左转 | 停止 | 前进 |
| 右转 | 前进 | 停止 |
对应程序如下:
void Car_Stop(void)
{
LF_Stop();
LR_Stop();
RF_Stop();
RR_Stop();
}
void Car_Straight(void)
{
LF_Fwd();
LR_Fwd();
RF_Fwd();
RR_Fwd();
}
void Car_Left(void)
{
LF_Stop();
LR_Stop();
RF_Fwd();
RR_Fwd();
}
void Car_Right(void)
{
RF_Stop();
RR_Stop();
LF_Fwd();
LR_Fwd();
}
六、HC-SR04 超声波测距

图 4 HC-SR04 超声波模块
HC-SR04 与 STM32 的连接如下:
| HC-SR04 引脚 | STM32 引脚 |
|---|---|
| Trig | PA6 |
| Echo | PA7 |
| VCC | 电源 |
| GND | 地 |
PA6 输出 10 μs 触发脉冲:
static void Trig_10us(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
Delay_us(2);
GPIO_SetBits(GPIOA, GPIO_Pin_6);
Delay_us(10);
GPIO_ResetBits(GPIOA, GPIO_Pin_6);
}
TIM2 的计数频率设置为 1 MHz,一个计数周期为 1 μs:
tim.TIM_Prescaler = 72 - 1;
tim.TIM_Period = 0xFFFF;
TIM_TimeBaseInit(TIM2, &tim);
程序记录 Echo 上升沿和下降沿对应的 TIM2 计数值,得到 Echo 高电平持续时间。距离计算代码为:
return (uint16_t)(pulse_us / 58);
测距函数在等待 Echo 上升沿和下降沿时分别设置 30000 次超时计数。超时后返回 0。
图 4 中 HC-SR04 仿真距离为 110.0 cm,OLED 显示整数距离 0111。
七、OLED、RFID 与运行信息

图 5 RFID、OLED 与 HC-SR04 运行状态
OLED 使用软件 I2C 驱动:
| OLED 引脚 | STM32 引脚 |
|---|---|
| SCL | PB8 |
| SDA | PB9 |
| VCC | 电源 |
| GND | 地 |
OLED 显示四行数据:
| 显示行 | 内容 |
|---|---|
| 第 1 行 | HC-SR04 距离 |
| 第 2 行 | RFID 状态 |
| 第 3 行 | 行驶状态 |
| 第 4 行 | 货物状态 |

图 6 OLED 运行数据显示
图 6 显示内容为:
HC-SR04:0111
RFID:yes
straight
cargo: NO
PB5 配置为下拉输入。PB5 为高电平时显示 RFID:yes,PB5 为低电平时显示 RFID:wait。
RFID 状态读取函数如下:
uint8_t IO_ReadPB5(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) ? 1 : 0;
}
八、红外循迹输入

图 7 PB0、PB1 循迹输入
PB0、PB1 配置为上拉输入,两个开关模拟左右红外循迹模块的数字输出。
循迹控制表如下:
| PB0 | PB1 | 行驶状态 | OLED 显示 |
|---|---|---|---|
| 1 | 1 | 直行 | straight |
| 1 | 0 | 左转 | left |
| 0 | 1 | 右转 | right |
| 0 | 0 | 停止 | stop |
控制程序如下:
if (b0 == 1 && b1 == 1)
{
Car_Straight();
OLED_ShowStateLine(s_straight);
}
else if (b0 == 1 && b1 == 0)
{
Car_Left();
OLED_ShowStateLine(s_left);
}
else if (b0 == 0 && b1 == 1)
{
Car_Right();
OLED_ShowStateLine(s_right);
}
else
{
Car_Stop();
OLED_ShowStateLine(s_stop);
}
图 1 中 PB0、PB1 均为高电平,四个电机同时前进,OLED 显示 straight。
九、主程序控制逻辑
系统初始化代码如下:
OLED_Init();
OLED_Clear();
OLED_Update();
Motor_Init();
IO_Init();
HCSR04_TIM_Init();
ADC_InitPA1();
ADC_CargoOut_InitPB10();
主循环依次读取距离、货物状态、循迹状态和 RFID 状态:
while (1)
{
uint16_t dist = HCSR04_TIM_GetDistanceCM();
uint8_t hasCargo = ADC_CargoOut_UpdateByPA1_2V();
uint8_t b0 = IO_ReadB0();
uint8_t b1 = IO_ReadB1();
uint8_t rfid = IO_ReadPB5();
OLED_Clear();
OLED_ShowDistanceLine(dist);
if (dist != 0 && dist < 100)
{
Car_Stop();
OLED_ShowStateLine(s_obst);
}
else
{
if (b0 == 1 && b1 == 1)
{
Car_Straight();
OLED_ShowStateLine(s_straight);
}
else if (b0 == 1 && b1 == 0)
{
Car_Left();
OLED_ShowStateLine(s_left);
}
else if (b0 == 0 && b1 == 1)
{
Car_Right();
OLED_ShowStateLine(s_right);
}
else
{
Car_Stop();
OLED_ShowStateLine(s_stop);
}
}
OLED_ShowCargoLine(hasCargo);
if (rfid)
OLED_ShowString(0, 16, s_rfid_yes, OLED_8X16);
else
OLED_ShowString(0, 16, s_rfid_wait, OLED_8X16);
OLED_Update();
Delay_ms(100);
}
距离有效且小于 100 cm 时,OLED 显示 obstacle,四个电机停止。距离为 0 或不小于 100 cm 时,程序执行 PB0、PB1 对应的循迹动作。
十、工程目录
代码
├─ Hardware
│ ├─ adc.c
│ ├─ adc.h
│ ├─ HCSR04.c
│ ├─ HCSR04.h
│ ├─ IO.c
│ ├─ IO.h
│ ├─ Motor.c
│ ├─ Motor.h
│ ├─ OLED.c
│ ├─ OLED.h
│ ├─ OELD_Data.c
│ └─ OELD_Data.h
├─ System
│ ├─ Delay.c
│ ├─ Delay.h
│ └─ sys
├─ Start
├─ library
├─ user
│ ├─ main.c
│ ├─ stm32f10x_conf.h
│ ├─ stm32f10x_it.c
│ └─ stm32f10x_it.h
├─ Objects
│ └─ project.hex
└─ project.uvprojx
各模块职责如下:
| 文件 | 职责 |
|---|---|
main.c |
系统初始化和主循环控制 |
HCSR04.c |
超声波触发、计时和距离计算 |
Motor.c |
四轮电机初始化和动作控制 |
IO.c |
PB0、PB1、PB5 输入读取 |
adc.c |
PA1 ADC 采集和货物状态输出 |
OLED.c |
OLED 软件 I2C 驱动和数据显示 |
Delay.c |
SysTick 微秒、毫秒和秒级延时 |
十一、Keil 编译与 Proteus 运行
11.1 Keil 编译
- 打开
代码/project.uvprojx; - 选择
Target 1; - 执行 Build;
- 编译完成后生成
代码/Objects/project.hex。
工程编译结果为:
Program Size: Code=4684 RO-data=2880 RW-data=0 ZI-data=2048
0 Error(s), 0 Warning(s)
【图片插入位置:Keil Build Output 编译成功截图,画面保留
0 Error(s), 0 Warning(s)】
11.2 Proteus 运行
- 打开
仿真/新工程 [Autosaved].pdsprj; - 双击 STM32F103C8;
- Program File 选择
代码/Objects/project.hex; - 启动仿真;
- 调节 RV1 改变 PA1 输入电压;
- 调节 HC-SR04 距离值;
- 切换 PB0、PB1 检查四种行驶状态;
- 切换 PB5 检查 RFID 显示状态。
【图片插入位置:Proteus 中 STM32F103C8 的 Program File 配置截图】
十二、运行结果
本次仿真运行状态如下:
- HC-SR04 距离设定为 110.0 cm;
- OLED 显示距离
0111; - PB5 为高电平,OLED 显示
RFID:yes; - PB0、PB1 均为高电平,OLED 显示
straight; - 四个电机执行前进;
- PA1 电压为 0.725993 V;
- PA1 电压低于 2.0 V 阈值,OLED 显示
cargo:NO; - PB10 输出低电平,LED 熄灭。
系统运行结果与程序控制逻辑一致。
十三、总结
本设计完成了基于 STM32F103C8 的超声波循迹送药机器人 Proteus 仿真。
系统通过 HC-SR04 完成距离检测,通过 PB0、PB1 完成循迹动作选择,通过 PA1 ADC 完成货物状态检测,通过 PB5 完成 RFID 状态输入,通过两组 L298 完成四轮电机控制,并通过 OLED 集中显示系统运行数据。
项目完整使用了 STM32 GPIO、ADC、通用定时器、SysTick 延时和软件 I2C,形成了传感器采集、控制决策、电机执行和状态显示的完整控制流程。
更多推荐



所有评论(0)