参考:stm32 超声波模块 原理 实现测距 +舵机使用
作者:点灯小哥
发布时间: 2021-03-10 19:37:16
网址:https://blog.csdn.net/weixin_46016743/article/details/114643703
目录
- 效果展示
- 超声波传感器原理
- 超声波测距编程步骤
- 代码编写
效果展示
超声波传感器原理
超声波测距编程步骤
要配置三个结构体
接线:
- Trig:PB11
- Echo:PB10
- PB5:连接舵机
代码编写
HC_SR04.h
#ifndef _HC_SR04_H //#ifndef #define #endif 条件编译 为了防止重复编译
#define _HC_SR04_H
#include "stm32f10x.h" // Device headervoid HC_SR04(void);
void Open_tim4(void);
void Close_tim4(void);
int GetEcho_time(void);
float GetLength(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)
#endif
超声波HC_SR04.c
#include "stm32f10x.h" // Device header
#include "HC_SR04.h"
#include "SysTick.h"extern uint16_t mscount = 0; //extern 让main函数也能使用这里这个void HC_SR04(void)
{GPIO_InitTypeDef GPIO_HC_SR04init; //1.配置GPIO引脚结构体 Trig PB11 Echo PB10TIM_TimeBaseInitTypeDef TIM_HC_SR04init; //2.配置定时器结构体NVIC_InitTypeDef NVIC_HC_SR04init; //3.配置NVIC中断控制器结构体(TIM4定时器)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断组1//rcc.hRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//4.开启GPIOB时钟(在APB2总线上)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//定时器的时钟//Trig PB11 发送GPIO_HC_SR04init.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_HC_SR04init.GPIO_Pin = GPIO_Pin_11; GPIO_HC_SR04init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( GPIOB, &GPIO_HC_SR04init );//Echo PB10 接收GPIO_HC_SR04init.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 只要求高电平 高低电平直接检测GPIO_HC_SR04init.GPIO_Pin = GPIO_Pin_10;GPIO_Init( GPIOB, &GPIO_HC_SR04init );//定时器4的配置TIM_HC_SR04init.TIM_ClockDivision = TIM_CKD_DIV1;//分频系数1 不分频 还是72MHzTIM_HC_SR04init.TIM_CounterMode = TIM_CounterMode_Up;//向上计数TIM_HC_SR04init.TIM_Period = 100 - 1 ; //1usTIM_HC_SR04init.TIM_Prescaler = 72 - 1 ; //72M 这两个相乘7200/72 000 000 = 1usTIM_TimeBaseInit( TIM4, &TIM_HC_SR04init);TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);//IT就是中断 定时器中断配置 中断标志:TIM_IT_Update是允许溢出/更新标志位TIM_Cmd( TIM4, DISABLE ); //定时器先关闭 等测量距离时再打开 下面给出打开定时器函数//NVIC中断控制器(TIM4定时器)NVIC_HC_SR04init.NVIC_IRQChannel = TIM4_IRQn;// 通道 中断源是定时器4NVIC_HC_SR04init.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级 给的最高的NVIC_HC_SR04init.NVIC_IRQChannelSubPriority = 0;//子优先级NVIC_HC_SR04init.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_HC_SR04init);
}
//打开定时器4
void Open_tim4(void)
{TIM_SetCounter( TIM4, 0);//开启计数器计数 计数值从0开始mscount = 0; //需要计算高电平5次数值 取平均值 防止一次算的距离不精准TIM_Cmd( TIM4, ENABLE ); //定时器使能 打开了
}//关闭定时器4
void Close_tim4(void)
{TIM_Cmd( TIM4, DISABLE ); //关闭
}//定时器TIM4中断服务函数 函数名不能改动
void TIM4_IRQHandler(void)
{if ( TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //判断是否发生中断{TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //清除中断的标记位mscount++; //记录发生的中断次数 为了取5次测量计算提高精度//定时器中断一次就是1us }
}//获取定时器计数器的值 得到Echo高电平的时间
int GetEcho_time(void)
{uint32_t t = 0;t = mscount * 1000; //发生了多少次中断 *1000 得到时间ms(一次中断就是1us)t += TIM_GetCounter(TIM4);//获取定时器计数值 {这两行没看懂 感觉重复了?}TIM4->CNT = 0;//代表向上增的寄存器(向上向下计数 前面章节有讲) 要置零 重装载ms_delay(50);//系统定时器延时return t;
}//获取超声波测距距离
float GetLength(void)
{int i = 0;uint16_t t = 0;float length = 0;float sum = 0;while(i != 5)//算5次 提高计算精度{TRIG_Send(1);us_delay(20);//硬件模块要求发送高电平时间大于10usTRIG_Send(0);//此时超声波开始工作了while(ECHO_Reci == 0);Open_tim4();i=i+1;while(ECHO_Reci == 1);Close_tim4();t = GetEcho_time();//计算ECHO高电平持续时间就能换算出距离length =((float) t / 58.0);sum = sum +length; }length = sum / 5.0;return length;
}
main.c
#include "stm32f10x.h" // Device header
#include "usart.h"
#include "led.h"
#include "tim.h"
#include "motor.h"
#include "SysTick.h"
#include "HC_SR04.h"//记得添加路径void delay(uint16_t time)
{uint16_t i = 0;while(time--){i=12000;while(i--);}
}int main(void)
{int pwmval = 195;float Length = 0;HC_SR04();Usart_Init();motor_config();while(1){int pwmval = 155;Length = GetLength();printf("%.3f\r\n",Length);//之前重定向print函数 串口打印输出距离 串口小助手就能看到打印的距离了ms_delay(500);//再加一个距离判断 将之前写的舵机部分加进来即可控制舵机if(Length < 5){for(pwmval = 195; pwmval >= 155;pwmval -=15 )//逐步转到位置{TIM_SetCompare2( TIM3, pwmval); //5. 配置PWM比较值 配合重装载值生成占空比delay(1000);}}else if (Length > 5){TIM_SetCompare2( TIM3, pwmval-20); //让舵机回去}}
}