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超声波模块的主要内容,如果未能解决你的问题,请参考以下文章

(STM32CubeMX)超声波模块测距传感器学习笔记

基于STM32F103ZET6 HC_SR04超声波测距模块

STM32CubeMX | 39-使用硬件定时器获取超声波模块数据(HC-SR04)

STM32CubeMX | 39-使用硬件定时器获取超声波模块数据(HC-SR04)

基于STM32F103c8t6的智能垃圾桶项目

基于STM32F103c8t6的智能垃圾桶项目