STM32L431CubeMX使用使用HC_SR04超声波模块测量距离并通过串口打印
参考文章:
【STM32】HAL库 STM32CubeMX教程八—定时器输入捕获
一、开发平台
·小熊派(STM32L431)
·HC_SR04超声波模块
·keil5
·cubemx
·使用HAL库
二、HC_SR04介绍
·实物图:
·基本工作原理
通过时序图可知,需要在TRIG的IO口上给出10us及以上的高电平信号,模块内部自动发出8个40KHz脉冲,自动检测是否有信号返回,若有信号返回,测量高电平在ECHO的IO口中输出的时间,测量距离 = (ECHO高电平输出时间*声速(340M/s)/2),建议测量周期在60ms(大约2.5cm)以上,否则测距功能会失效。
三、CubeMX配置
·选择芯片
RCC选择外部高速时钟
配置SYS
配置时钟树,stm32l431最大时钟频率为80MHz
配置USART,按默认配置,引脚默认在PA9,PA10。
配置TIM2时钟
·预分频填80-1,时钟计数频率 = 80MHz/PSC+1=1Mhz ,即计数频率为1us
·上升沿捕获
·自动装载值设置为32Bit最大值 65535
·并在NVIC设置中使能TIM2中断
配置GPIO,配置PB9作为TRIG,默认输出低电平
设置路径,工程名称,编译器
勾选代码生成
四、keil5代码部分
1、printf重定向
首先勾选Use MicroLIB调用MDK的微库,MicroLIB是对C标准库高度优化之后的库,比标准库代码更少,使用效率更高。
在usart.c文件最后加上代码,这里不使用HAL库函数HAL_UART_Transmit来发送数据,直接操作寄存器来发送,效率更高。
/* USER CODE BEGIN 1 */
#if 1
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
/* 堵塞判断串口是否发送完成 */
while((USART1->ISR & 0X40) == 0);
/* 串口发送完成,将该字符发送 */
USART1->TDR = (uint8_t) ch;
return ch;
}
#endif
/* USER CODE END 1 */
2、创建HC_SR04.c/.h文件
3、HC_SR04.h
·为了防止头文件重复定义
#ifndef __HC_SR04_H__
#define __HC_SR04_H__
#endif
·添加所需头文件
#ifndef __HC_SR04_H__
#define __HC_SR04_H__
#include "stm32l4xx_hal.h"
#include "tim.h"
#include "usart.h"
#include <stdio.h>
#endif
·定义TRIG高电平与低电平
#define TRIG_L HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)
#define TRIG_H HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)
·声明函数
void delay_us(uint16_t us);
void Get_Distance(void);
4、HC_SR04.c
·包含头文件以及定义变量
#include "HC_SR04.h"
float distance; //测量距离
uint32_t capture_value1; //存放定时器捕获值数组
uint32_t capture_value2;
uint8_t cnt=0; //状态计数值
·HC_SR04模块需要用到us级延时,而HAL库中的HAL_Delay只支持ms级延时,所以自己实现us延时
void delay_us(uint16_t us)
{
uint16_t differ = 0xffff-us-5;
__HAL_TIM_SET_COUNTER(&htim2,differ); //设定TIM2计数器起始值
HAL_TIM_Base_Start(&htim2); //启动定时器
while(differ < 0xffff-5){ //判断
differ = __HAL_TIM_GET_COUNTER(&htim2); //查询计数器的计数值
}
HAL_TIM_Base_Stop(&htim2);
}
·根据时序图可知
/*
HC_SR04启动函数:触发信号顺序
给TRIG一个低电平,延时10us以上,再给TRIG一个高电平
*/
void HC_SR04_Start(void)
{
TRIG_L;
delay_us(20);
TRIG_H;
}
·tim中断回调函数
/*中断回调函数*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//
{
if(TIM2 == htim->Instance)// 判断触发的中断的定时器为TIM2
{
switch(cnt){
case 1:
capture_value1 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //设置为下降沿捕获
cnt++;
break;
case 2:
capture_value2 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_1); //停止捕获 或者: __HAL_TIM_DISABLE(&htim2);
cnt++;
}
}
}
·获得测量后的距离
/*
获取HC_SR04测出与目标之间的距离
*/
void Get_Distance(void)
{
uint16_t measure;
switch(cnt){
case 0:
HC_SR04_Start();
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); //启动输入捕获 或者: __HAL_TIM_ENABLE(&htim5);
cnt++;
break;
case 3:
measure = capture_value2-capture_value1;
distance = (measure*0.034)/2;
printf("距离为%f cm\r\n",distance);
cnt = 0;
TIM2->CNT = 0;
break;
}
}
实现以上功能的流程
1.设置TIM2 CH1为输入捕获功能;
2.设置上升沿捕获;
3.使能TIM2 CH1捕获功能;
4.捕获到上升沿后,定时器当前计数值存入capture_value1,改为捕获下降沿;
5.捕获到下降沿后,定时器当前计数值存入存入capture_value2,关闭TIM2 CH1捕获功能; cnt=3;
6. 高电平时间: capture_value2 - capture_value1 重新启动输入捕获
__HAL_TIM_SET_COUNTER(&TIM2_Handler,0); //设置计数寄存器的值变为0
HAL_TIM_PWM_Start() 函数用于使能定时器某一通道的PWM输出。
HAL_TIM_IC_Start_IT() 函数用于使能定时器某一通道的输入捕获功能,并使能相应的中断
HAL_TIM_IC_Stop_IT() 函数和开启功能相反,是关闭定时器某一通道的输入捕获功能和相应中断
__HAL_TIM_SET_CAPTUREPOLARITY不是函数,而是底层操作的一个宏定义
在stm32l4xx_hal_tim.h文件中可以找到。其作用是修改定时器某一通道的输入捕获极性
其中有两个函数,第一个为清除清除原来的捕获极性,第二个为设置通道捕捉极性
TIM_RESET_CAPTUREPOLARITY(&TIM2_Handler,TIM_CHANNEL_1); //一定要先清除原来的捕获极性!!
TIM_SET_CAPTUREPOLARITY(&TIM2_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器2通道1设置为下降沿捕获(重设捕获极性)
在修改定时器某一通道的输入捕获极性时,一定要先清除该通道之前捕获极性
__HAL_TIM_GET_COMPARE也是一个宏定义。
在stm32l4xx_hal_tim.h文件中可以找到。其作用是获取定时器某一通道的捕获/比较寄存器值,等价于 : HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
两者都是直接读取对应CCRx寄存器的值
5、main.c
在main函数的循环中添加
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Get_Distance();
HAL_Delay(500);
}
/* USER CODE END 3 */
五、接线
HC_SR04 | 开发板 |
---|---|
VCC | 5V |
TRIG | PB9 |
ECHO | PA0 |
GND | GND |
六、串口打印效果
作者能力有限,如有出错,希望各位大佬帮忙指出,谢谢