1.输入捕获
原子哥的输入捕获实验
1.1 输入捕获原理
输入捕获模式可以用来测量脉冲宽度或者测量频率。 我们以测量脉宽为例,用一个简图来说明输入捕获的原理,如图: 输入捕获测量高电平脉宽的原理,假定定时器工作在向上计数模式,图中 t1~t2 时间,就是我们需要测量的高电平时间。 测量方法如下:首先设置定时器通道 x 为上升沿捕获,这样,t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。 这样,根据定时器的计数频率,我们就可以算出 t1~t2 的时间,从而得到高电平脉宽。 在 t1~t2 之间,可能产生 N 次定时器溢出,这就要求我们对定时器溢出,做处理,防止高电平太长,导致数据不准确。如图所示, t1~t2之间, CNT计数的次数等于: N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。
1.2 摘自【STM32】HAL库 STM32CubeMX教程八—定时器输入捕获
链接摘自【STM32】HAL库 STM32CubeMX教程八—定时器输入捕获
输入捕获的工作流程(对应CubeMx的四个选项)
1.设置输入捕获滤波器 STM32在很多功能中都提供了滤波器,滤波器的功能简单来说就是多次检测视为一次有效,达到滤波效果, 数字滤波器由一个事件计数器组成,假设我们是检测高电平,滤波N次,那么记录到N个事件后计数器会产生一个输出的跳变。也就是说连续N次采样检测,如果都是高电平,则说明这是一个有效的电平信号,这样便可以过滤掉那些因为某些而干扰产生的一些信号 输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度。其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1的CKD[1:0]的设置来确定的。 2.设置输入捕获极性 设置具体为那种捕获事件 可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获 3.设置输入捕获映射关系 STM32为了更好的优化使用,TIMx_CH1通道1捕捉到的信号可以传输到IC1,TIMx_CH1捕捉到的信号也可以连接到IC2,TIMx_CH2捕捉到的信号也可以连接到IC2,也可以连接到IC2
4.设置输入捕获分频器 设置每N个事件触发一次捕获,可以设置为1/2/4/8次检测到电平变化才触发捕获
1.3 原理总结
STM32F4 的输入捕获,简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值( TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
1.4 配置工程和编写代码
这里我们选择TIM5的通道1
预分频系数为71 计数时钟频率就是 72MHz/(71+1) = 1MHz 此时1us计数一次 自动加载值设置为16bit最大值 上升沿捕获 不分频 滤波值为8 同时在NVIC一栏使能TIM5的中断
开启串口1。
uint32_t capture_Buf[3] = {0};
uint8_t capture_Cnt = 0;
uint32_t high_time;
switch (capture_Cnt)
{
case 0:
capture_Cnt++;
__HAL_TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1);
break;
case 3:
high_time = capture_Buf[1]- capture_Buf[0];
HAL_UART_Transmit(&huart1, (uint8_t *)high_time, 1, 0xffff);
HAL_Delay(1000);
capture_Cnt = 0;
break;
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(TIM5 == htim->Instance)
{
switch(capture_Cnt){
case 1:
capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);
capture_Cnt++;
break;
case 2:
capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);
HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1);
capture_Cnt++;
}
}
}
1.5 原理分析和现象观察
1.原理分析: 代码逻辑:摘自【STM32】HAL库 STM32CubeMX教程八—定时器输入捕获
硬件逻辑: 定时器5的输入捕获通道一对应的GPIO是PA0-WKUP。
而开关摁下后,是一个上升沿。松开时,是一个下降沿,结合代码逻辑,很容易理解。测试的是摁键摁下的时间。
按下KEY_UP。
1.6 输入捕获函数补充
1.7 代码分享
输入捕获实验 提取码:3ozl
2.超声波HC-SR04模块
参考博客:STM32CubeMX | 39-使用硬件定时器获取超声波模块数据(HC-SR04)
2.1 基本工作原理
HC-SR04超声波测距模块可提供2cm- 400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。 基本工作原理: (1)采用I0口TRIG触发测距,给最少10us的高电平信呈。 (2)模块自动发送8个40khz的方波,自动检测是否有信号返回; (3)有信号返回,通过I0口ECHO输出- -一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离= (高电平时间*声速(340M/S))/2; 知道d和L,勾股定理就能算出S。
2.2 实物图和接线
void HC_SR04_Init(hc_sr04_device_t *hc_sr04_device)
{
hc_sr04_device1.trig_port = GPIOB;
hc_sr04_device1.trig_pin = GPIO_PIN_8;
hc_sr04_device1.echo_port = GPIOB;
hc_sr04_device1.echo_pin = GPIO_PIN_9;
hc_sr04_device1.tim = &htim2;
}
这里我设置的Trig和Echo分别为PB8,PB9。
HC-SR04超声波模块 | STM32 |
---|
VCC | 5V(必须是5V) | GND | GND | Trig | 触发控制信号输入PB8 | Echo | 回响信号输出PB9 |
2.3 超声波时序图
以上时序图表明你只需要提供一一个 10uS以上脉冲触发信号,该模块内部将发出8个40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。 回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式: uS/58=厘米或者uS/148=英寸;或是:距离=高电平时间*声速(340M/S) /2;建议测量周期为60ms以上,以防止发射信号对回响信号的影响。
2.4 配置工程
1.配置GPIO
1)配置两个普通的GPIO,一个配置为输出模式,用于连接模块的Trig引脚,触发一次测距,这里我配置为PB8,另一个配置为输入模式(浮空),用于连接模块的Echo引脚,接收echo信号,这里我配置为PB9。
2.配置通用定时器TIM2
接下来开始配置TIM2,首先选择TIM2,我们的目的是每1us计数一次 ,所以定时器的频率需要在1Mhz, 时钟源选择内部时钟:
3.配置时钟树
STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz即可:
2.5 编写代码和分享
2.5.1printf重定向
#include "stdio.h"
int fputc(int c,FILE *stream)
{
uint8_t ch[1]={c};
HAL_UART_Transmit(&huart1,ch,1,0xFFFF);
return c;
}
2.5.2 添加us级延时函数
一种Cortex-M内核中的精确延时方法
2.5.3 编写驱动
参考博客
int HC_SR04_Measure(hc_sr04_device_t *hc_sr04_device)
{
uint32_t tick_us;
HC_SRO4_Mutex_Pend();
HC_SR04_Start(hc_sr04_device);
__HAL_TIM_SetCounter(hc_sr04_device->tim, 0);
while (HAL_GPIO_ReadPin(hc_sr04_device->echo_port, hc_sr04_device->echo_pin) == GPIO_PIN_RESET);
HAL_TIM_Base_Start(hc_sr04_device->tim);
while (HAL_GPIO_ReadPin(hc_sr04_device->echo_port, hc_sr04_device->echo_pin) == GPIO_PIN_SET);
HAL_TIM_Base_Stop(hc_sr04_device->tim);
tick_us = __HAL_TIM_GetCounter(hc_sr04_device->tim);
hc_sr04_device->distance = (double)(tick_us/1000000.0) * 340.0 / 2.0 *100.0;
HC_SRO4_Mutex_Post();
return 0;
}
这个是利用定时器来实现计时的。并在while中不断执行Measure。
2.5.4测试结果
int ret;
extern hc_sr04_device_t hc_sr04_device1;
HC_SR04_Init(&hc_sr04_device1);
while (1)
{
ret = HC_SR04_Measure(&hc_sr04_device1);
}
在监视窗口中可以看到distance的数据。单位是cm。 代码分享 提取码:x6sx
2.6 注意事项
1、此模块不宜带电连接,若要带电连接,则先让模块的GND端先连接,否则会影响 模块的正常工作。 2、测距时,被测物体的面积不少于0.5平方米且平面尽量要求平整,否则影响测量的 结果。
3.基于输入捕获的超声波HC-SR04模块使用
第二部分是利用定时器来实现计时的,并在while中不断执行Measure。而.基于输入捕获的超声波HC-SR04模块使用,使我们摆脱在while中重复测量。原理在输入捕获中已经讲解,直接开始吧!
3.1 配置工程
TIM2配置为10ms计数一次,看清时钟主频。 TIM1的通道1设置为输入捕获,每隔10us捕获一次,看清时钟主频。 Echo接输入捕获通道的GPIO,即PE9。
NVIC选项卡打开中断。 开启GPIO。作为Trig的输出通道,PC6。
3.2 代码编写
修改宏定义中的时钟主频和GPIO。
#define CPU_FREQUENCY_MHZ 168
#define SAMPLENUM 10
#define Trig(state) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6, (GPIO_PinState)(state))
#define Echo HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_9)
#define RELOADVALUE 0xffff
详情可观看另一篇博客。(等等更)
3.3 实验观察
打开debug,观察distance。
|