STM32F429使用HC-SR04输出距离到串口助手

本次实验是用HAL库编写定时器捕获程序,来获得距离值,并通过串口助手显示距离值。移植的是原子的实验九输入捕获实验的程序

实验前准备:

  • 阿波罗STM3F429开发板
  • HC-SR04超声波模块
  • 串口调试助手
  • 四根杜邦线

关于HC-SR04超声波测距模块,需要注意看它的时序图,如下:
在这里插入图片描述
可知使用该模块我们需要给至少10us的触发信号,在本实验中我给了20us的触发信号:

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//打开PB6
delay_us(20);//向PB6输入一个长为20us的高电平方波
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);//关闭PB6

而模块内部发出信号是传感器自动回应的,不需要代码去实现。

输出回响信号是通过对输入捕获实现,在向上计数模式下,通过计算高电平的时间,即捕获一次上升沿,清零计数器的值后再捕获一次下降沿的值,根据定时器的计数频率,就可以算出两次捕获的时间,从而得到高电平脉宽,也就得到了距离。(详细请看正点原子STM32F429开发指南-HAL库版本_V1.1——实验九输入捕获实验)

接线如下:

HC-SR04 STM32
VCC -> VCC
Trig -> PB6
Echo -> PA0
GND -> GND

下面贴出我觉得需要注意的地方的代码:

//定时器5初始化
void ultrasound_init()
{
    TIM5_Handler.Instance=TIM5;//定时器5
    TIM5_Handler.Init.Prescaler=90-1;//预分屏系数
    TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数
    TIM5_Handler.Init.Period=0xFFFFFFFF;//自动装载值
    TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //时钟分频因子   
    HAL_TIM_IC_Init(&TIM5_Handler);
    
    TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING;//上升沿捕获
    TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//映射到TI1上
    TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1;//配置输入分频,不分频
    TIM5_CH1Config.ICFilter=0;//配置输入滤波器,不滤波
    HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);
    
    HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1);   //开启TIM5的捕获通道1,并且开启捕获中断
    __HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE);   //使能更新中断
}

//定时器5回调函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM5)
    {        
        __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟
        __HAL_RCC_TIM5_CLK_ENABLE();//使能TIM5时钟
        
        GPIO_Initure.Pin=GPIO_PIN_0;//Pin0
        GPIO_Initure.Mode=GPIO_MODE_AF_PP;//复用推挽输出
        GPIO_Initure.Speed=GPIO_SPEED_HIGH;//高速
        GPIO_Initure.Pull=GPIO_PULLDOWN;//下拉
        GPIO_Initure.Alternate=GPIO_AF2_TIM5;//PA0 复用为 TIM5 通道 1
        HAL_GPIO_Init(GPIOA,&GPIO_Initure);
        
        HAL_NVIC_SetPriority(TIM5_IRQn,2,0); //设置中断优先级,抢占 2,子优先级 0
        HAL_NVIC_EnableIRQ(TIM5_IRQn); //开启 ITM5 中断通道
    }
    
    __HAL_RCC_GPIOB_CLK_ENABLE();  //使能PB时钟
    
    GPIO_InitStructure.Pin= GPIO_PIN_6;
    GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;//推挽输出
    GPIO_InitStructure.Pull=GPIO_PULLUP;//上拉
    GPIO_InitStructure.Speed=GPIO_SPEED_HIGH;//高速
    HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
}

一开始调试的时候我得到的距离是0,后来对比了一下别人的代码,发现我GPIOA的管脚模式选择错了,应该要选择GPIO_MODE_AF_PP(复用推完输出),第二个是 HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1); 开启中断函数弄错了,不知怎么就少写了_IT,导致后面检查才发现没开启中断。实在是太大意了。

接下来是主函数的测距实现:

int main(void)
{      
    long time=0;  
    float Distance;
        
    HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED    
    ultrasound_init(); //以1MHZ的频率计数
        
    while (1)
    {
        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//打开PB6
        delay_us(20);//向PB6输入一个长为20us的高电平方波
        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);//关闭PB6
        //delay_us(20);
        if(TIM5CH1_CAPTURE_STA&0X80)        //成功捕获到了一次高电平
        {
            time=TIM5CH1_CAPTURE_STA&0X3F; 
            time*=0XFFFFFFFF;               //溢出时间总和
            time+=TIM5CH1_CAPTURE_VAL;      //得到总的高电平时间
            Distance=time*340/20000;
            printf("the distance is %.2f cm\r\n",Distance);
            delay_ms(1000);
            TIM5CH1_CAPTURE_STA=0;          //开启下一次捕获
        }
    }
}


Distance=time*340/20000;声音在空气中传播的大约速度为340m/s,而且是一个回传,所以得到的距离还需要除以2才是最后的实际距离。(计算的Distance单位是cm)
详细解释看mc.six的帖子
在这里插入图片描述
实验测出距离如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42827999/article/details/89644157