嵌入式硬件篇---超声波|PID


文章目录

  • 前言
  • [1. 硬件准备](#1. 硬件准备)
  • [2. 硬件连接](#2. 硬件连接)
  • [3. 超声波测距原理](#3. 超声波测距原理)
  • [4. 代码实现(基于HAL库)](#4. 代码实现(基于HAL库))
    • [(1) 初始化定时器(用于测量Echo高电平时间)](#(1) 初始化定时器(用于测量Echo高电平时间))
    • [(2) 超声波触发与距离计算](#(2) 超声波触发与距离计算)
  • [5. PID算法实现](#5. PID算法实现)
    • [(1) PID结构体定义](#(1) PID结构体定义)
    • [(2) PID计算函数](#(2) PID计算函数)
  • [6. 控制执行机构](#6. 控制执行机构)
    • [(1) 电机控制(PWM调速)](#(1) 电机控制(PWM调速))
    • [(2) 舵机控制(角度调整)](#(2) 舵机控制(角度调整))
  • [7. 主循环逻辑](#7. 主循环逻辑)
  • [8. PID参数整定技巧](#8. PID参数整定技巧)
  • [9. 关键问题与优化](#9. 关键问题与优化)

前言

STM32F103RCT6 上使用超声波传感器(如HC-SR04)结合PID算法 实现稳定距离控制 ,通常用于避障、跟随或定位等场景。以下是详细实现步骤:


1. 硬件准备

主控芯片

主控芯片:STM32F103RCT6(72MHz Cortex-M3,足够处理超声波数据与PID运算)。

超声波模块

超声波模块:HC-SR04(测距范围2cm~400cm,精度±3mm)。

执行机构

执行机构:电机(如直流电机+编码器)或舵机(用于调整方向)。

其他

其他:电源、驱动电路(如L298N)、OLED/LCD(可选,用于显示距离)。

2. 硬件连接

HC-SR04引脚 STM32引脚 说明

VCC 5V 模块供电

Trig PA1 触发信号(输出)

Echo PA0 回波信号(输入,需EXTI中断)

GND GND 共地

注意:Echo信号为5V电平,需通过**电阻分压(如1kΩ+2kΩ)**转换为3.3V,避免损坏STM32。

3. 超声波测距原理

触发信号

触发信号:STM32发送10μs的高电平脉冲到Trig引脚。

回波检测

回波检测:HC-SR04发射超声波并接收回波,Echo引脚输出高电平,

持续时间与距离成正比(公式:距离(cm) = 高电平时间(μs) / 58)。

中断捕获

中断捕获:使用定时器输入捕获模式或EXTI中断+普通定时器测量Echo高电平时间。

4. 代码实现(基于HAL库)

(1) 初始化定时器(用于测量Echo高电平时间)

c 复制代码
// 定时器2初始化(1MHz计数频率,72MHz/72分频)
TIM_HandleTypeDef htim2;
void MX_TIM2_Init(void) {
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;          // 72分频
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0xFFFF;         // 最大计数值
  HAL_TIM_IC_Init(&htim2);
}

// 输入捕获配置(通道1,PA0)
TIM_IC_InitTypeDef sConfigIC;
sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING; // 上升沿触发
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);

(2) 超声波触发与距离计算

c 复制代码
float Get_Distance(void) {
  uint32_t start_time = 0, end_time = 0;
  float distance_cm = 0;

  // 发送10us触发脉冲
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
  delay_us(10);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);

  // 等待Echo上升沿(启动定时器)
  while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
  HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1);
  start_time = htim2.Instance->CCR1;

  // 等待Echo下降沿(停止定时器)
  while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);
  end_time = htim2.Instance->CCR1;
  HAL_TIM_IC_Stop(&htim2, TIM_CHANNEL_1);

  // 计算距离(单位:cm)
  distance_cm = (end_time - start_time) / 58.0f;
  return distance_cm;
}

5. PID算法实现

PID控制器通过调节输出使当前距离(反馈值)趋近目标距离(设定值)。

(1) PID结构体定义

c 复制代码
typedef struct {
  float Kp, Ki, Kd;      // PID参数
  float target;          // 目标距离(cm)
  float error, last_error, integral;
} PID_Controller;

PID_Controller pid = {0.5, 0.01, 0.2, 10.0, 0, 0, 0}; // 示例参数

(2) PID计算函数

c 复制代码
float PID_Update(PID_Controller *pid, float current) {
  pid->error = pid->target - current;  // 误差=目标值-当前值

  // 积分项(防饱和)
  pid->integral += pid->error;
  if (pid->integral > 100) pid->integral = 100;
  else if (pid->integral < -100) pid->integral = -100;

  // 微分项
  float derivative = pid->error - pid->last_error;
  pid->last_error = pid->error;

  // PID输出
  float output = pid->Kp * pid->error + 
                 pid->Ki * pid->integral + 
                 pid->Kd * derivative;
  return output;
}

6. 控制执行机构

根据PID输出调整电机或舵机:

(1) 电机控制(PWM调速)

c 复制代码
// 初始化PWM(TIM3通道1,PA6)
void MX_TIM3_Init(void) {
  TIM_OC_InitTypeDef sConfigOC = {0};
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 71;          // 1MHz频率
  htim3.Init.Period = 999;             // 1kHz PWM
  HAL_TIM_PWM_Init(&htim3);
  sConfigOC.Pulse = 0;                // 初始占空比0
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}

// 更新电机速度(PID输出映射到PWM占空比)
void Set_Motor_Speed(float pid_output) {
  uint16_t pwm = (uint16_t)fabs(pid_output * 10); // 比例缩放
  if (pwm > 999) pwm = 999;
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwm);

  // 根据输出正负设置电机方向
  if (pid_output > 0) {
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);   // 正转
  } else {
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 反转
  }
}

(2) 舵机控制(角度调整)

c 复制代码
// 设置舵机角度(PID输出映射到0~180°)
void Set_Servo_Angle(float pid_output) {
  uint16_t angle = 90 + (uint16_t)(pid_output * 10); // 示例映射
  uint16_t pwm = 500 + angle * 2000 / 180;           // 0.5ms~2.5ms
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwm);
}

7. 主循环逻辑

c 复制代码
int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();

  float current_distance = 0;
  float pid_output = 0;

  while (1) {
    current_distance = Get_Distance();      // 获取当前距离
    pid_output = PID_Update(&pid, current_distance);
    Set_Motor_Speed(pid_output);           // 调整电机速度
    // 或 Set_Servo_Angle(pid_output);     // 调整舵机角度

    HAL_Delay(50); // 控制周期50ms(20Hz)
  }
}

8. PID参数整定技巧

先调P

先调P:增大Kp直到系统快速响应但出现振荡。

再调D

再调D:加入Kd抑制振荡。

最后调I

最后调I:小幅增加Ki消除静态误差。

测试

测试场景:目标距离从远到近阶跃变化,观察响应曲线。

9. 关键问题与优化

超声波噪声

超声波噪声:多次采样取中值滤波

死区处理

死区处理:当误差小于阈值关闭PID输出,避免抖动。

动态目标

动态目标:若目标距离变化,需重新整定PID参数

通过上述步骤,STM32F103RCT6可稳定控制物体与超声波传感器间的距离。实际应用中需根据机械特性(如电机惯性)调整PID参数。


相关推荐
智商偏低27 分钟前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen2 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森4 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白4 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D4 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术7 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt8 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘8 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang8 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n10 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件