准备材料
- 超声波模块
H
C
−
S
R
04
HC-SR04
HC−SR04
- STM32F103RCT6(Mini板)
超声波模块原理分析
引脚 | 功能 |
---|
VCC | 接5V |
GND | 接开发板GND |
Trig | 接外部PWM信号输入 |
Echo | 输出整形过的方波信号 |
性能指标
精度:
3
m
m
3mm
3mm
测距范围:
2
c
m
2cm
2cm至
4
m
4m
4m
原理
给
T
r
i
g
Trig
Trig引脚输入一个
10
u
s
10us
10us以上的高电平信号,此时模块会发出超声波,并从
E
c
h
o
Echo
Echo引脚输出
5
V
5V
5V高电平,等超声波反射回来被模块接收到后,
E
c
h
o
Echo
Echo引脚输出低电平,高电平持续的时间就是距离。时间与距离的转换公式如下:
2
×
S
=
t
×
v
2\times S=t \times v
2×S=t×v
其中
S
=
距
离
,
单
位
:
c
m
S= 距离,单位:cm
S=距离,单位:cm
t
=
超
声
波
传
播
的
实
际
,
单
位
:
u
s
t= 超声波传播的实际,单位:us
t=超声波传播的实际,单位:us
v
=
声
速
,
344
m
/
s
v= 声速,344m/s
v=声速,344m/s
公式化简后可得
S
=
t
÷
58
S=t \div 58
S=t÷58
STM32程序设计
核心就是利用好TIM定时器的PWM输出、输入捕获功能
首先,要给
T
r
i
g
Trig
Trig引脚一个PWM信号(占空比自行调整),以持续输出至少
10
u
s
10us
10us的高电平信号,这里直接搬运正点原子PWM输出实验核心代码。
然后检测
E
c
h
o
Echo
Echo引脚高电平持续时间的方法就是用输入捕获去获得高电平持续时间(精度
1
u
s
1us
1us)。这里我没有使用正点原子的算法,我的输入捕获算法设计如下:
首先,我们
T
I
M
5
TIM5
TIM5定时器的最大计数是
65535
65535
65535,也就是总共计数
65536
u
s
65536us
65536us,我们知道超声波模块最远传输距离是
4
m
(
400
c
m
)
4m(400cm)
4m(400cm),也就是说,
E
c
h
o
Echo
Echo 高电平持续时间最长
23200
u
s
23200us
23200us,远小于溢出周期,因此不用担心计数器截断的问题,所以中断更新直接放弃考虑溢出中断,仅考虑捕获中断。然后我们定义两个变量
S
T
A
STA
STA 和
R
I
S
E
_
G
E
T
RISE\_ GET
RISE_GET ,初始状态都置为0;
S
T
A
STA
STA表示完成一次完整的高电平捕获,
R
I
S
E
_
G
E
T
RISE\_GET
RISE_GET 表示捕获到一次上升沿。因此中断服务函数中,我们首先判断是否已经捕获上升沿,如果没,在此情况下发生的第一个捕获事件一定是捕获到上升沿,标记
R
I
S
E
_
G
E
T
=
1
RISE\_GET=1
RISE_GET=1,计数器清零;下次捕获事件的中断一定就是下降沿了,此时标记
S
T
A
=
1
STA=1
STA=1,然后输出此时
T
I
M
5
TIM5
TIM5的计数值。
Codes
#include<stm32f10x.h>
#include<delay.h>
#include<IIC.h>
#include<TM1637.h>
#include<sys.h>
#define Trig PAout(2)
#define LED0 PAout(8)
TIM_ICInitTypeDef TIM5_ICInitStructure;
unsigned char Data[20]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
uint8_t time[4];
u16 STA=0,RISE_GET=0;
u16 TIM5CH1_CAPTURE_VAL;
float ans,time_cost,dis;
int dis_int,dis_res,ans_int,ans_res;
long long tot,temp;
int cnt=0;
void GPIO_Init1(){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_8;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM5_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM5,TIM_IT_CC1,ENABLE);
TIM_Cmd(TIM5,ENABLE );
}
void TIM5_IRQHandler(void)
{
if (RISE_GET){
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){
TIM5CH1_CAPTURE_VAL=TIM_GetCounter(TIM5);
TIM_SetCounter(TIM5,0);
RISE_GET=0;
STA=1;
}
}
else{
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET && !STA){
TIM_SetCounter(TIM5,0);
RISE_GET=1;
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1);
}
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
int main(void)
{
delay_init();
GPIO_Init1();
IIC_Init();
TIM5_Cap_Init(0XFFFF,72-1);
TIM3_PWM_Init(8999,179);
TIM_SetCompare2(TIM3,8995);
while (1)
{
LED0=1;
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);
while (!STA);
dis=TIM5CH1_CAPTURE_VAL/58.0;
dis_int=dis;
LED0=0;
time[0]=Data[dis_int/1000];
time[1]=Data[(dis_int/100)%10];
time[2]=Data[(dis_int%100)/10];
time[3]=Data[(dis_int%10)];
TM_Display(time);
STA=0;
delay_ms(10);
}
}
测试
实际测试结果还是挺令人满意的,系统也十分稳定可靠。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)