本人学习过程的记录,如有错误或疏漏麻烦在评论区指出。代码附于最后。
按下WU_ UP (PA0) 按键,使PD0向Trig输出一个15us的高电平,通过PB6(定时器4的一通道)测量Echo返回的高电平的时间。
时序图:
给Trig 引脚一个不小于10us 的高电平,模块内部自动发出8 个40KHz 脉冲,并检测反射回来的脉冲,Echo 引脚返回的高电平长度即为发送脉冲到接收脉冲所花费的时间。
声速约等于0.034cm/us
距离=0.034*时间/2
实际宿舍床长度:1.9*1.2m,测量值与实际值基本相符
后发现实际测量值达不到手册中的4 米,将模块的Echo 引脚接到逻辑分析仪上,直接测量高电平的时间长度,并更换了室友的模块进行对照,认为达不到理论值并不是代码编写的问题,是由于超声波测距仪是声波发射,具有声波的扇形发射特性,所以当声波经过之处障碍物较多时,反射回来的声波较多,干扰较多,易报错。
代码:
timer.c
#include "timer.h"
#include "delay.h"
#include "usart.h"
void TIM4_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM4_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM4时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能GPIOA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 清除之前设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_ResetBits(GPIOD,GPIO_Pin_0);
//初始化定时器4 TIM4
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM4输入捕获参数
TIM4_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM4_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM4, &TIM4_ICInitStructure);
//中断分组初始化
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM4中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
TIM_Cmd(TIM4,ENABLE ); //使能定时器4
}
u16 TIM4CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM4CH1_CAPTURE_VAL; //输入捕获值
//定时器5中断服务程序
void TIM4_IRQHandler(void)
{
if((TIM4CH1_CAPTURE_STA&0X8000)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
if(TIM4CH1_CAPTURE_STA&0X4000)//已经捕获到高电平了
{
if((TIM4CH1_CAPTURE_STA&0X3FFF)==0X3FFF)//高电平太长了
{
TIM4CH1_CAPTURE_STA|=0X8000;//标记成功捕获了一次
TIM4CH1_CAPTURE_VAL=999;
}else TIM4CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM4, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM4CH1_CAPTURE_STA&0X4000) //捕获到一个下降沿
{
TIM4CH1_CAPTURE_STA|=0X8000; //标记成功捕获到一次上升沿
TIM4CH1_CAPTURE_VAL=TIM_GetCapture1(TIM4);
TIM_OC1PolarityConfig(TIM4,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM4CH1_CAPTURE_STA=0; //清空
TIM4CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM4,0);
TIM4CH1_CAPTURE_STA|=0X4000; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM4,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
timer.h
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
void TIM4_Cap_Init(u16 arr,u16 psc);
#endif
main.c
#include "delay.h"
#include "sys.h"
#include "timer.h"
#include "usart.h"
extern u16 TIM4CH1_CAPTURE_STA; //输入捕获状态
extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
u32 temp=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart_init(115200); //串口初始化为115200
TIM4_Cap_Init(1000-1,72-1); // 1000*72/72M=1ms
while(1)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
{
printf("距离为:\n");
GPIO_SetBits(GPIOD,GPIO_Pin_0);
delay_us(15);
GPIO_ResetBits(GPIOD,GPIO_Pin_0);
delay_ms(30);
if(TIM4CH1_CAPTURE_STA&0X8000)//完成捕获
{
temp=TIM4CH1_CAPTURE_STA&0X3FFF;//中断的次数
printf("%d\n",temp);
temp*=1000; //溢出时间总和 72/72000000=1us,
temp+=TIM4CH1_CAPTURE_VAL; //得到总的高电平时间
printf("%d\n",temp);
if(temp>120&temp<26470)
{
temp/=2;
temp*=0.034;
printf("%d cm\n",temp);
}
else
{
printf("ERROR\n");
}
TIM4CH1_CAPTURE_STA=0; //开启下一次捕获
}
delay_ms(500);
}
}
}