基于STM32的测障测角小车设计与Proteus仿真

简介: 基于STM32的测障测角小车设计与Proteus仿真

一、系统概述与核心功能

1. 系统定位

本设计基于STM32F103C8T6核心板,结合超声波测距、SG90舵机测角与L298N直流电机驱动,构建一款具备“前方180°扇形区域障碍扫描与自动避障”功能的智能小车。通过舵机带动超声波探头左右旋转,小车能在行进中实时构建前方环境地图,计算障碍物距离与偏离角度,从而做出最优的绕行决策。结合Proteus仿真电路,可在无实物情况下验证控制逻辑与避障算法。

2. 核心功能模块

模块 功能描述
运动底盘 4WD/2WD差速驱动,支持前进、后退、原地左/右旋转
测障测角单元 SG90舵机(0°-180°旋转)搭载HC-SR04超声波,实现前方扇形区域扫描与距离测定
避障决策 基于扫描数据(距离+角度),判断左侧/右侧哪边空间更大,执行绕障逻辑
人机交互 OLED显示最近障碍距离与角度,指示灯反馈当前运行状态
仿真调试 Proteus环境下搭建虚拟电路,联合Keil进行软硬件协同仿真调试

二、硬件设计方案

1. 核心硬件选型

模块 型号 关键参数 接口方式
主控MCU STM32F103C8T6 72MHz Cortex-M3,20KB RAM,3个通用定时器(PWM输出) 核心控制器
测距传感器 HC-SR04 探测距离2cm-400cm,精度±3mm,触发信号>10μs,回响脉冲宽度对应距离 TIM2输入捕获(PA0-Echo, PA1-Trig)
角度控制 SG90舵机 转动角度0°-180°,PWM控制,工作频率50Hz(周期20ms),脉冲范围0.5ms-2.5ms TIM3_CH1(PA6)
电机驱动 L298N 双H桥,支持7-35V电机电压,逻辑电压5V,连续电流2A/路,带续流二极管保护 IN1-4(PB0-PB3),ENA/B(PA8-PA9)
直流电机 TT直流减速电机×4 额定电压6V,空载转速200rpm,减速比1:48 L298N输出端
电源模块 18650锂电池×2 7.4V/2200mAh,带充放电保护板,续航>2小时 7.4V直供电机,LM2596降压至5V/3.3V

2. 硬件电路设计要点

  • 舵机与超声波挂载:将HC-SR04牢固粘贴在SG90舵机的摇臂延长杆上,确保二者重心平衡。
  • 电机驱动接线:L298N的ENA和ENB引脚必须接到STM32的PWM引脚(如PA8/PA9),以实现精确的调速控制;IN1-IN4接到普通GPIO(PB0-PB3)控制方向。
  • 电源去耦:在L298N的12V/5V输入端并联1000μF电解电容与0.1μF瓷片电容,防止电机启停时的瞬间大电流拉低逻辑电压。
  • 共地处理:STM32逻辑地与L298N逻辑地必须可靠连接,避免电位差导致控制信号紊乱。

三、软件设计与核心算法

1. 系统架构

采用前后台系统(无操作系统),以主循环为前台逻辑调度核心,以通用定时器中断为后台精准控制源:

  1. TIM2输入捕获中断:精准捕捉超声波回响脉冲宽度,换算为距离值(Distance = Pulse_Width / 58.0 cm)。
  2. TIM3 PWM输出:产生50Hz周期、占空比可调的方波,控制舵机转角(Angle = (Duty - 5) / 10 * 180)。
  3. 主循环逻辑
    • 扫描阶段:控制舵机从0°扫到180°,每间隔15°停留并触发测距。
    • 决策阶段:分析扫描数据,找出最近障碍物的距离和角度。若距离小于安全阈值(如20cm),则判定左侧或右侧是否有通行空间。
    • 执行阶段:根据决策结果,控制电机驱动小车前进、左转绕行或右转绕行。

2. 核心代码实现(基于标准库)

2.1 舵机角度控制(TIM3 PWM)

#include "stm32f10x.h"
#include "timer.h"

// 舵机初始化(50Hz,即20ms周期)
void SG90_Init(void) {
   
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    // 1. 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // 2. 配置PA6为复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. 定时器时基配置:72MHz / (7199+1) / (199+1) = 50Hz
    TIM_TimeBaseStructure.TIM_Period = 199;       // ARR
    TIM_TimeBaseStructure.TIM_Prescaler = 7199;    // PSC
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    // 4. PWM通道配置
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 15;           // 初始占空比7.5% (1.5ms,对应90°)
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);

    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    TIM_Cmd(TIM3, ENABLE);
}

// 设置舵机角度(0-180度)
void SG90_SetAngle(uint8_t angle) {
   
    // 0度对应0.5ms (CCR=5),180度对应2.5ms (CCR=25)
    // 公式:CCR = 5 + (angle / 180.0) * 20
    uint16_t ccr_value = 5 + (angle * 20 / 180);
    TIM_SetCompare1(TIM3, ccr_value);
}

2.2 超声波测距(TIM2输入捕获)

#include "stm32f10x.h"
#include "ultrasonic.h"

volatile uint8_t is_rising = 0;       // 上升沿/下降沿标志
volatile uint32_t rising_time = 0;     // 上升沿捕获值
volatile uint32_t falling_time = 0;    // 下降沿捕获值
volatile uint8_t distance_cm = 0;     // 计算出的距离(cm)

// 超声波初始化
void HC_SR04_Init(void) {
   
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 1. 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // 2. Trig引脚(PA1)配置为推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. Echo引脚(PA0)配置为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 4. 定时器配置 (1us计数一次,72MHz/72=1MHz)
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    TIM_TimeBaseStructure.TIM_Prescaler = 71;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    // 5. 输入捕获配置
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 先捕获上升沿
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x00;
    TIM_ICInit(TIM2, &TIM_ICInitStructure);

    // 6. NVIC配置
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
}

// 发送10us以上触发脉冲
void HC_SR04_Trig(void) {
   
    GPIO_SetBits(GPIOA, GPIO_Pin_1);
    Delay_us(15);  // 延时15us
    GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

// TIM2中断服务程序
void TIM2_IRQHandler(void) {
   
    if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
   
        if (is_rising == 0) {
     // 捕获到上升沿
            rising_time = TIM_GetCapture1(TIM2);
            is_rising = 1;
            // 切换为下降沿捕获
            TIM_OC1PolarityConfig(TIM2, TIM_ICPolarity_Falling);
        } else {
     // 捕获到下降沿
            falling_time = TIM_GetCapture1(TIM2);
            is_rising = 0;

            // 计算高电平持续时间(us)
            uint32_t pulse_width;
            if (falling_time >= rising_time) {
   
                pulse_width = falling_time - rising_time;
            } else {
   
                pulse_width = (0xFFFF - rising_time + 1) + falling_time;
            }

            // 转换为厘米 (公式:距离cm = 高电平时间us / 58)
            distance_cm = pulse_width / 58;

            // 切换回上升沿捕获
            TIM_OC1PolarityConfig(TIM2, TIM_ICPolarity_Rising);
        }
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
    }
}

2.3 避障决策算法(核心逻辑)

#include "avoid_obstacle.h"

// 定义扫描数据存储结构
typedef struct {
   
    uint8_t angle;     // 舵机角度 (0-180)
    uint8_t dist;      // 该角度测得的距离 (cm)
} ScanPoint_t;

ScanPoint_t scan_map[13];  // 扫描13个点 (0°, 15°, 30°... 180°)

// 前方扇形扫描函数
void Radar_Scan(void) {
   
    uint8_t idx = 0;
    for (uint8_t angle = 0; angle <= 180; angle += 15) {
   
        SG90_SetAngle(angle);
        Delay_ms(200);  // 等待舵机转动到位

        HC_SR04_Trig();
        Delay_ms(50);   // 等待超声波测量完成

        scan_map[idx].angle = angle;
        scan_map[idx].dist = distance_cm;
        idx++;
    }
}

// 避障决策函数
// 返回值:0=前进,1=左转,2=右转,3=后退
uint8_t Avoid_Obstacle_Decision(void) {
   
    uint8_t min_dist = 255;
    uint8_t min_angle = 90; // 默认指向正前方

    // 1. 寻找最近障碍物
    for (uint8_t i = 0; i < 13; i++) {
   
        if (scan_map[i].dist < min_dist) {
   
            min_dist = scan_map[i].dist;
            min_angle = scan_map[i].angle;
        }
    }

    // 2. 判断是否需要避障(安全距离20cm)
    if (min_dist > 20) {
   
        return 0;  // 安全,继续前进
    }

    // 3. 判断障碍物出现在左侧还是右侧
    if (min_angle < 90) {
     // 障碍物在左侧,向右转绕行
        return 2;
    } else {
                  // 障碍物在右侧或正前方,向左转绕行
        return 1;
    }
}

四、Proteus仿真电路设计

在没有实物的情况下,可以利用Proteus强大的仿真功能来验证上述代码。

1. 仿真环境搭建

  • 主控MCU:在Proteus库中搜索 STM32F103C8(若找不到,可用 STM32F103RBSTM32F103C6 代替,引脚差异需微调)。
  • 电机驱动:搜索 L298(注意不是L298N,Proteus里通常只画出芯片内部逻辑),将其输入输出引脚连接好。
  • 直流电机:搜索 MOTOR-DC,连接在L298的输出端。
  • 舵机与超声波:Proteus中没有现成的HC-SR04和SG90模型。为了仿真,我们可以:
    1. 逻辑替代:用几个滑动变阻器(Potentiometer)模拟距离输入,连接到ADC引脚。
    2. 物理替代:用 DC MOTOR 模拟舵机转动(虽然不准确,但能看到角度变化的趋势)。
    3. 手动模拟:在仿真运行时,手动点击Proteus里的按钮,模拟舵机到位和超声波回响信号。

2. 仿真调试技巧

  • 联合调试:在Keil中编译生成 .hex 文件,加载到Proteus的STM32芯片属性中。
  • 虚拟终端(Virtual Terminal):在Proteus中添加虚拟串口,连接到STM32的USART1引脚(PA9/PA10),可以在电脑上看到小车实时发送的扫描数据和决策结果。
  • 激励源:若想模拟超声波回响脉冲,可以使用 PULSE GENERATOR(脉冲发生器),设置一个宽度随距离变化的脉冲,连接到PA0(Echo引脚)。

参考代码 测障测角小车+仿真电路 www.youwenfan.com/contentali/124102.html

五、系统调试与扩展

1. 实物调试步骤

阶段 操作 工具
舵机调试 测试0°、90°、180°是否精准到位,有无抖动 肉眼观察、量角器
测距调试 放置障碍物在不同距离,对比测量值与真实值 卷尺、串口打印
扫描调试 观察舵机转动是否流畅,扫描点是否覆盖前方180° 肉眼观察、OLED显示
避障调试 在轨道放置障碍物,观察小车是否能顺利绕行 实际场地测试

2. 扩展功能

  • PID速度闭环:添加编码器,实现小车定速行驶,避免电池电压下降导致速度变化。
  • 视觉避障:将超声波升级为OpenMV摄像头,实现颜色识别和更复杂的道路循迹。
  • 手机遥控:添加HC-05蓝牙模块,通过手机APP实时查看雷达扫描图并遥控小车。

六、总结

基于STM32的测障测角小车是嵌入式系统入门与进阶的经典实战项目。通过SG90舵机与HC-SR04超声波的巧妙结合,打破了单一固定探头的视野局限,实现了前方180°的雷达式扫描。配合L298N电机驱动与精心设计的避障算法,小车能够智能应对复杂路况。利用Proteus仿真与Keil联合调试,开发者可以在硬件成型前完美验证逻辑漏洞,极大地提高了开发效率。

相关文章
|
8天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
2970 7
|
10天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3071 20
|
23天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23567 15
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
|
4天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
1956 3
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
10天前
|
人工智能 JSON BI
DeepSeek V4-Pro 接入 Claude Code 完全实战:体验、测试与关键避坑指南
Claude Code 作为当前主流的 AI 编程辅助工具,凭借强大的代码理解、工程执行与自动化能力深受开发者喜爱,但原生模型的使用成本相对较高。为了在保持能力的同时进一步降低开销,不少开发者开始寻找兼容度高、价格更友好的替代模型。DeepSeek V4 系列的发布带来了新的选择,该系列包含 V4-Pro 与 V4-Flash 两款模型,并提供了与 Anthropic 完全兼容的 API 接口,理论上只需简单修改配置,即可让 Claude Code 无缝切换为 DeepSeek 引擎。
2464 3
|
8天前
|
人工智能 安全 开发工具
Claude Code 官方工作原理与使用指南
Claude Code 不是传统代码补全工具,而是 Anthropic 推出的终端 AI 代理,具备代理循环、双驱动架构(模型+工具)、全局项目感知、6 种权限模式等核心能力,本文基于官方文档系统解析其工作原理与高效使用技巧。
1342 0
|
8天前
|
存储 Linux iOS开发
【2026最新】MarkText中文版Markdown编辑器使用图解(附安装包)
MarkText是一款免费开源、跨平台的Markdown编辑器,主打所见即所得实时预览,支持Windows/macOS/Linux。内置数学公式、流程图、代码高亮、多主题及PDF/HTML导出,是Typora的轻量免费替代首选。(239字)