超声波的应用

功能实现请看最顶端视频

配合舵机实现指定距离转动功能:

主函数代码:

主函数部分: 首先定义了一个用于调整电机 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 函数用于获取超声波距离,通过多次测量取平均值的方式提高测量精度。首先发送触发信号,然后等待回声信号,记录时间并计算距离,最后返回平均距离。

相关推荐
LateBloomer77727 分钟前
FreeRTOS——信号量
笔记·stm32·学习·freertos
wenchm1 小时前
细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法
stm32·单片机·嵌入式硬件
编码追梦人2 小时前
如何实现单片机的安全启动和安全固件更新
单片机
电子工程师UP学堂2 小时前
电子应用设计方案-16:智能闹钟系统方案设计
单片机·嵌入式硬件
飞凌嵌入式3 小时前
飞凌嵌入式T113-i开发板RISC-V核的实时应用方案
人工智能·嵌入式硬件·嵌入式·risc-v·飞凌嵌入式
blessing。。4 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
嵌新程5 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin2012305 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件
电工小王(全国可飞)6 小时前
STM32 RAM在Memory Map中被分为3个区域
stm32·单片机·嵌入式硬件
maxiumII6 小时前
Diving into the STM32 HAL-----DAC笔记
笔记·stm32·嵌入式硬件