STM32智能小车
本文介绍了基于STM32的四轮智能小车控制系统,包含PWM模块、电机驱动、超声波测距、红外循迹和蓝牙遥控五大功能模块。
1.Delay
了解就可以,直接复制粘贴到项目中。
Delay.h
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
Delay.c
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
2.PWM模块
2.1 什么是PWM?
PWM(Pulse Width Modulation,脉冲宽度调制)是一种通过调节脉冲的占空比来控制模拟信号的技术。在嵌入式系统中,PWM广泛应用于电机控制、LED调光、电源管理等场景。
2.2 PWM基本原理
周期:一个完整PWM波形的时间长度
占空比:高电平时间占整个周期的比例
频率:周期的倒数,决定PWM信号的刷新速度
2.3 STM32 PWM配置步骤
1. 时钟使能
2. GPIO配置
3. 时基单元配置
4. 输出比较配置
5. 使能定时器
2.4 参数计算
2.4.1PWM频率计算
定时器时钟 = 72MHz / (预分频器 + 1)
PWM频率 = 定时器时钟 / (自动重装载值 + 1)
示例配置:
系统时钟:72MHz
预分频器:71
自动重装载值:999
PWM频率 = 72MHz / 72 / 1000 = 1kHz
2.4.2占空比控制
基本概念
占空比(Duty Cycle) = 高电平时间 / 总周期时间 × 100%
关键寄存器
ARR(Auto-Reload Register):自动重装载值,决定PWM周期
CCRx(Capture/Compare Register):比较值,决定高电平时间
计算公式:
占空比 = (CCRx + 1) / (ARR + 1) × 100%
2.5代码实现
pwm.h
#pragma once
void Pwm_Init(void);
pwm.c
#include "stm32f10x.h"
#include "Delay.h"
void Pwm_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
//定时器2 前轮
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 1000 - 1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCIdleState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_Pulse = 0; //CCR
TIM_OC2Init(TIM2, &TIM_OCInitStruct);//左前轮
TIM_OC3Init(TIM2, &TIM_OCInitStruct);//右前轮
TIM_Cmd(TIM2, ENABLE);
//定时器3 后轮
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 1000 - 1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCIdleState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_Pulse = 0; //CCR
TIM_OC3Init(TIM3, &TIM_OCInitStruct);//后前轮
TIM_OC4Init(TIM3, &TIM_OCInitStruct);//后前轮
TIM_Cmd(TIM3, ENABLE);
}
3.电机模块
3.1 模块概述
这是一个基于STM32的完整四轮小车电机驱动模块,支持PWM速度控制和方向控制,实现了多种运动模式。
3.2 L298N电机驱动模块
3.2.1 L298N电机驱动模块的引脚
ENA IN1
IN2 IN3
IN4 ENB
OUT1 OUT2
OUT3 OUT4
VS GND
5V GND
3.2.2 模块基本信息
芯片型号:L298N
驱动能力:双H桥直流电机/步进电机驱动器
最大电压:46V
最大电流:2A(每桥)
逻辑电压:5V
3.2.3 引脚功能表格
电源引脚
| 引脚名称 | 引脚类型 | 功能说明 | 连接方法 | 注意事项 |
|---|---|---|---|---|
| VCC | 电源输入 | 逻辑电源 | 接MCU的5V | 为内部逻辑电路供电 |
| GND | 地线 | 电源地 | 接MCU和电源地 | 共地很重要 |
| VS | 电源输入 | 电机驱动电源 | 接外部电源(5-35V) | 根据电机电压选择 |
| 5V输出 | 电源输出 | 5V输出 | 可为MCU供电 | 使能跳线帽时输出5V |
电机控制通道A
| 引脚名称 | 引脚类型 | 功能说明 | 控制逻辑 | 电机状态 |
|---|---|---|---|---|
| ENA | 使能输入 | 电机A使能 | PWM信号 | 速度控制 |
| IN1 | 数字输入 | 电机A方向1 | 0/1信号 | 方向控制 |
| IN2 | 数字输入 | 电机A方向2 | 0/1信号 | 方向控制 |
| OUT1 | 电机输出 | 电机A输出1 | - | 接电机线1 |
| OUT2 | 电机输出 | 电机A输出2 | - | 接电机线2 |
电机控制通道B
| 引脚名称 | 引脚类型 | 功能说明 | 控制逻辑 | 电机状态 |
|---|---|---|---|---|
| ENB | 使能输入 | 电机B使能 | PWM信号 | 速度控制 |
| IN3 | 数字输入 | 电机B方向1 | 0/1信号 | 方向控制 |
| IN4 | 数字输入 | 电机B方向2 | 0/1信号 | 方向控制 |
| OUT3 | 电机输出 | 电机B输出1 | - | 接电机线1 |
| OUT4 | 电机输出 | 电机B输出2 | - | 接电机线2 |
3.2.4 控制逻辑真值表
电机A控制逻辑
| ENA | IN1 | IN2 | 电机A状态 | 说明 |
|---|---|---|---|---|
| 0 | X | X | 停止 | 使能关闭 |
| PWM | 1 | 0 | 正转 | 速度由PWM控制 |
| PWM | 0 | 1 | 反转 | 速度由PWM控制 |
| PWM | 1 | 1 | 刹车 | 快速停止 |
| PWM | 0 | 0 | 滑行停止 | 惯性停止 |
电机B控制逻辑
| ENB | IN3 | IN4 | 电机B状态 | 说明 |
|---|---|---|---|---|
| 0 | X | X | 停止 | 使能关闭 |
| PWM | 1 | 0 | 正转 | 速度由PWM控制 |
| PWM | 0 | 1 | 反转 | 速度由PWM控制 |
| PWM | 1 | 1 | 刹车 | 快速停止 |
| PWM | 0 | 0 | 滑行停止 | 惯性停止 |
3.3 硬件架构
电机控制接口
PWM速度控制:使用TIM2和TIM3产生PWM信号
方向控制:8个GPIO引脚控制电机正反转
四轮独立控制:每个轮子都有独立的速度和方向控制
3.4 引脚分配
// 前轮电机 - TIM2
左前轮:PWM(PA1-通道2), 方向(PA3, PA4)
右前轮:PWM(PA2-通道3), 方向(PA5, PA6)
// 后轮电机 - TIM3
左后轮:PWM(PB0-通道3), 方向(PB3, PB4)
右后轮:PWM(PB1-通道4), 方向(PB5, PB6)
3.5代码实现
motor.h
#pragma once
// 电机类型定义
typedef enum {
MOTOR_LEFT_FRONT = 0, // 左前轮
MOTOR_RIGHT_FRONT, // 右前轮
MOTOR_LEFT_REAR, // 左后轮
MOTOR_RIGHT_REAR // 右后轮
} Motor_Type;
// 电机方向定义
typedef enum {
MOTOR_FORWARD = 0, // 前进
MOTOR_BACKWARD // 后退
} Motor_Direction;
// 电机速度结构体
typedef struct {
uint16_t left_front;
uint16_t right_front;
uint16_t left_rear;
uint16_t right_rear;
} Motor_Speed_t;
// 速度档位定义
#define SPEED_LOW 300
#define SPEED_MEDIUM 600
#define SPEED_HIGH 900
#define SPEED_FULL 1000
// 全局变量声明
extern Motor_Speed_t g_motor_speed;
// 函数声明
void Motor_Init(void);
void Motor_SetSpeed(Motor_Type motor, uint16_t speed);
void Motor_SetAllSpeeds(uint16_t left_speed, uint16_t right_speed);
void Motor_SetDirection(Motor_Type motor, Motor_Direction direction);
void Motor_Forward(uint16_t speed);
void Motor_Backward(uint16_t speed);
void Motor_TurnLeft(uint16_t speed);
void Motor_TurnRight(uint16_t speed);
void Motor_SpinLeft(uint16_t speed);
void Motor_SpinRight(uint16_t speed);
void Motor_MoveOmni(Motor_Direction front_left, Motor_Direction front_right,
Motor_Direction rear_left, Motor_Direction rear_right,
uint16_t speed);
void Motor_StopAll(void);
Motor_Speed_t Motor_GetSpeeds(void);
motor.c
#include "stm32f10x.h"
#include "Delay.h"
#include "pwm.h"
#include "motor.h"
// 电机速度结构体
Motor_Speed_t g_motor_speed = {0, 0, 0, 0};
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_Init(GPIOB, &GPIO_InitStruct);
Pwm_Init();
Motor_StopAll();
}
/**
* @brief 设置单个电机速度
* @param motor: 电机选择
* @param speed: 速度值 0-1000
* @retval 无
*/
void Motor_SetSpeed(Motor_Type motor, uint16_t speed)
{
if(speed > 1000) speed = 1000;
switch(motor)
{
case MOTOR_LEFT_FRONT:
TIM_SetCompare2(TIM2, speed);
g_motor_speed.left_front = speed;
break;
case MOTOR_RIGHT_FRONT:
TIM_SetCompare3(TIM2, speed);
g_motor_speed.right_front = speed;
break;
case MOTOR_LEFT_REAR:
TIM_SetCompare3(TIM3, speed);
g_motor_speed.left_rear = speed;
break;
case MOTOR_RIGHT_REAR:
TIM_SetCompare4(TIM3, speed);
g_motor_speed.right_rear = speed;
break;
}
}
/**
* @brief 设置所有电机速度
* @param left_speed: 左侧电机速度
* @param right_speed: 右侧电机速度
* @retval 无
*/
void Motor_SetAllSpeeds(uint16_t left_speed, uint16_t right_speed)
{
Motor_SetSpeed(MOTOR_LEFT_FRONT, left_speed);
Motor_SetSpeed(MOTOR_LEFT_REAR, left_speed);
Motor_SetSpeed(MOTOR_RIGHT_FRONT, right_speed);
Motor_SetSpeed(MOTOR_RIGHT_REAR, right_speed);
}
/**
* @brief 设置单个电机方向
* @param motor: 电机选择
* @param direction: 方向 (MOTOR_FORWARD / MOTOR_BACKWARD)
* @retval 无
*/
void Motor_SetDirection(Motor_Type motor, Motor_Direction direction)
{
switch(motor)
{
case MOTOR_LEFT_FRONT:
if(direction == MOTOR_FORWARD) {
GPIO_SetBits(GPIOA, GPIO_Pin_3); // IN1=1
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // IN2=0
} else {
GPIO_ResetBits(GPIOA, GPIO_Pin_3); // IN1=0
GPIO_SetBits(GPIOA, GPIO_Pin_4); // IN2=1
}
break;
case MOTOR_RIGHT_FRONT:
if(direction == MOTOR_FORWARD) {
GPIO_SetBits(GPIOA, GPIO_Pin_5); // IN3=1
GPIO_ResetBits(GPIOA, GPIO_Pin_6); // IN4=0
} else {
GPIO_ResetBits(GPIOA, GPIO_Pin_5); // IN3=0
GPIO_SetBits(GPIOA, GPIO_Pin_6); // IN4=1
}
break;
case MOTOR_LEFT_REAR:
if(direction == MOTOR_FORWARD) {
GPIO_SetBits(GPIOB, GPIO_Pin_3); // IN5=1
GPIO_ResetBits(GPIOB, GPIO_Pin_4); // IN6=0
} else {
GPIO_ResetBits(GPIOB, GPIO_Pin_3); // IN5=0
GPIO_SetBits(GPIOB, GPIO_Pin_4); // IN6=1
}
break;
case MOTOR_RIGHT_REAR:
if(direction == MOTOR_FORWARD) {
GPIO_SetBits(GPIOB, GPIO_Pin_5); // IN7=1
GPIO_ResetBits(GPIOB, GPIO_Pin_6); // IN8=0
} else {
GPIO_ResetBits(GPIOB, GPIO_Pin_5); // IN7=0
GPIO_SetBits(GPIOB, GPIO_Pin_6); // IN8=1
}
break;
}
}
/**
* @brief 小车前进
* @param speed: 前进速度
* @retval 无
*/
void Motor_Forward(uint16_t speed)
{
// 所有电机向前
Motor_SetDirection(MOTOR_LEFT_FRONT, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_RIGHT_FRONT, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_LEFT_REAR, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_RIGHT_REAR, MOTOR_FORWARD);
Motor_SetAllSpeeds(speed, speed);
}
/**
* @brief 小车后退
* @param speed: 后退速度
* @retval 无
*/
void Motor_Backward(uint16_t speed)
{
// 所有电机向后
Motor_SetDirection(MOTOR_LEFT_FRONT, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_RIGHT_FRONT, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_LEFT_REAR, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_RIGHT_REAR, MOTOR_BACKWARD);
Motor_SetAllSpeeds(speed, speed);
}
/**
* @brief 小车左转(差速转弯)
* @param speed: 转弯速度
* @retval 无
*/
void Motor_TurnLeft(uint16_t speed)
{
// 左侧电机向后,右侧电机向前
Motor_SetDirection(MOTOR_LEFT_FRONT, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_LEFT_REAR, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_RIGHT_FRONT, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_RIGHT_REAR, MOTOR_FORWARD);
// 差速控制:内侧轮速度稍慢
Motor_SetSpeed(MOTOR_LEFT_FRONT, speed * 0.7);
Motor_SetSpeed(MOTOR_LEFT_REAR, speed * 0.7);
Motor_SetSpeed(MOTOR_RIGHT_FRONT, speed);
Motor_SetSpeed(MOTOR_RIGHT_REAR, speed);
}
/**
* @brief 小车右转(差速转弯)
* @param speed: 转弯速度
* @retval 无
*/
void Motor_TurnRight(uint16_t speed)
{
// 左侧电机向前,右侧电机向后
Motor_SetDirection(MOTOR_LEFT_FRONT, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_LEFT_REAR, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_RIGHT_FRONT, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_RIGHT_REAR, MOTOR_BACKWARD);
// 差速控制:内侧轮速度稍慢
Motor_SetSpeed(MOTOR_LEFT_FRONT, speed);
Motor_SetSpeed(MOTOR_LEFT_REAR, speed);
Motor_SetSpeed(MOTOR_RIGHT_FRONT, speed * 0.7);
Motor_SetSpeed(MOTOR_RIGHT_REAR, speed * 0.7);
}
/**
* @brief 小车原地左转
* @param speed: 旋转速度
* @retval 无
*/
void Motor_SpinLeft(uint16_t speed)
{
// 左侧向后,右侧向前 - 实现原地旋转
Motor_SetDirection(MOTOR_LEFT_FRONT, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_LEFT_REAR, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_RIGHT_FRONT, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_RIGHT_REAR, MOTOR_FORWARD);
Motor_SetAllSpeeds(speed, speed);
}
/**
* @brief 小车原地右转
* @param speed: 旋转速度
* @retval 无
*/
void Motor_SpinRight(uint16_t speed)
{
// 左侧向前,右侧向后 - 实现原地旋转
Motor_SetDirection(MOTOR_LEFT_FRONT, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_LEFT_REAR, MOTOR_FORWARD);
Motor_SetDirection(MOTOR_RIGHT_FRONT, MOTOR_BACKWARD);
Motor_SetDirection(MOTOR_RIGHT_REAR, MOTOR_BACKWARD);
Motor_SetAllSpeeds(speed, speed);
}
/**
* @brief 小车斜向移动(四轮独立控制)
* @param front_left: 左前轮速度方向
* @param front_right: 右前轮速度方向
* @param rear_left: 左后轮速度方向
* @param rear_right: 右后轮速度方向
* @param speed: 移动速度
* @retval 无
*/
void Motor_MoveOmni(Motor_Direction front_left, Motor_Direction front_right,
Motor_Direction rear_left, Motor_Direction rear_right,
uint16_t speed)
{
Motor_SetDirection(MOTOR_LEFT_FRONT, front_left);
Motor_SetDirection(MOTOR_RIGHT_FRONT, front_right);
Motor_SetDirection(MOTOR_LEFT_REAR, rear_left);
Motor_SetDirection(MOTOR_RIGHT_REAR, rear_right);
Motor_SetAllSpeeds(speed, speed);
}
/**
* @brief 停止所有电机
* @param 无
* @retval 无
*/
void Motor_StopAll(void)
{
// 关闭所有方向控制
GPIO_ResetBits(GPIOA, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);
GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);
// 关闭所有PWM输出
Motor_SetAllSpeeds(0, 0);
}
/**
* @brief 获取电机速度信息
* @param 无
* @retval 电机速度结构体
*/
Motor_Speed_t Motor_GetSpeeds(void)
{
return g_motor_speed;
}
电机模块详解:
设计思路:
-
四轮独立PWM控制,实现精确差速
-
结构体保存电机状态,便于监控
-
模块化函数设计,支持复杂运动模式
4. 超声波测距模块
4.1 模块概述
这是一个基于STM32的HC-SR04超声波测距模块驱动程序,通过测量声波飞行时间来计算距离,广泛应用于机器人避障、距离检测等场景。
4.2 硬件连接
| 超声波模块 | STM32引脚 | 功能说明 |
|---|---|---|
| VCC | 5V | 电源正极 |
| GND | GND | 电源地 |
| Trig | PB8 | 触发信号输出 |
| Echo | PB9 | 回响信号输入 |
4.3 超声波避障模块的原理
超声波避障模块的工作原理模仿了蝙蝠的回声定位机制。其核心是测量超声波从发射到接收所经过的时间,从而计算距离。
工作流程如下:
1.触发: 主控器(如单片机)向超声波模块的Trig引脚发送一个至少10微秒的高电平脉冲。
2.发射:模块内部电路接收到触发信号后,会自动发射一束 8个40kHz 的超声波脉冲。
3.传播: 超声波在空气中以约 340m/s 的速度向前传播,遇到障碍物后会被反射。
4.接收: 模块的接收器(探头)会检测到返回的超声波回声。
5.回响:当模块确认接收到回波后,会在其 Echo 引脚输出一个高电平。这个高电平的持续时间与超声波“发射-接收”所花费的时间完全成正比。
6.计算:主控器通过测量 Echo 引脚高电平的持续时间,即可计算出距离。
4.4 核心工作原理
测距时序
Trig: ______|¯¯¯¯¯|________________
10-20us
Echo: ________________|¯¯¯¯¯|______
↑ ↑
开始计时 结束计时
发射:Trig引脚输出10-20us高电平脉冲
接收:Echo引脚输出高电平,持续时间与距离成正比
计算:距离 = (高电平时间 × 声速) / 2
4.5代码实现
ultrasonic.h
#ifndef __ULTRASONIC_H
#define __ULTRASONIC_H
// 避障动作定义
typedef enum {
AVOID_FORWARD = 0, // 前进
AVOID_SLOW_RIGHT, // 慢速右转
AVOID_BACK_RIGHT, // 后退右转
AVOID_STOP // 停止
} Avoidance_Action_t;
// 距离阈值定义
#define OBSTACLE_SAFE_DISTANCE 25.0 // 安全距离25cm
#define OBSTACLE_WARNING_DISTANCE 15.0 // 警告距离15cm
#define OBSTACLE_DANGER_DISTANCE 8.0 // 危险距离8cm
// 函数声明
void Ultrasonic_Init(void);
void Ultrasonic_Trigger(void);
float Ultrasonic_GetDistance(void);
Avoidance_Action_t Ultrasonic_AvoidObstacle(float distance);
#endif
ultrasonic.c
#include "ultrasonic.h"
#include "stm32f10x.h"
#include "Delay.h"
// 超声波状态变量
static uint32_t g_echo_start_time = 0;
static uint32_t g_echo_end_time = 0;
static uint8_t g_measurement_done = 0;
static float g_current_distance = 0.0;
/**
* @brief 超声波模块初始化
* @param 无
* @retval 无
*/
void Ultrasonic_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); // 使用TIM4进行时间测量
// Trig引脚(PB8)输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Echo引脚(PB9)输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 定时器4配置 - 用于测量高电平时间
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 1MHz计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
// 配置外部中断用于Echo引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line9;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM4, ENABLE);
}
/**
* @brief 发送超声波触发信号
* @param 无
* @retval 无
*/
void Ultrasonic_Trigger(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_8);
Delay_us(20); // 20us触发脉冲
GPIO_ResetBits(GPIOB, GPIO_Pin_8);
}
/**
* @brief 获取距离测量结果
* @param 无
* @retval 距离值(cm)
*/
float Ultrasonic_GetDistance(void)
{
g_measurement_done = 0;
Ultrasonic_Trigger();
// 等待测量完成(最多100ms)
uint32_t timeout = 0;
while(!g_measurement_done && timeout < 100) {
Delay_ms(1);
timeout++;
}
if(timeout >= 100) {
return -1.0; // 测量超时
}
return g_current_distance;
}
/**
* @brief 避障决策函数
* @param distance: 当前距离
* @retval 避障动作指令
*/
Avoidance_Action_t Ultrasonic_AvoidObstacle(float distance)
{
if(distance < 0) {
return AVOID_STOP; // 测量错误,停止
}
else if(distance > OBSTACLE_SAFE_DISTANCE) {
return AVOID_FORWARD; // 安全距离,继续前进
}
else if(distance > OBSTACLE_WARNING_DISTANCE) {
return AVOID_SLOW_RIGHT; // 警告距离,慢速右转
}
else {
return AVOID_BACK_RIGHT; // 危险距离,后退并右转
}
}
/**
* @brief EXTI9_5中断服务函数
* @param 无
* @retval 无
*/
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line9) != RESET) {
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9)) {
// 上升沿 - 开始计时
g_echo_start_time = TIM_GetCounter(TIM4);
TIM_SetCounter(TIM4, 0);
} else {
// 下降沿 - 结束计时
g_echo_end_time = TIM_GetCounter(TIM4);
uint32_t pulse_width = g_echo_end_time - g_echo_start_time;
// 计算距离(声速340m/s = 0.034cm/us)
g_current_distance = (pulse_width * 0.034) / 2.0;
g_measurement_done = 1;
}
EXTI_ClearITPendingBit(EXTI_Line9);
}
}
超声波模块详解:
设计思路:
-
使用外部中断精确捕捉Echo信号的上升沿和下降沿
-
定时器测量高电平脉冲宽度
-
根据距离阈值做出不同的避障决策
5. 红外循迹模块
5.1 模块概述
这是一个基于STM32的五路红外循迹传感器模块,用于智能小车自动跟随黑线行驶。通过检测地面反射光强度来识别路径,实现精确的线路跟踪功能。
5.2 红外循迹模块的原理
红外循迹模块的核心原理是利用不同颜色表面对红外光的不同反射率。
1、物理基础
红外发射管:发射出一束人眼不可见的红外光。
红外接收管(通常是光敏三极管):接收反射回来的红外光,其电阻会随着接收到的红外光强度而变化。
2、工作过程
-
当模块安装在距离地面一定高度(通常1-3厘米)时,红外光会照射到地面并被反射。
-
遇到白色表面:白色反射率高,大部分红外光被反射回来,接收管接收到较强的信号,输出低电平(或通过比较器后输出低电平)。
-
遇到黑色表面:黑色吸收率高,大部分红外光被吸收,只有很少的红外光被反射回来,接收管接收到的信号很弱,输出高电平(或通过比较器后输出高电平)。
简单总结:白底黑线 → 压到黑线输出高电平;黑底白线 → 压到白线输出低电平。
5.3 硬件连接
| 传感器通道 | STM32引脚 | 传感器位置 | 检测范围 |
|---|---|---|---|
| LEFT2 | PB12 | 最左侧 | 远左检测 |
| LEFT1 | PB13 | 左侧 | 左边界 |
| MIDDLE | PB14 | 中间 | 路径中心 |
| RIGHT1 | PB15 | 右侧 | 右边界 |
| RIGHT2 | PB10 | 最右侧 | 远右检测 ``` |
5.4 传感器布局示意图
行驶方向
↑
┌───┬───┬───┬───┬───┐
│ L2│ L1│ M │ R1│ R2│ 传感器排列
└───┴───┴───┴───┴───┘
○ ○ ○ ○ ○ 检测点
5.5代码实现
infrared.h
#pragma once
//传感器状态结构体
typedef struct {
uint8_t left2 : 1;
uint8_t left1 : 1;
uint8_t middle : 1;
uint8_t right1 : 1;
uint8_t right2 : 1;
} Track_State_t;
//循迹动作定义
typedef enum {
TRACK_FORWARD = 0,
TRACK_SLOW_LEFT,
TRACK_SHARP_LEFT,
TRACK_SLOW_RIGHT,
TRACK_SHARP_RIGHT,
TRACK_STOP
} Tracking_Action_t;
extern Track_State_t g_track_state;
//函数声明
void Infrared_Init(void);
Track_State_t Infrared_ReadSensors(void);
Tracking_Action_t Infrared_TrackLine(Track_State_t state);
const char* Infrared_GetStateString(Track_State_t state);
infrared.c
#include "stm32f10x.h"
#include "infrared.h"
//循迹传感器状态
Track_State_t g_track_state = {0};
/**
* @brief 红外循迹传感器初始化
* @param 无
* @retval 无
*/
void Infrared_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//开启GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 5路红外传感器引脚:PB12~PB15, PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/**
* @brief 读取循迹传感器状态
* @param 无
* @retval 传感器状态结构体
*/
Track_State_t Infrared_ReadSensors(void)
{
Track_State_t state;
//检测到黑线时输出低电平(0),未检测到为高电平(1)
state.left2 = (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0);
state.left1 = (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == 0);
state.middle = (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0);
state.right1 = (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15) == 0);
state.right2 = (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == 0);
g_track_state = state;
return state;
}
/**
* @brief 循迹决策函数
* @param state: 传感器状态
* @retval 循迹动作指令
*/
Tracking_Action_t Infrared_TrackLine(Track_State_t state)
{
//5路传感器状态判断
if(state.middle && !state.left1 && !state.right1) {
return TRACK_FORWARD;
}
else if (state.left1 && !state.left2) {
return TRACK_SLOW_LEFT;
}
else if (state.left2) {
return TRACK_SHARP_LEFT;
}
else if (state.right1 && !state.right2) {
return TRACK_SLOW_RIGHT;
}
else if (state.right2) {
return TRACK_SHARP_RIGHT;
}
else if (!state.left1 && !state.middle && !state.right1) {
return TRACK_STOP;
}
else {
return TRACK_FORWARD;
}
}
/**
* @brief 获取传感器状态描述
* @param state: 传感器状态
* @retval 状态描述字符串
*/
const char* Infrared_GetStateString(Track_State_t state)
{
if(state.left2 && state.left1 && state.middle && state.right1 && state.right2)
return "11111 - All Sensors";
else if(state.left2) return "11000 - Far Left";
else if(state.left1) return "01100 - Left";
else if(state.middle) return "00100 - Center";
else if(state.right1) return "00011 - Right";
else if(state.right2) return "00011 - Far Right";
else return "00000 - Lost";
}
红外循迹模块详解:
设计思路:
-
使用5路红外传感器提高循迹精度
-
根据传感器组合状态做出不同的转向决策
-
支持轻微偏离和严重偏离的不同处理
6. 蓝牙遥控模块
6.1 蓝牙模块
最常用的是 HC-05 或 HC-06 模块。
HC-05:主从一体,既可以作为主机也可以作为从机,功能更强,可以做模块间的通信。
HC-06:从机模式,只能被连接,价格稍低,完全满足手机遥控小车的需求。
HC-05/HC-06 关键参数:
接口:UART(串口),与STM32直接连接
工作电压:3.3V
通信距离:通常约10米(空旷地带)
默认波特率:9600(可配置)
6.2 蓝牙遥控系统的原理
蓝牙遥控的本质是无线串口通信。整个系统的工作流程如下:
手机APP --(蓝牙无线信号)--> 蓝牙模块 --(串口指令)--> STM32 --(控制信号)--> 电机驱动 --> 车轮电机
核心原理:
1.配对连接:手机与小车上的蓝牙模块进行配对。
2.数据发送:手机APP将您的操控(如前进、后退、左转、右转)编码成特定的指令字符串。
3.无线传输:指令通过蓝牙协议无线发送给车载蓝牙模块。
4.串口解析:车载蓝牙模块通过串口将指令字符串透传给STM32。
5.指令执行:STM32解析字符串,控制电机驱动模块,从而改变小车的运动状态。
6.3硬件连接(以HC-05为例)
HC-05蓝牙模块 STM32F103C8T6 L298N电机驱动
VCC --------> 3.3V 12V Input <--- 电池正极
GND --------> GND GND <--- 电池负极
TXD --------> PA10 (USART1_RX) IN1, IN2, IN3, IN4 --> STM32 GPIO
RXD --------> PA9 (USART1_TX) OUT1, OUT2 --> 左轮电机
OUT3, OUT4 --> 右轮电机
详细接线表:
| 模块 | 引脚 | 连接到STM32 | 说明 |
|---|---|---|---|
| HC-05 | VCC | 3.3V | 切勿接5V,会烧坏模块! |
| GND | GND | 共地 | |
| TXD | PA10 (USART1_RX) | 蓝牙发送,STM32接收 | |
| RXD | PA9 (USART1_TX) | 蓝牙接收,STM32发送 |
6.4 代码实现
bluetooth.h
#pragma once
#define BLUETOOTH_BUFFER_SIZE 64
//蓝牙动作定义
typedef enum {
BT_ACTION_FORWARD = 0,
BT_ACTION_BACKWARD,
BT_ACTION_LEFT,
BT_ACTION_RIGHT,
BT_ACTION_STOP,
BT_ACTION_MODE_MANUAL,
BT_ACTION_MODE_AVOIDANCE,
BT_ACTION_MODE_TRACKING,
BT_ACTION_MODE_STOP
} Bluetooth_Action_t;
//蓝牙处理结构体
typedef struct {
uint8_t command;
Bluetooth_Action_t action;
uint8_t valid;
char description[20];
} Bluetooth_Result_t;
extern volatile uint8_t g_current_command;
extern volatile uint8_t g_bluetooth_cmd_ready;
//函数声明
void Bluetooth_Init(void);
void Bluetooth_SendString(char *str);
void Bluetooth_SendData(uint8_t data);
Bluetooth_Result_t Bluetooth_ProcessCommand(uint8_t cmd);
uint8_t Bluetooth_GetCommand(void);
bluetooth.c
#include "stm32f10x.h"
#include <stdio.h>
#include <string.h>
#include "bluetooth.h"
//蓝牙接收缓冲区
volatile uint8_t g_bluetooth_rx_buffer[BLUETOOTH_BUFFER_SIZE];
volatile uint8_t g_bluetooth_rx_index = 0;
volatile uint8_t g_bluetooth_cmd_ready = 0;
volatile uint8_t g_current_command = 0;
/**
* @brief 蓝牙串口初始化
* @param 无
* @retval 无
*/
void Bluetooth_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// USART1 TX(PA9) - 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART1 RX(PA10) - 浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART参数配置
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 配置串口中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能串口
USART_Cmd(USART1, ENABLE);
// 发送启动信息
Bluetooth_SendString("Four-Wheel Smart Car Ready!\r\n");
Bluetooth_SendString("Commands: F-forward B-back L-left R-right S-stop\r\n");
Bluetooth_SendString("Modes: 1-Manual 2-Avoidance 3-Tracking 0-Stop\r\n");
}
/**
* @brief 串口发送字符串
* @param str: 要发送的字符串
* @retval 无
*/
void Bluetooth_SendString(char *str)
{
while(*str) {
USART_SendData(USART1, *str++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
}
/**
* @brief 串口发送数据
* @param data: 要发送的数据
* @retval 无
*/
void Bluetooth_SendData(uint8_t data)
{
USART_SendData(USART1, data);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
/**
* @brief 处理蓝牙命令
* @param cmd: 接收到的命令
* @retval 处理结果
*/
Bluetooth_Result_t Bluetooth_ProcessCommand(uint8_t cmd)
{
Bluetooth_Result_t result;
result.command = cmd;
result.valid = 1;
switch(cmd) {
case 'F': case 'f':
result.action = BT_ACTION_FORWARD;
strcpy(result.description, "Forward");
break;
case 'B': case 'b':
result.action = BT_ACTION_BACKWARD;
strcpy(result.description, "Backward");
break;
case 'L': case 'l':
result.action = BT_ACTION_LEFT;
strcpy(result.description, "Turn Left");
break;
case 'R': case 'r':
result.action = BT_ACTION_RIGHT;
strcpy(result.description, "Turn Right");
break;
case 'S': case 's':
result.action = BT_ACTION_STOP;
strcpy(result.description, "Stop");
break;
case '0':
result.action = BT_ACTION_MODE_STOP;
strcpy(result.description, "Stop Mode");
break;
case '1':
result.action = BT_ACTION_MODE_MANUAL;
strcpy(result.description, "Manual Mode");
break;
case '2':
result.action = BT_ACTION_MODE_AVOIDANCE;
strcpy(result.description, "Avoidance Mode");
break;
case '3':
result.action = BT_ACTION_MODE_TRACKING;
strcpy(result.description, "Tracking Mode");
break;
default:
result.valid = 0;
strcpy(result.description, "Unknown Command");
break;
}
return result;
}
/**
* @brief 获取蓝牙命令
* @param 无
* @retval 接收到的命令,0表示无新命令
*/
uint8_t Bluetooth_GetCommand(void)
{
if(g_bluetooth_cmd_ready) {
g_bluetooth_cmd_ready = 0;
return g_current_command;
}
return 0;
}
/**
* @brief USART1中断服务函数
* @param 无
* @retval 无
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
uint8_t received_data = USART_ReceiveData(USART1);
// 简单的命令处理:只取单个字符命令
if(received_data != '\r' && received_data != '\n') {
g_current_command = received_data;
g_bluetooth_cmd_ready = 1;
// 回声显示
Bluetooth_SendData(received_data);
Bluetooth_SendString("\r\n");
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
蓝牙模块详解:
设计思路:
-
支持单字符命令和模式切换
-
提供命令回声和状态反馈
-
结构化管理命令处理结果
7. 系统主控模块
#include "stm32f10x.h"
#include "motor.h"
#include "ultrasonic.h"
#include "infrared.h"
#include "bluetooth.h"
#include "Delay.h"
#include <stdio.h>
//系统工作模式
typedef enum {
MODE_STOP = 0, //停止模式
MODE_MANUAL, // 手动遥控模式
MODE_AUTO_AVOIDANCE, // 自动避障模式
MODE_AUTO_TRACKING // 自动循迹模式
} System_Mode_t;
typedef struct {
System_Mode_t current_mode;
System_Mode_t previous_mode;
uint32_t mode_change_time;
uint8_t system_initialized;
} System_State_t;
//全局变量
System_State_t g_system_state = {MODE_STOP, MODE_STOP, 0, 0};
uint32_t g_system_tick = 0;
/**
* @brief 系统初始化
* @param 无
* @retval 无
*/
void System_Init(void)
{
//初始化各模块
Motor_Init();
Ultrasonic_Init();
Infrared_Init();
Bluetooth_Init();
g_system_state.system_initialized = 1;
g_system_state.current_mode = MODE_STOP;
g_system_tick = 0;
Bluetooth_SendString("System Initialization Complete!\r\n");
}
/**
* @brief 系统模式切换
* @param new_mode: 新模式
* @retval 无
*/
void System_ChangeMode(System_Mode_t new_mode)
{
if(new_mode == g_system_state.current_mode) {
return; // 模式未改变
}
g_system_state.previous_mode = g_system_state.current_mode;
g_system_state.current_mode = new_mode;
g_system_state.mode_change_time = g_system_tick;
// 模式切换时停止电机
Motor_StopAll();
// 发送模式切换信息
char mode_msg[50];
switch(new_mode) {
case MODE_STOP:
sprintf(mode_msg, "Mode Changed: STOP\r\n");
break;
case MODE_MANUAL:
sprintf(mode_msg, "Mode Changed: MANUAL CONTROL\r\n");
break;
case MODE_AUTO_AVOIDANCE:
sprintf(mode_msg, "Mode Changed: AUTO AVOIDANCE\r\n");
break;
case MODE_AUTO_TRACKING:
sprintf(mode_msg, "Mode Changed: AUTO TRACKING\r\n");
break;
}
Bluetooth_SendString(mode_msg);
}
/**
* @brief 手动模式处理
* @param action: 蓝牙动作
* @retval 无
*/
void ManualMode_Handler(Bluetooth_Action_t action)
{
switch(action) {
case BT_ACTION_FORWARD:
Motor_Forward(SPEED_MEDIUM);
Bluetooth_SendString("Moving Forward\r\n");
break;
case BT_ACTION_BACKWARD:
Motor_Backward(SPEED_MEDIUM);
Bluetooth_SendString("Moving Backward\r\n");
break;
case BT_ACTION_LEFT:
Motor_TurnLeft(SPEED_MEDIUM);
Bluetooth_SendString("Turning Left\r\n");
break;
case BT_ACTION_RIGHT:
Motor_TurnRight(SPEED_MEDIUM);
Bluetooth_SendString("Turning Right\r\n");
break;
case BT_ACTION_STOP:
Motor_StopAll();
Bluetooth_SendString("Stopped\r\n");
break;
default:
break;
}
}
/**
* @brief 自动避障模式处理
* @param 无
* @retval 无
*/
void AvoidanceMode_Handler(void)
{
static uint32_t last_measure_time = 0;
// 每200ms测量一次距离
if(g_system_tick - last_measure_time > 200) {
last_measure_time = g_system_tick;
float distance = Ultrasonic_GetDistance();
Avoidance_Action_t action = Ultrasonic_AvoidObstacle(distance);
char dist_msg[30];
sprintf(dist_msg, "Distance: %.1fcm\r\n", distance);
Bluetooth_SendString(dist_msg);
switch(action) {
case AVOID_FORWARD:
Motor_Forward(SPEED_LOW);
break;
case AVOID_SLOW_RIGHT:
Motor_TurnRight(SPEED_LOW);
break;
case AVOID_BACK_RIGHT:
Motor_Backward(SPEED_LOW);
Delay_ms(300);
Motor_SpinRight(SPEED_MEDIUM);
Delay_ms(500);
break;
case AVOID_STOP:
Motor_StopAll();
break;
}
}
}
/**
* @brief 自动循迹模式处理
* @param 无
* @retval 无
*/
void TrackingMode_Handler(void)
{
Track_State_t track_state = Infrared_ReadSensors();
Tracking_Action_t action = Infrared_TrackLine(track_state);
// 每100ms发送一次传感器状态
static uint32_t last_report_time = 0;
if(g_system_tick - last_report_time > 100) {
last_report_time = g_system_tick;
char track_msg[50];
sprintf(track_msg, "Track: %s\r\n", Infrared_GetStateString(track_state));
Bluetooth_SendString(track_msg);
}
switch(action) {
case TRACK_FORWARD:
Motor_Forward(SPEED_MEDIUM);
break;
case TRACK_SLOW_LEFT:
Motor_TurnLeft(SPEED_LOW);
break;
case TRACK_SHARP_LEFT:
Motor_SpinLeft(SPEED_MEDIUM);
Delay_ms(100);
break;
case TRACK_SLOW_RIGHT:
Motor_TurnRight(SPEED_LOW);
break;
case TRACK_SHARP_RIGHT:
Motor_SpinRight(SPEED_MEDIUM);
Delay_ms(100);
break;
case TRACK_STOP:
Motor_StopAll();
// 尝试寻找路线
Motor_SpinLeft(SPEED_LOW);
Delay_ms(200);
break;
}
}
/**
* @brief 系统状态报告
* @param 无
* @retval 无
*/
void System_ReportStatus(void)
{
static uint32_t last_report_time = 0;
// 每2秒报告一次系统状态
if(g_system_tick - last_report_time > 2000) {
last_report_time = g_system_tick;
Motor_Speed_t motor_speeds = Motor_GetSpeeds();
char status_msg[100];
sprintf(status_msg,
"System Status - Mode: %d, Motors: LF%d RF%d LR%d RR%d\r\n",
g_system_state.current_mode,
motor_speeds.left_front,
motor_speeds.right_front,
motor_speeds.left_rear,
motor_speeds.right_rear);
Bluetooth_SendString(status_msg);
}
}
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main()
{
//系统初始化
System_Init();
Bluetooth_SendString("Four-Wheel Smart Car System Started!\r\n");
while(1) {
g_system_tick++;
//处理蓝牙命令
uint8_t bt_cmd = Bluetooth_GetCommand();
if (bt_cmd != 0) {
Bluetooth_Result_t result = Bluetooth_ProcessCommand(bt_cmd);
if (result.valid) {
//模式切换命令
switch(result.action) {
case BT_ACTION_MODE_STOP:
System_ChangeMode(MODE_STOP);
break;
case BT_ACTION_MODE_MANUAL:
System_ChangeMode(MODE_MANUAL);
break;
case BT_ACTION_MODE_AVOIDANCE:
System_ChangeMode(MODE_AUTO_AVOIDANCE);
break;
case BT_ACTION_MODE_TRACKING:
System_ChangeMode(MODE_AUTO_TRACKING);
break;
default:
//运动命令只在手动模式下处理
if (g_system_state.current_mode == MODE_MANUAL) {
ManualMode_Handler(result.action);
}
break;
}
}
}
//根据当前模式执行相应功能
switch(g_system_state.current_mode) {
case MODE_STOP:
//停止模式,不执行任何动作
break;
case MODE_MANUAL:
//手动模式由蓝牙命令驱动
break;
case MODE_AUTO_AVOIDANCE:
AvoidanceMode_Handler();
break;
case MODE_AUTO_TRACKING:
TrackingMode_Handler();
break;
}
//系统状态报告
System_ReportStatus();
Delay_ms(10); //主循环延时
}
}
主控模块详解:
设计思路:
-
四模式状态机:停止、手动、避障、循迹
-
模块化处理函数,便于维护和扩展
-
系统状态监控和报告机制
系统特点:
-
安全优先:模式切换时自动停止
-
状态反馈:实时报告系统状态
-
灵活控制:支持遥控和自动模式
-
易于调试:丰富的状态信息输出
更多推荐



所有评论(0)