MCU主控:
STM32L051C8T6
超声波模块:
RCWL-1601
基本工作原理:
1、采用IO口TRIG触发测距,给至少10us的高电平信号;
2、模块自动发送8个40khz的方波,自动检测是否有信号返回;
3、有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;
本模块使用方法简单,一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出.一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,即可以得到你移动测量的值。超声波模块时序图如下:
输入捕获可以用来测量脉冲宽度或者测量频率。超声波用到的是测量脉宽,这里我以测量脉宽为例,用一个简图来说明输入捕获的原理,如下图:
如上图所示,就是输入捕获测量高电平脉宽的原理,假定定时器工作在向上计数模式,图中t1-t2时间,就是我们需要测量的高电平时间。测量方法如下:首先设置定时器通道x为上升沿捕获,这样,t1时刻就会捕捉到CNT值,然后立即清零CNT,并设置通道x为下降沿捕获,这样t2时刻又会发生捕获事件,得到此时的CNT值,记为CCRx2。这样,根据定时器的计数频率,我们就可以算出t1-t2的时间,从而得到高电平的脉宽。
在t1-t2之间,可能产生N次定时器溢出,这就要求我们对定时器溢出做处理,防止高电平太长,导致数据不准确。如上图所示,t1-t2之间CNT计数的的次数等于:N*ARR+CRRx2,有了这个计数次数,再乘以CNT的计数周期,即可得到t1-t2的时间长度,即高电平持续时间。
2、STM32CubeMx 配置
1)、系统时钟配置
2)、定时器22配置
3)、串口1配置
3、代码说明:
tim.c文件
/* USER CODE BEGIN 0 */
#include "stdio.h"
uint8_t text_flag = 0;
uint8_t dis_fm = 0;
uint8_t Channel2Edge = 0;
uint16_t Channel2HighTime, Channel2RisingTime, Channel2FallingTime;
/* USER CODE END 0 */
.....
/* USER CODE END 1 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
/*防止未使用参数(s)编译警告*/
UNUSED(htim);
if(htim->Instance == htim22.Instance)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(Channel2Edge == 0) //捕获上升沿
{
Channel2RisingTime = HAL_TIM_ReadCapturedValue(&htim22, TIM_CHANNEL_2); //获取上升沿时间点
__HAL_TIM_SET_CAPTUREPOLARITY(&htim22, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); //切换捕获极性
HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2); //切换捕获极性后需重新启动
Channel2Edge = 1; //上升沿、下降沿捕获标志位
}
else if(Channel2Edge == 1) //捕获下降沿
{
Channel2FallingTime = HAL_TIM_ReadCapturedValue(&htim22, TIM_CHANNEL_2); //获取下降沿时间点
__HAL_TIM_SET_CAPTUREPOLARITY(&htim22, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); //切换捕获极性
HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2); //切换捕获极性后需重新启动
Channel2HighTime = Channel2FallingTime < Channel2RisingTime ? Channel2FallingTime + 0xffff - Channel2RisingTime + 1 : Channel2FallingTime - Channel2RisingTime;
//高电平持续时间 = 下降沿时间点 - 上升沿时间点
dis_fm = Channel2HighTime * 17 / 100; //计算超声波测量距离
printf("dis_fm = %dcm \r\n", dis_fm);
//i++;//累加计数
Channel2Edge = 0; //一次采集完毕,清零
}
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}
}
/* USER CODE END 1 */
usart.c文件
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
....
/* USER CODE BEGIN 1 */
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 1 */
main.c文件
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void Delay_us(uint32_t t)//64M条件下的一微妙
{
int n = 11;
while(--t)
{
while(--n);
n = 11;
}
}
void gases_start_signal(void)
{
unsigned char i=0;
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
//延时20us
Delay_us(20);
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
/* USER CODE END 0 */
....
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);
/* USER CODE END 2 */
....
/* USER CODE BEGIN WHILE */
while (1)
{
//ADC_GetValue();
gases_start_signal();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
串口助手打印结果:
代码连接