目录
一、前言
二、工作原理
①输入捕获的通道概览
②输入捕获的工作过程
③溢出时间计算
三、STM32CubeMX配置(本文使用的STM32CubeMX版本为5.6.0)
1.MCU选型
2.使能时钟
3.时钟配置
4.设置GPIO口
5.定时器配置
6.串口配置
四、配置STM32CubeMX生成工程文件
五、KEIL程序
STM32L051C8T6除了基本定时器 TIM6 和 LPTIM1,其他定时器都具有输入捕 获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。
在通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、左下部分(输入捕获)这三个部分。这里主要讲解一下左下部分(输入捕获);
总结下来工作过程:通过检测TIMx_CHx通道上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时,还可以配置捕获时是否触发中断/DMA等。
将输入捕获的通道图进行分解,分解成四个部分,下面对这四个部分进行分析来了解输入捕获的工作过程:
t1时刻检测到高电平,发生中断,在中断里将计数值置0,开始记溢出次数N,
其中每计数0xFFFF次溢出一次,直到t2时刻跳变回低电平,
获取最后一次溢出时到t2时刻的计数值TIM2CH1_CAPTURE_VAL
则 高电平时间 = 溢出次数*65535+TIM2CH1_CAPTURE_VAL us ;根据定时器初始化时的频率即可计算出溢出总次数所占用的时间,即为高电平时间。
如果计数器值为 32 bit 那么最大为0xFFFFFFFF
如果计数器值为 16bit 那么最大为0xFFFF
高电平时间:
思路:将LED3配置成呼吸灯。
本例程使用的为STM32L051C8T6型号
6.点击GENERATE CODE生成工程文件
1.相关函数:
初始化定时器函数,此函数初始化了在STM32CubeMX内设置的参数,系统已经处理好了,并已经添加在了main函数内;
MX_TIM2_Init(); //初始化定时器配置
使能TIM2定时器;
HAL_TIM_Base_Start_IT(&htim2);
开启定时器输入捕获中断;
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
在main.h中添加枚举定义变量;
typedef struct //测量低电平脉宽
{
uint8_t ucFinishFlag; //结束
uint8_t ucStartFlag; //开始
uint16_t usCtr;
uint16_t usPeriod;
}STRUCT_CAPTURE;
在main.c中定义全局变量;
/* USER CODE BEGIN 0 */
STRUCT_CAPTURE strCapture = { 0, 0, 0 };
uint32_t ulTmrClk, ulTime,ulTimea,ulTimeb;
/* USER CODE END 0 */
在main函数代码;
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf ( "STM32 输入捕获实验\n" );
printf ( "按下KEY1,测试KEY1按下的时间\n" );
/* 获取定时器时钟周期 */
ulTmrClk = HAL_RCC_GetHCLKFreq()/32; //实际上就是定时器时钟/预分频系数 32M/32获取每次计数时间
/* 启动定时器 */
HAL_TIM_Base_Start_IT(&htim2);
/* 启动定时器通道输入捕获并开启中断 */
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 完成测量低电平脉宽 */
if(strCapture.ucFinishFlag == 1 )
{
/* 计算低电平计数值 ,0xFFFF为Period计数周期*/
ulTime = strCapture .usPeriod * 0xFFFF + strCapture .usCtr;
/* 打印低电平脉宽时间 */
printf ( ">>测得低电平脉宽时间:%d.%d s\n", ulTime / ulTmrClk, ulTime % ulTmrClk );
strCapture .ucFinishFlag = 0;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
在main.c文件中添加中断回调函数,用于处理定时器输入捕获时处理的数据;
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/*每次溢出时间为65536us*/
/*需要判断电平时间是否太长*/
if(strCapture.ucFinishFlag==0)//还未成功捕获
{
if(strCapture.ucStartFlag==1)//已经开始捕获
{
if(strCapture.usPeriod==0XFFFF)//电平太长了
{
strCapture.ucFinishFlag=1; //标记成功捕获了一次
strCapture .usCtr=0XFFFF;
} else strCapture .usPeriod ++;
}
}
/*不需要判断电平时间是否太长*/
// strCapture .usPeriod ++;
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
TIM_IC_InitTypeDef sConfigIC;
if ( strCapture .ucStartFlag == 0 )
{
__HAL_TIM_SET_COUNTER(htim,0); // 清零定时器计数
strCapture .usPeriod = 0;
strCapture .usCtr = 0;
/*配置输入捕获参数,主要是修改触发电平*/
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
/*清除中断标志位*/
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
/*启动输入捕获并开启中断*/
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
strCapture .ucStartFlag = 1;
}
else
{
/*获取定时器计数值*/
strCapture .usCtr = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
/*配置输入捕获参数,主要是修改触发电平*/
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
/*清除中断标志位*/
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
/*启动输入捕获并开启中断*/
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
strCapture .ucStartFlag = 0;
strCapture .ucFinishFlag = 1;
}
}
/* USER CODE END 4 */
在usart.c文件中添加串口重定向;
#include "stdio.h" //这个一定不能忘
/* USER CODE BEGIN 1 */
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE * f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1,&ch, 1, 0xffff);
return ch;
}
/* USER CODE END 1 */
2.编译文件,下载。即可,将杜邦线PA0与PB0引脚相连接,按下KEY1实现效果如下:
源工程文件代码下载:https://download.csdn.net/download/cheng_nnan/12366745