超声波的应用
功能实现请看最顶端视频
配合舵机实现指定距离转动功能:
主函数代码:
主函数部分: 首先定义了一个用于调整电机 PWM 值的变量 pwmval 和用于存储超声波测量距离的变量 length。
调用 HC_SR04Config 函数配置超声波传感器,usart_init 函数初始化串口通信,motor_config 函数配置电机。
在无限循环中,不断调用 Getlength 函数获取超声波传感器测量的距离,并通过串口打印输出。然后根据距离判断条件,调整电机的 PWM 值。如果距离小于 5,则逐渐减小 PWM 值;如果距离大于 5,则将 PWM 值减去 20。
// 包含必要的头文件
#include "stm32f10x.h"
#include "systick.h"
#include "led.h"
#include "HC_SR04.h"
#include "usart.h"
#include "motor.h"// 定义延时函数
void delay(uint16_t time)
{uint16_t i = 0;while (time--){// 设置一个较大的循环次数进行延时i = 12000;while (i--);}
}int main()
{// 初始化 PWM 值int pwmval = 195;// 用于存储超声波测量的距离float length = 0;// 配置 HC-SR04 超声波传感器HC_SR04Config();// 初始化串口通信usart_init();// 配置电机motor_config();while (1){// 获取超声波传感器测量的距离,保留三位小数length = Getlength();printf("%.3f\r\n", length);// 延时 50 毫秒ms_delay(50);// 如果距离小于 5if (length < 5){// 逐渐减小 PWM 值for (pwmval = 195; pwmval >= 155; pwmval -= 15){// 设置 TIM3 的通道 2 比较值TIM_SetCompare2(TIM3, pwmval);// 延时 500 毫秒delay(500);}}// 如果距离大于 5else if (length > 5){// 调整 PWM 值TIM_SetCompare2(TIM3, pwmval - 20);}}
}
舵机代码:
电机配置函数部分(motor_config): 首先定义了一些结构体变量用于配置 GPIO 和 TIM 相关参数。 通过时钟使能函数使能了 GPIOB、TIM3 和复用功能时钟。
配置 GPIO 为部分重映射,并将 GPIOB 的引脚 5 配置为复用推挽输出模式,用于连接电机。
配置 TIM3 的时钟分割、计数模式、周期和预分频值,以及通道 2 的 PWM 模式、输出状态和极性。最后使能 TIM3。
#include "stm32f10x.h"
#include "motor.h"// 舵机配置函数
void motor_config(void)
{GPIO_InitTypeDef GPIO_Motorinit;TIM_TimeBaseInitTypeDef TIM_Motorinit;TIM_OCInitTypeDef TIMPWM_Motorinit;// 使能 GPIOB 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);// 使能 TIM3 时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);// 使能复用功能时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 配置 GPIO 为部分重映射GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);// 配置 GPIOB 的引脚 5 为复用推挽输出模式,速度为 50MHzGPIO_Motorinit.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Motorinit.GPIO_Pin = GPIO_Pin_5;GPIO_Motorinit.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_Motorinit);// 配置 TIM3 的时钟分割、计数模式、周期和预分频值TIM_Motorinit.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分割TIM_Motorinit.TIM_CounterMode = TIM_CounterMode_Up; // TIM 向上计数模式TIM_Motorinit.TIM_Period = 200 - 1; // 设置下一个更新事件的周期TIM_Motorinit.TIM_Prescaler = 7200 - 1; // 设置预分频周期,用于 TIM 的时钟预分频TIM_TimeBaseInit(TIM3, &TIM_Motorinit);// 配置 TIM3 的通道 2 为 PWM1 模式,使能输出,低电平有效TIMPWM_Motorinit.TIM_OCMode = TIM_OCMode_PWM1; // 选择定时器模式 1TIMPWM_Motorinit.TIM_OutputState = TIM_OutputState_Enable; // 使能比较输出TIMPWM_Motorinit.TIM_OCPolarity = TIM_OCPolarity_Low; // 设置有效输出极性为低电平TIM_OC2Init(TIM3, &TIMPWM_Motorinit); // 初始化 TIM3 通道 2TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);// 使能 TIM3TIM_Cmd(TIM3, ENABLE);
}
超声波传感器代码:
超声波传感器配置函数部分(HC_SR04Config): 定义了一些结构体变量用于配置 GPIO 和 TIM 以及 NVIC 相关参数。 使能了 GPIOB 和 TIM4 的时钟,并配置 NVIC 优先级分组为 1。 将 GPIOB 的引脚 11(Trig 引脚)配置为推挽输出模式,引脚 10(ECHO 引脚)配置为浮空输入模式。 配置 TIM4 的时钟分割、计数模式、周期和预分频值,并使能 TIM4 的更新中断。最后配置 TIM4 中断的优先级并初始化 NVIC。
#include "stm32f10x.h"
void HC_SR04Config(void);
void Open_tim4(void);
void Close_tim4(void);
int GetEcho_time(void);
float Getlength(void);
void TIM4_IRQHandler(void);// 宏定义,用于读取 ECHO 引脚的输入电平
#define ECHO_Reci GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)
// 宏定义,用于设置 TRIG 引脚的输出电平
#define TRIG_Send(a) if(a) \GPIO_SetBits(GPIOB, GPIO_Pin_11); \else \GPIO_ResetBits(GPIOB, GPIO_Pin_11);\#include "HC_SR04.h"
#include "stm32f10x.h"
#include "systick.h"// 外部变量,用于存储毫秒计数
extern uint16_t mscount = 0;// HC-SR04 超声波传感器配置函数
void HC_SR04Config(void)
{GPIO_InitTypeDef GPIO_hcsr04init;TIM_TimeBaseInitTypeDef TIM_hcsr04init;NVIC_InitTypeDef NVIC_hcsr04init;// 使能 GPIOB 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);// 使能 TIM4 时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);// 配置 NVIC 优先级分组为 1NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);// 配置 Trig 引脚(PB11)为推挽输出模式GPIO_hcsr04init.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_hcsr04init.GPIO_Pin = GPIO_Pin_11;GPIO_hcsr04init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_hcsr04init);// 配置 ECHO 引脚(PB10)为浮空输入模式GPIO_hcsr04init.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_hcsr04init.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOB, &GPIO_hcsr04init);// 配置 TIM4 的时钟分割、计数模式、周期和预分频值TIM_hcsr04init.TIM_ClockDivision = TIM_CKD_DIV1;TIM_hcsr04init.TIM_CounterMode = TIM_CounterMode_Up;TIM_hcsr04init.TIM_Period = 1000 - 1;TIM_hcsr04init.TIM_Prescaler = 72 - 1;// 初始化 TIM4TIM_TimeBaseInit(TIM4, &TIM_hcsr04init);// 使能 TIM4 的更新中断TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);// 禁用 TIM4TIM_Cmd(TIM4, DISABLE);// 配置 TIM4 中断的优先级NVIC_hcsr04init.NVIC_IRQChannel = TIM4_IRQn;NVIC_hcsr04init.NVIC_IRQChannelPreemptionPriority = 0;NVIC_hcsr04init.NVIC_IRQChannelSubPriority = 0;NVIC_hcsr04init.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_hcsr04init);
}// 打开 TIM4
void Open_tim4(void)
{// 将 TIM4 的计数器清零TIM_SetCounter(TIM4, 0);// 重置毫秒计数mscount = 0;// 使能 TIM4TIM_Cmd(TIM4, ENABLE);
}// 关闭 TIM4
void Close_tim4(void)
{// 禁用 TIM4TIM_Cmd(TIM4, DISABLE);
}// TIM4 中断服务函数
void TIM4_IRQHandler(void)
{if (TIM_GetITStatus(TIM4, TIM_IT_Update)!= RESET){// 清除 TIM4 的更新中断标志TIM_ClearITPendingBit(TIM4, TIM_IT_Update);// 增加毫秒计数mscount++;}
}// 获取回声时间
int GetEcho_time(void)
{uint32_t t = 0;t = mscount * 1000;t += TIM_GetCounter(TIM4);// 将 TIM4 的计数器清零TIM4->CNT = 0;// 延时 50 毫秒ms_delay(50);return t;
}// 获取超声波距离
float Getlength(void)
{int i = 0;uint32_t t = 0;float length = 0;float sum = 0;while (i!= 5){// 设置 TRIG 引脚为高电平TRIG_Send(1);// 延时 20 微秒us_delay(20);// 设置 TRIG 引脚为低电平TRIG_Send(0);while (ECHO_Reci == 0);// 打开 TIM4Open_tim4();i = i + 1;while (ECHO_Reci == 1);// 关闭 TIM4Close_tim4();t = GetEcho_time();// 根据时间计算距离length = ((float)t / 58.0);sum = sum + length;}// 计算平均距离length = sum / 5.0;return length;
}
Open_tim4 函数用于打开 TIM4,将计数器清零,重置毫秒计数并使能 TIM4。
Close_tim4 函数用于关闭 TIM4。
TIM4_IRQHandler 是 TIM4 的中断服务函数,当 TIM4 发生更新中断时,清除中断标志并增加毫秒计数。
GetEcho_time 函数用于获取回声时间,通过读取毫秒计数和 TIM4 的计数器值计算得到。
Getlength 函数用于获取超声波距离,通过多次测量取平均值的方式提高测量精度。首先发送触发信号,然后等待回声信号,记录时间并计算距离,最后返回平均距离。