STM32--HC-SR04超声波模块
Posted yasina
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32--HC-SR04超声波模块相关的知识,希望对你有一定的参考价值。
工作电压:5V
原理:给TR口一个>10us的高电平 ,开始工作·,超声波与障碍物后反弹,EC口会输出一个持续的高电平 ,这个高电平的持续时间就是声波在空气中传播的时间
公式:dis=T*声速/2 dis:距离 T: EC高电平持续时间
可以用外部中断或者定时器输入捕获来测量时间
本文采用输入捕获 TR--PA1 EC--PA0--tim2ch1
定时器初始化
1 //EC--PA0--T2CH1 TR--PA1
2 //定时器2通道1输入捕获配置
3 TIM_ICInitTypeDef TIM2_ICInitStructure;
4
5 void TIM2_Cap_Init(u16 arr,u16 psc)
6 {
7 GPIO_InitTypeDef GPIO_InitStructure;
8 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
9 NVIC_InitTypeDef NVIC_InitStructure;
10
11 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2时钟
12 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
13
14 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
16 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
17 GPIO_Init(GPIOA, &GPIO_InitStructure);
18 GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
19
20 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
21 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
22 GPIO_Init(GPIOA, &GPIO_InitStructure);
23
24
25 //初始化定时器2 TIM2
26 TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
27 TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
28 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
29 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
30 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
31
32 //初始化TIM2输入捕获参数
33 TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
34 TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
35 TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
36 TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
37 TIM2_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
38 TIM_ICInit(TIM2, &TIM2_ICInitStructure);
39
40 //中断分组初始化
41 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
42 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
43 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
44 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
45 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
46
47 TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
48
49 TIM_Cmd(TIM2,ENABLE ); //使能定时器2
50
51 }
中断服务函数
u8 TIM2CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM2CH1_CAPTURE_VAL; //输入捕获值
//定时器5中断服务程序
void TIM2_IRQHandler(void)
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM2CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM2CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM2CH1_CAPTURE_STA=0; //清空
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
模块初始化:
u32 HC_SR04(void)
{
PAout(1)=1;
Delay_us(15);
PAout(1)=0;
Delay_us(6000);
u32 temp;
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=65536; //溢出时间总和
temp+=TIM2CH1_CAPTURE_VAL; //得到总的高电平时间
TIM2CH1_CAPTURE_STA=0; //开启下一次捕获
return temp;
}
u32 aHC_SR04(void)
{
u32 atemp=0;
int i;
for(i=0;i<9;i++)
atemp+=HC_SR04();
return atemp/10;
}
main.c
int main(void)
{
u32 temp=0;
int dis;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
delay_init(); //延时函数初始化
uart_init(9600); //9600
TIM2_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数
while(1)
{
temp=aHC_SR04();
dis=(int)temp*340/20000;
printf("主函数时间%d 距离:%dcm
",temp,dis);
Delay_ms(500);
}
}
可以实现测距 但还需要后期改进。
问题一、这里用了u32 aHC_SR04(void)来求10次测距的平均值;本来早就写好了 但在调试中发现了一些问题 我用的时正点原子的定时器例程改的
里面的delay_ms() delay_us()函数貌似有问题 调用原子哥的延时函数总是计时=0;不知道原因,如有大神知道,请指教。
所以我自己写了个软件延时函数;
问题二、网上大多数的利用输入捕获 超声波测距的例子中,都对定时器设置了溢出值。但我认为没有必要;本例中超声波模块最多测400cm,若声波在0度空气中传播332m/s,即4m最多12ms,而TIM2工作在1MHZ的频率,
即1us 自动重装载值65535,65535*0.000332=22.08M,远远大于4m,所以一般情况下不用溢出处理
以上是关于STM32--HC-SR04超声波模块的主要内容,如果未能解决你的问题,请参考以下文章
基于STM32F103ZET6 HC_SR04超声波测距模块
STM32CubeMX | 39-使用硬件定时器获取超声波模块数据(HC-SR04)