STM32的HAL库开发---通用定时器(TIMER)---定时器脉冲计数
一、脉冲计数实验原理
1、 外部时钟模式1:核心为蓝色部分的时基单元,时基单元的时钟源可以来自四种,分别是内部时钟PCLK、外部时钟模式1,外部时钟模式2、内部定时器触发(级联)。而脉冲计数就是使用外部时钟模式1和外部时钟模式2。
当使用外部时钟模式1的时候,输入信号主要来自定时器的通道1和通道2,然后通过信号TI1FP1和TI2FP2来到TRGI,然后经过从模式控制器来到时基单元。在从模式控制器里边的从模式选择外部时钟模式1,而外部时钟模式1实际上信号可以来自于TI1FP1、TI2FP2、TI1F_ED三种,其中TI1F_ED为双边沿检测,当来一个脉冲之后,无论是上升沿还是下降沿,TI1F_ED都有效,都会触发计数器计数,如果分频系数是1,一个脉冲会记两个数。而TI1FP1和TI2FP2只能是一种边沿,记一个信号。
分频系数为1时,直接读取计数器的值就是脉冲的个数。
2、外部时钟模式2:信号来自TIMx_ETR引脚,经过极性选择、边沿检测器、预分频器、输入滤波器,来到ETRF,设置从模式控制器模式为外部时钟模式2,然后来到时基单元。
例子:外部时钟模式1,信号配置成通道2输入。
设置SMS为111,外部时钟模式1,信号从定时器通道2来到TI2,然后首先经过滤波器,滤波器可以设置ICF进行设置。 然后设置边沿检测器,通过CC2P位来设置是上升沿还是下降沿有效,然后设置TRGI信号源,设置为110,信号来自TI2FP2,这块的设置跟输入捕获时候设置有些类似。
二、通用定时器脉冲计数实验配置步骤
1、HAL_TIM_IC_Init()函数,配置定时器基础工作参数。跟base_init函数一样。
2、HAL_TIM_IC_Msplnit()函数,配置NVIC、CLOCK、GPIO等。
3、HAL_TIM_SlaveConfigSynchro()函数,配置定时器从模式等。
4、HAL _TIM_IC_Start()函数,使能输入捕获并启动计数器。
5、__HAL_TIM_GET_COUNTERO()宏定义,获取计数器的值。
6、__HAL_TIM_SET_COUNTERO()宏定义,设置计数器的值。
三、通用定时器脉冲计数实验
实验:将定时器2通道1输入的高电平脉冲作为定时器2的时钟,并通过串口打印脉冲数,定时器2通道1为PA0 PA0接的按键 按下一次产生一个脉冲
1、寄存器配置版本
注意:在配置过程中PSC设置为1时,都正常,但是PSC设置的值不是1时,一定要软件产生更新事件,由于PSC有影子寄存器,实际起作用的是影子寄存器,不软件产生更新事件,PSC的值会在计数器溢出的时候进入影子寄存器。
在HAL库里边这个软件更新事件在初始化函数最后写了。
#include "./BSP/TIMER/TIM_IC.h"
void TIM_IC_Init(void)
{
//开启GPIOA时钟
RCC->APB2ENR |= (1 << 2);
//设置PA0为输入模式
GPIOA ->CRL &= ~(0X03 << 0);
//设置PA0为输入下拉
GPIOA->CRL |= (1 << 3);
GPIOA->CRL &= ~(1 << 2);
//开启定时器2时钟
RCC->APB1ENR |= (1 << 0);
//设置分频系数PSC
TIM2->PSC = 5;
//开启ARR寄存器缓冲功能
TIM2->CR1 |= (1 << 7);
//设置计数器向上计数模式
TIM2->CR1 &= ~(1 << 4);
//设置TS位 为 101接TI1FP1
TIM2->SMCR |= (1 << 6);
TIM2->SMCR &= ~(1 << 5);
TIM2->SMCR |= (1 << 4);
//设置SMS为外输时钟模式1 111
TIM2->SMCR |= 0X07;
//设置输入滤波 IC1F 0000
TIM2->CCMR1 &= ~(0X0F << 4);
//设置CC1P 上升沿捕获
TIM2->CCER &= ~(1 << 1);
//设置ARR值为999
TIM2->ARR = 999;
//使能计数器 CEN位
TIM2->CR1 |= (1<< 0);
//***********注意:重要****************
//软件产生更新事件 使PSC的值立即生效
//由于PSC有影子寄存器 不软件产生更新事件 PSC的值会等到计数器溢出是才生效
TIM2->EGR |= (1 << 0);
}
2、 库函数版本
tim_inCapture.h头文件程序
#ifndef __TIM_INCAPTURE_H
#define __TIM_INCAPTURE_H
#include "stm32f1xx.h"
void TIM_IC_Init(uint16_t psc,uint16_t arr);
#endif
tim_inCapture.c源文件程序
#include "./BSP/TIMER/tim_inCapture.h"
TIM_HandleTypeDef htim;
void TIM_IC_Init(uint16_t psc,uint16_t arr)
{
htim.Instance = TIM2;
htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = arr;
htim.Init.Prescaler = psc;
//定时器初始化 PSC ARR 计数模式 ARR缓冲功能
HAL_TIM_IC_Init(&htim);
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
//设置双边沿触发
//sSlaveConfig.InputTrigger = TIM_TS_TI1F_ED;
//设置单边沿触发
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
sSlaveConfig.TriggerFilter = 0X0;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
//这个是输入分频的 这个在外部时钟模式1没有用 外部时钟模式2有分频
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
//定时器从模式配置
HAL_TIM_SlaveConfigSynchro(&htim, &sSlaveConfig);
//启动定时器
HAL_TIM_IC_Start(&htim, TIM_CHANNEL_1);
}
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim ->Instance == TIM2)
{
//开启定时器2时钟
__HAL_RCC_TIM2_CLK_ENABLE();
//开启GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Mode = GPIO_MODE_INPUT;
GPIO_Init.Pin = GPIO_PIN_0;
GPIO_Init.Pull = GPIO_PULLDOWN;
GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;//速度是输出用的 可以不设置
//初始化PA0为下拉输入
HAL_GPIO_Init(GPIOA, &GPIO_Init);
}
}
main,c主函数程序
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/tim_inCapture.h"
uint8_t count = 0;//捕获高电平完成
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_Init(); /* LED初始化 */
usart_init(115200);
TIM_IC_Init(0 ,999);
while(1)
{
LED0(1);
LED1(0);
delay_ms(500);
LED0(0);
LED1(1);
delay_ms(500);
count = TIM2->CNT;
printf("脉冲个数:%d\r\n",count);
}
}