历史上的今天
今天是:2024年10月28日(星期一)
2021年10月28日 | stm32专题二十六:输入捕获 脉宽测量
2021-10-28 来源:eefocus
硬件设计:

脉宽测量原理:
当按键没有按下时,由硬件电路自动拉低。如果按键按下,则PA0产生上升沿,我们进行脉宽测量时,首先设置为上升沿捕获,然后在第一次捕获到上升沿时,将计数器清零,并设置捕获极性为下降沿捕获。当第二次捕获到信号时,就是一个完整的高电平时间。值得注意的是,如果定时器溢出频率为72M(预分频系数71)时,最大计数值为65536us,要考虑溢出(更新中断)。
代码如下,非常简单。
bsp_GeneralTim.c
#include "bsp_GeneralTim.h"
// 定时器输入捕获用户自定义变量结构体定义
TIM_ICUserValueTypeDef TIM_ICUserValueStructure = {0, 0, 0, 0};
// 中断优先级配置
static void GENERAL_TIM_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 设置中断组为0
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
// 设置中断来源
NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQ ;
// 设置主优先级为 0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// 设置抢占优先级为3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static void GENERAL_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 输入捕获通道 GPIO 初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);
}
static void GENERAL_TIM_Mode_Config(void)
{
// 开启定时器时钟,即内部时钟CK_INT=72M
GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
/*--------------------时基结构体初始化-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD;
// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_PSC;
// 时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
// 初始化定时器
TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
/*--------------------输入捕获结构体初始化-------------------*/
TIM_ICInitTypeDef TIM_ICInitStructure;
// 配置输入捕获的通道,需要根据具体的GPIO来配置
TIM_ICInitStructure.TIM_Channel = GENERAL_TIM_CHANNEL_x;
// 输入捕获信号的极性配置
TIM_ICInitStructure.TIM_ICPolarity = GENERAL_TIM_STRAT_ICPolarity;
// 输入通道和捕获通道的映射关系,有直连和非直连两种
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
// 输入的需要被捕获的信号的分频系数
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
// 输入的需要被捕获的信号的滤波系数
TIM_ICInitStructure.TIM_ICFilter = 0;
// 定时器输入捕获初始化
TIM_ICInit(GENERAL_TIM, &TIM_ICInitStructure);
// 清除更新和捕获中断标志位
TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update|GENERAL_TIM_IT_CCx);
// 开启更新和捕获中断
TIM_ITConfig (GENERAL_TIM, TIM_IT_Update | GENERAL_TIM_IT_CCx, ENABLE );
// 使能计数器
TIM_Cmd(GENERAL_TIM, ENABLE);
}
void GENERAL_TIM_Init(void)
{
GENERAL_TIM_NVIC_Config();
GENERAL_TIM_GPIO_Config();
GENERAL_TIM_Mode_Config();
}
bsp_GeneralTim.h
#ifndef __BSP_ADVANCETIM_H
#define __BSP_ADVANCETIM_H
#include "stm32f10x.h"
/************通用定时器TIM参数定义,只限TIM2、3、4、5************/
// 当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意
// 我们这里默认使用TIM5
#define GENERAL_TIM TIM5
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM5
#define GENERAL_TIM_PERIOD 0XFFFF
#define GENERAL_TIM_PSC (72-1)
// TIM 输入捕获通道GPIO相关宏定义
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_0
#define GENERAL_TIM_CHANNEL_x TIM_Channel_1
// 中断相关宏定义
#define GENERAL_TIM_IT_CCx TIM_IT_CC1
#define GENERAL_TIM_IRQ TIM5_IRQn
#define GENERAL_TIM_INT_FUN TIM5_IRQHandler
// 获取捕获寄存器值函数宏定义
#define GENERAL_TIM_GetCapturex_FUN TIM_GetCapture1
// 捕获信号极性函数宏定义
#define GENERAL_TIM_OCxPolarityConfig_FUN TIM_OC1PolarityConfig
// 测量的起始边沿
#define GENERAL_TIM_STRAT_ICPolarity TIM_ICPolarity_Rising
// 测量的结束边沿
#define GENERAL_TIM_END_ICPolarity TIM_ICPolarity_Falling
// 定时器输入捕获用户自定义变量结构体声明
typedef struct
{
uint8_t Capture_FinishFlag; // 捕获结束标志位
uint8_t Capture_StartFlag; // 捕获开始标志位
uint16_t Capture_CcrValue; // 捕获寄存器的值
uint16_t Capture_Period; // 自动重装载寄存器更新标志
}TIM_ICUserValueTypeDef;
extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure;
/**************************函数声明********************************/
void GENERAL_TIM_Init(void);
#endif /* __BSP_ADVANCETIM_H */
以上是一些结构体配置,然后比较重要的是中断服务函数:
void GENERAL_TIM_INT_FUN(void)
{
// 当要被捕获的信号的周期大于定时器的最长定时时,定时器就会溢出,产生更新中断
// 这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去
if ( TIM_GetITStatus ( GENERAL_TIM, TIM_IT_Update) != RESET )
{
TIM_ICUserValueStructure.Capture_Period ++;
TIM_ClearITPendingBit ( GENERAL_TIM, TIM_FLAG_Update );
}
// 上升沿捕获中断
if ( TIM_GetITStatus (GENERAL_TIM, GENERAL_TIM_IT_CCx ) != RESET)
{
// 第一次捕获
if ( TIM_ICUserValueStructure.Capture_StartFlag == 0 )
{
// 计数器清0
TIM_SetCounter ( GENERAL_TIM, 0 );
// 自动重装载寄存器更新标志清0
TIM_ICUserValueStructure.Capture_Period = 0;
// 存捕获比较寄存器的值的变量的值清0
TIM_ICUserValueStructure.Capture_CcrValue = 0;
// 当第一次捕获到上升沿之后,就把捕获边沿配置为下降沿
GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Falling);
// 开始捕获标准置1
TIM_ICUserValueStructure.Capture_StartFlag = 1;
}
// 下降沿捕获中断
else // 第二次捕获
{
// 获取捕获比较寄存器的值,这个值就是捕获到的高电平的时间的值
TIM_ICUserValueStructure.Capture_CcrValue =
GENERAL_TIM_GetCapturex_FUN (GENERAL_TIM);
// 当第二次捕获到下降沿之后,就把捕获边沿配置为上升沿,好开启新的一轮捕获
GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Rising);
// 开始捕获标志清0
TIM_ICUserValueStructure.Capture_StartFlag = 0;
// 捕获完成标志置1
TIM_ICUserValueStructure.Capture_FinishFlag = 1;
}
TIM_ClearITPendingBit (GENERAL_TIM,GENERAL_TIM_IT_CCx);
}
}
在主函数中进行测试:
main.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_GeneralTim.h"
#include void delay(uint32_t count); int main(void) { uint32_t time; // TIM 计数器的驱动时钟 uint32_t TIM_PscCLK = 72000000 / (GENERAL_TIM_PSC + 1); /* 串口初始化 */ USART_config(); GENERAL_TIM_Init(); printf ( "STM32 输入捕获测试rn" ); printf ( "按下K1,测试K1按下的时间rn" ); while (1) { if(TIM_ICUserValueStructure.Capture_FinishFlag == 1) { // 计算高电平时间的计数器的值 time = TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD+1) + (TIM_ICUserValueStructure.Capture_CcrValue+1); // 打印高电平脉宽时间 printf ( "rn测得高电平脉宽时间:%d.%d srn",time/TIM_PscCLK,time%TIM_PscCLK ); TIM_ICUserValueStructure.Capture_FinishFlag = 0; } } } 测试结果为:
史海拾趣
|
本信息来自合作QQ群:AVR单片机学习与交流群(17727270) 群管理员在坛子里的ID:铜河 100M、4通道,2G采样,25k记录 据说,这个虽然是100M,但实测是200M… 查看全部问答> |
|
大家好,我的程序(不是自己写的)在执行判断扫描时老是停留在一个地方,怎么办? 程序段如下: main: nop nop nop mov wdt_contr,#00111110B ;喂狗   ...… 查看全部问答> |
|
2440 CAMERA CODE DMA地址在CONFIG.BIB中设置的疑惑? 我的CONFIG.BIB一段如下: MEMORY ;NK NK 8C200000 01D00000 RAMIMAGE ;RAM RAM 8E800000 0 ...… 查看全部问答> |
|
我现在用一个运算放大器调整单片机的采样信号.放大器的型号为LF412,资料里电源连接方式是双电源供电,如接+/-15v,由于我现在的输入信号只有正的.我把负电源接地,正电源接+15v,请问这样做行吗?… 查看全部问答> |
|
06.23【每周讨论】我们年轻,富有正义。对于社会中的不文明现象该怎样看待呢? 06.23【每周讨论】年轻的我们,富有正义、满怀激情。对于社会中的不文明现象该怎样看待呢?我们年轻人,富有正义、满怀激情,眼里容不下一粒沙。社会中那些不文明的现象经常在我们的周围发生,却让我们感到无可奈何。若为此感到懊恼的话,那你永远 ...… 查看全部问答> |




