嵌入式-定时器的输入捕获,超声波获距实验-Day23
目录
一、输入捕获
1.输入捕获的基本原理
2.输入捕获的内部结构
3.输入滤波
4.边沿检测
5.信号选择
6.分频器
二、超声波测距实验
1.HCSR-04模块的使用方法
2.梳理思路
3.搭建电路
4.USART的IO初始化和模块初始化
5.初始化时基单元
6.初始化输入捕获
7.实现初始化的后续模块
8.代码
一、输入捕获
1.输入捕获的基本原理
当时基单元传进信号时,即时基单元初始化后,将信号也接入通道1和通道2,一个接收脉冲信号的上升沿,一个接收信号的下降沿。
这里的闪 电符号cc1,cc2表示的是发生事件了,即当通道1接收到上升沿然后产生事件cc1,然后会拍照保存CNT的值到CCR1寄存器里面,同理cc2的事件发生也会执行步数保存,那这两保存的数据相减就得到了这个波形的脉宽。
2.输入捕获的内部结构
3.输入滤波
滤除毛刺,即去除噪声、
4.边沿检测
就是检测边沿的
5.信号选择
信号分为直接,间接(来源于一对通道,比如1和2,3和4是互为一对)。TRC后面学
间接的优势:
如果没有间接的话,测量一个脉宽。即需要测量上升沿和下降沿正常要两引脚,但是有了间接就可以光使用一个引脚,使用直接的方法走通道1的上升沿检测,使用间接走通道2的下降沿检测。这样就比正常的能空闲出一个引脚来。
6.分频器
比如设置分频为4,那么当传输了4次上身沿后才出现cc1的事件。即控制事件出现的频率
二、超声波测距实验
关键器件:超声波测距传感器HC-SR04.
1.HCSR-04模块的使用方法
1. HC-SR04 的引脚
VCC:电源,5V
GND:地
Trig:触发引脚(输入)
Echo:回响引脚(输出)
2. 工作流程(看图对应理解)
触发 (Trig)
给 Trig 引脚一个 大于 10 微秒 的高电平脉冲。
这就相当于告诉模块:“开始发射超声波”。
发射 (超声波)
模块会自动发射 8 个 40kHz 的超声波脉冲(持续时间大约 200 微秒左右)。
发射之后,模块就开始“监听”反射回来的超声波。
回响 (Echo 输出高电平)
当发射完超声波之后,模块会立即拉高 Echo 引脚。
当检测到超声波的回声后(即目标物体反射的超声波返回时),Echo 引脚拉低。
所以,Echo 引脚高电平的时间长度,就是超声波往返目标物体的时间。
测距公式
声速取 340 m/s(空气中)。
超声波走的是 往返路程,所以要除以 2。
公式就是:
距离=(时间×声速 ) / 2
3. 为什么用脉冲来测?
Echo 脉冲的 宽度(时间长短) 就是“声波飞出去再回来”所花的时间。
只要测量 这个脉冲的宽度,就能算出目标物体的距离。
2.梳理思路
从上下两图可以看到,整体的执行流程就是:
0.初始化USART、时基单元、输入捕获通道。
1.对CNT清零。因为如果CNT不清零,可能会发生重新计数,导致不能正确记录时间。比如上边沿97-ARR的100-清零0-下边沿20这个,20到97不好记录时间
2.对cc1和cc2标志位清零
3.开启定时器。注意:当时基单元的开关一闭合就要开始计数了,即CNT开始加了
4.给传感器的Trig引脚发送脉冲,随便一个单片机正常的引脚都可以,只要能给传感器的Trig发送任意大于10us的脉冲信号就行,表示要开始启动了。
由于启动了,传感器自动发送声波,发送后,Echo就输出,注意是输出,高电压,知道传感器接收声波结束,Echo拉低电压表示结束。——那这个有啥用,就是用来测距离的,他底层就是这么测的,使用自己记录的这个高电压变化即脉冲信号,可以记录当前传感器和障碍物的距离。
5.等待cc1的变化和cc2的变化。因为需要拿他两的时间差t,去算出前面没算完的距离。
6.关闭定时器
3.搭建电路

4.USART的IO初始化和模块初始化
5.初始化时基单元
初始化的值默认定时器是传入的72MHz,但是分辨率和周期怎么选择。
网上查找这个传感器的精度最高3mm,那就是最高对应着8us,所以分辨率必须小于8us,那越小越好,但不能太小的话,就取1us。
周期当然越大越好,因为不知道这个要测的脉冲信号的对应的时间多少,但因为就怕出现到达ARR极限值然后归0导致你测不了脉宽即时间,所以周期选择 设备支持的最大的2的16次,因为定时器的时基单元默认是16位的寄存器。
6.初始化输入捕获
这里不一定要遵循手册,因为Echo默认是低电压,所以可以设置对接的引脚为输入下拉,默认也是低电压。
首先初始化输入的IO引脚
之后初始化输入通道1和2(即实现了一个引脚,两个通道的使用)
7.实现初始化的后续模块
8.代码
#include "stm32f10x.h"
#include "Delay.h"#include "usart.h"void App_USART_Init(void);
void App_TimeBase_Init(void);
void App_IC_Init(void);int main(void)
{//传感器测距 //首先初始化USART、时基单元、输入捕获App_USART_Init();App_TimeBase_Init();App_IC_Init();TIM_SetCounter(TIM1,0);TIM_ClearFlag(TIM1,TIM_FLAG_CC1);TIM_ClearFlag(TIM1,TIM_FLAG_CC2);TIM_Cmd(TIM1,ENABLE);//给传感器发送启动信号GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);DelayUs(10);GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);while(1){while(TIM_GetFlagStatus(TIM1,TIM_FLAG_CC1)==RESET || TIM_GetFlagStatus(TIM1,TIM_FLAG_CC2)==RESET);uint16_t cc1=TIM_GetCapture1(TIM1);uint16_t cc2=TIM_GetCapture1(TIM2);float end=(cc2-cc1)*(1.0e-6f)*340.0f/2;My_USART_Printf(USART1,"%.3f\n",end*100);Delay(100);}
}void App_USART_Init(){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//这里只是往串口调试工具发数据,所以不用定义RxGPIO_InitTypeDef GPIO_InitStruct={0};GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);USART_InitTypeDef USART_InitStruct={0};USART_InitStruct.USART_BaudRate=115200;USART_InitStruct.USART_Mode=USART_Mode_Tx;USART_InitStruct.USART_Parity=USART_Parity_No;USART_InitStruct.USART_StopBits=USART_StopBits_1;USART_InitStruct.USART_WordLength=USART_WordLength_8b;USART_Init(USART1,&USART_InitStruct);}
void App_TimeBase_Init(){//RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);//默认是72MHz,选择分辨率1us,周期25535+1TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct={0};TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period=25535;TIM_TimeBaseInitStruct.TIM_Prescaler=71;TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);//开启预加载TIM_ARRPreloadConfig(TIM1,ENABLE);//顺便也把CCRx的预加载也打开TIM_CCPreloadControl(TIM1,ENABLE);}//初始化输入
void App_IC_Init(){//初始化一个输入引脚RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStrut={0};GPIO_InitStrut.GPIO_Mode=GPIO_Mode_IPD;GPIO_InitStrut.GPIO_Pin=GPIO_Pin_0;GPIO_InitStrut.GPIO_Speed=GPIO_Speed_2MHz;GPIO_Init(GPIOA,&GPIO_InitStrut);//初始化两通道TIM_ICInitTypeDef IC_InitStruct={0};IC_InitStruct.TIM_Channel=TIM_Channel_1;IC_InitStruct.TIM_ICFilter=1;IC_InitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;IC_InitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;IC_InitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;TIM_ICInit(TIM1,&IC_InitStruct);IC_InitStruct.TIM_Channel=TIM_Channel_2;IC_InitStruct.TIM_ICFilter=1;IC_InitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;IC_InitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;IC_InitStruct.TIM_ICSelection=TIM_ICSelection_IndirectTI;TIM_ICInit(TIM1,&IC_InitStruct);}