参考: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 header
void 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 PB10
TIM_TimeBaseInitTypeDef TIM_HC_SR04init; //2.配置定时器结构体
NVIC_InitTypeDef NVIC_HC_SR04init; //3.配置NVIC中断控制器结构体(TIM4定时器)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断组1
//rcc.h
RCC_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 不分频 还是72MHz
TIM_HC_SR04init.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_HC_SR04init.TIM_Period = 100 - 1 ; //1us
TIM_HC_SR04init.TIM_Prescaler = 72 - 1 ; //72M 这两个相乘7200/72 000 000 = 1us
TIM_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;// 通道 中断源是定时器4
NVIC_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);//硬件模块要求发送高电平时间大于10us
TRIG_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); //让舵机回去
}
}
}