功能实现请看最顶端视频
配合舵机实现指定距离转动功能:
主函数代码:
主函数部分: 首先定义了一个用于调整电机 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);
// 如果距离小于 5
if (length < 5)
{
// 逐渐减小 PWM 值
for (pwmval = 195; pwmval >= 155; pwmval -= 15)
{
// 设置 TIM3 的通道 2 比较值
TIM_SetCompare2(TIM3, pwmval);
// 延时 500 毫秒
delay(500);
}
}
// 如果距离大于 5
else 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 为复用推挽输出模式,速度为 50MHz
GPIO_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; // 选择定时器模式 1
TIMPWM_Motorinit.TIM_OutputState = TIM_OutputState_Enable; // 使能比较输出
TIMPWM_Motorinit.TIM_OCPolarity = TIM_OCPolarity_Low; // 设置有效输出极性为低电平
TIM_OC2Init(TIM3, &TIMPWM_Motorinit); // 初始化 TIM3 通道 2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
// 使能 TIM3
TIM_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 优先级分组为 1
NVIC_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;
// 初始化 TIM4
TIM_TimeBaseInit(TIM4, &TIM_hcsr04init);
// 使能 TIM4 的更新中断
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
// 禁用 TIM4
TIM_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;
// 使能 TIM4
TIM_Cmd(TIM4, ENABLE);
}
// 关闭 TIM4
void Close_tim4(void)
{
// 禁用 TIM4
TIM_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);
// 打开 TIM4
Open_tim4();
i = i + 1;
while (ECHO_Reci == 1);
// 关闭 TIM4
Close_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 函数用于获取超声波距离,通过多次测量取平均值的方式提高测量精度。首先发送触发信号,然后等待回声信号,记录时间并计算距离,最后返回平均距离。