STM32:两种方式实现超声波测距
超声波模块HC-SR04的工作原理很简单,有很多办法可以完成超声波测距,这里简单介绍两种。
(图片来源网络,侵删)
1.定时器中断法
配置定时器的中断并声明一个Time的变量,在中断中先判断标志位,然后检查echo端口是否为高电平,如果是,Time++,然后变量time乘以定时时间就能得到echo端口高电平持续的时间,经过计算就可以得到距离。
Timer.c
#include "stm32f10x.h" // Device header #include "Timer.h" extern uint16_t Time; //Time变量在HCSR04.c文件中定义 void Timer_Init() { Time = 0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //选择APB1总线下的定时器Timer3 TIM_InternalClockConfig(TIM3); //TIM3使用内部时钟 //默认使用内部时钟,不写这句代码也没关系 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟1分频 TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,此处为向上计数 TIM_TimeBaseInitStructure.TIM_Period = 7200 - 1; //ARR 1 = 0.0001S,自动重装器的值 TIM_TimeBaseInitStructure.TIM_Prescaler = 0; //PSC,预分频器的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //高级计时器特有,重复计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); TIM_ClearFlag(TIM3, TIM_FLAG_Update); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能中断 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //将中断优先级分为两组,即组1和组2。 NVIC_InitTypeDef NVIC_InitStructure;// 定义一个NVIC_InitTypeDef结构体变量,用于初始化中断控制器 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;// 设置中断通道为TIM3的IRQn中断 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;// 使能中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;// 设置中断优先级为2,表示高优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;// 设置中断子优先级为1,表示低优先级 NVIC_Init(&NVIC_InitStructure);// 使用NVIC_Init函数初始化中断控制器 TIM_Cmd(TIM3, ENABLE);// 使能定时器TIM3 } void TIM3_IRQHandler(void) // 定时器3的中断函数 { if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) // 检查定时器3的更新中断标志位是否被设置 { if (GPIO_ReadInputDataBit(Echo_Port, Echo_Pin) == 1) // 读取回声传感器端口上的引脚状态 { Time++; // 如果引脚状态为高电平,则增加时间计数器 } TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清空标志位,表示中断已经处理完毕 } }
Timer.h
#ifndef __TIMER_H #define __TIMER_H #define Trig_Port GPIOA #define Trig_Pin GPIO_Pin_5 #define Trig_RCC RCC_APB2Periph_GPIOA #define Echo_Port GPIOA #define Echo_Pin GPIO_Pin_6 #define Echo_RCC RCC_APB2Periph_GPIOA void Timer_Init(void); #endif
2.输入捕获法
配置定时器的输入捕获,在echo端口的上升沿捕获一次,下降沿捕获一次,通过“TIM_GetCapture2(TIM3)”这句代码直接可以将时间读取出来。
IC.c
#include "stm32f10x.h" // Device header void IC_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // TIM3->使用引脚PA6 //在超声波模块已经配置过 // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIO_InitTypeDef GPIO_InitStructure; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PB6引脚,接入超声波Echo引脚 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_InternalClockConfig(TIM3); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元 TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC分频系数 TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //通道一 TIM_ICInitTypeDef TIM_ICInitStructure; TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//TIM3的通道1 TIM_ICInitStructure.TIM_ICFilter = 0xF;//配置滤波器,参数决定滤波效果,高频滤波 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//极性选择,选择上升沿触发 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//每次都触发捕获 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//通道触发选择 //通道二 // TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//捕获通道二 // TIM_ICInitStructure.TIM_ICFilter=0xF;//滤除高频波动 // TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Falling;//下降触发捕获 // TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频 // TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_IndirectTI;//交叉通道输入 // TIM_ICInit(TIM3,&TIM_ICInitStructure); TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//pwmi模式配置通道2,效果相当于上面的代码 TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); TIM_Cmd(TIM3, ENABLE); }
IC.h
#ifndef __IC_H #define __IC_H void IC_Init(void); #endif
#超声波部分
这里将展示如何将获取到的时间值计算得到距离,定时器中断和输入捕获两种方法的实现都在下面的文件中,我们正确添加完文件后,在main文件中直接调用就可以实现测距的功能了。
HCSR04.c
#include "stm32f10x.h" // Device header #include "HCSR04.h" #include "Timer.h" #include "Delay.h" uint16_t Time; void HCSR04_Init() { RCC_APB2PeriphClockCmd(Trig_RCC, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin = Trig_Pin; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Trig_Port, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStruct.GPIO_Pin = Echo_Pin; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Echo_Port, &GPIO_InitStruct); GPIO_ResetBits(Trig_Port, Trig_Pin);//Trig引脚给低电平,为后续启动做准备 } void HCSR04_Start(void) { GPIO_SetBits(Trig_Port, Trig_Pin); Delay_us(40); GPIO_ResetBits(Trig_Port, Trig_Pin); Timer_Init();//定时器初始化 } uint16_t HCSR04_GetValue(void) //定时器中断测距 { HCSR04_Start(); Delay_ms(100); return ((Time * 0.0001) * 34000) / 2; // return Time; } float GetLength(void) //输入捕获测距 { int i=0; float length=0; float sum=0; float Length; for(i=0;i
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。