1.脉冲计数实验原理
2.从模式配置结构体
typedef struct
{
uint32_t SlaveMode; /* 从模式选择 /
uint32_t InputTrigger; / 输入触发源选择 /
uint32_t TriggerPolarity; / 输入触发极性 /
uint32_t TriggerPrescaler; / 输入触发预分频 /
uint32_t TriggerFilter; / 输入滤波器设置 */
} TIM_SlaveConfigTypeDef;
3.实验要求
1.将定时器2通道1输入的高电平脉冲作为定时器2的时钟,并通过串口打印脉冲数。
2.配置从模式:外部时钟模式1、触发选择、上升沿触发、不分频、不滤波。
4.输入脉冲实验配置步骤
1,配置定时器基础工作参数 HAL_TIM_IC_Init()
2,定时器输入捕获MSP初始化 HAL_TIM_IC_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置定时器从模式等 HAL_TIM_SlaveConfigSynchro()
4,使能输入捕获并启动计数器 HAL_TIM_IC_Start()
5,获取计数器的值 __HAL_TIM_GET_COUNTER()
6,设置计数器的值 __HAL_TIM_SET_COUNTER()
5.输入脉冲实验配置步骤
5.1 gtim.c
#include "./BSP/TIMER/gtim.h"
#include "./BSP/LED/led.h"
#include "./SYSTEM/usart/usart.h"
/******************************定时器脉冲计数实验*****************************************/
//1.定时器句柄定义
TIM_HandleTypeDef g_timx_cnt_chy_handle; //定时器x句柄
uint32_t g_timxchy_cnt_ofcnt = 0; //溢出累计次数
//2.通用定时器脉冲通道 初始化函数
//基本工作参数配置
// * @note
// * 通用定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
// * 通用定时器的时钟为APB1时钟的2倍, 而APB1为42M, 所以定时器时钟 = 84Mhz
// * 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
// * Ft=定时器工作频率,单位:Mhz
// *
// * @param arr: 自动重装值
// * @param psc: 预分频系数
// * @retval 无
void gtim_timx_cnt_chy_init(uint16_t psc)
{
TIM_SlaveConfigTypeDef timx_slave_config = {0};
//2.1定时器句柄初始化、包括定时器2基地址、自动重装载值、预分频系数
g_timx_cnt_chy_handle.Instance = GTIM_TIMX_CNT; //定时器2
g_timx_cnt_chy_handle.Init.Prescaler = psc; //预分频系数
g_timx_cnt_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数模式
g_timx_cnt_chy_handle.Init.Period = 65535; //自动重装载值为65535
HAL_TIM_IC_Init(&g_timx_cnt_chy_handle); //初始化定时器
//3 定时器从模式配置
timx_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; //从模式:外部触发模式1
timx_slave_config.InputTrigger = TIM_TS_TI1FP1; //输入触发:选择 TI1FP1(TIMX_CH1) 作为输入源
timx_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; // 极性选择:上升沿
timx_slave_config.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; //触发预分频:无
timx_slave_config.TriggerFilter = 0; // 配置输入滤波器,不滤波
HAL_TIM_SlaveConfigSynchro(&g_timx_cnt_chy_handle,&timx_slave_config);//定时器从模式初始化配置
//4 使能更新中断
__HAL_TIM_ENABLE_IT(&g_timx_cnt_chy_handle, TIM_IT_UPDATE);
//5 输入捕获使能、启动计数器
HAL_TIM_IC_Start(&g_timx_cnt_chy_handle,GTIM_TIMX_CNT_CHY);
}
//3.定时器输入捕获MSP(MCU Specific Package)初始化
// @param htim:定时器句柄
// @note 此函数会被HAL_TIM_IC_Init()调用
// @retval 无
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == GTIM_TIMX_CNT)
{
GPIO_InitTypeDef gpio_init_struct; //gpio结构体定义
//定时器时钟使能
GTIM_TIMX_CNT_CHY_CLK_ENABLE();
//GPIO时钟使能
GTIM_TIMX_CNT_CHY_GPIO_CLK_ENABLE();
//GPIO初始化
gpio_init_struct.Pin = GTIM_TIMX_CNT_CHY_GPIO_PIN; //输入捕获的GPIO口
gpio_init_struct.Mode = GPIO_MODE_AF_PP; //复用推挽输出
gpio_init_struct.Pull = GPIO_PULLDOWN; //下拉
gpio_init_struct.Alternate =GTIM_TIMX_CNT_CHY_GPIO_AF; //复用为捕获TIM2的通道1
HAL_GPIO_Init(GTIM_TIMX_CNT_CHY_GPIO_PORT, &gpio_init_struct);
}
}
//6.获取计数器的值
// * @param 无
// * @retval 当前计数值
uint32_t gtim_timx_cnt_chy_get_count()
{
uint32_t count = 0; //定义计数总值变量
count = g_timxchy_cnt_ofcnt * 65536; //计算溢出次数 x arr 之积
count += __HAL_TIM_GET_COUNTER(&g_timx_cnt_chy_handle); //加上当前CNT的值
return count;
}
//7.计数器的值重置函数
// * @param 无
// * @retval 无
void gtim_timx_cnt_chy_restart()
{
__HAL_TIM_DISABLE(&g_timx_cnt_chy_handle); //关闭定时器
g_timxchy_cnt_ofcnt = 0; //累计溢出次数清零
__HAL_TIM_SET_COUNTER(&g_timx_cnt_chy_handle,0); //计数器清零
__HAL_TIM_ENABLE(&g_timx_cnt_chy_handle); //定时器使能
}
//8.更新中断服务函数
// * @param 无
// * @retval 无
void GTIM_TIMX_CNT_IRQHandler()
{
//没有使用定时器HAL库公共处理函数,通过判断中断标注为实现溢出次数的累加
if(__HAL_TIM_GET_FLAG(&g_timx_cnt_chy_handle,TIM_FLAG_UPDATE) != RESET)
{
g_timxchy_cnt_ofcnt++; //累计溢出次数
}
__HAL_TIM_CLEAR_IT(&g_timx_cnt_chy_handle,TIM_IT_UPDATE); //清理TIM开启时的中断标识
}
5.2 gtim.h
#ifndef __GTIM_H
#define __GTIM_H
#include "./SYSTEM/sys/sys.h"
/* TIMX 输入计数定义
* 这里的输入计数使用定时器TIM2_CH1,捕获WK_UP按键的输入
* 默认是针对TIM2~TIM5, 只有CH1和CH2通道可以用做输入计数, CH3/CH4不支持!
* 注意: 通过修改这几个宏定义,可以支持TIM1~TIM8任意一个定时器,CH1/CH2对应IO口做输入计数
* 特别要注意:默认用的PA0,设置的是下拉输入!如果改其他IO,对应的上下拉方式也得改!
*/
#define GTIM_TIMX_CNT_CHY_GPIO_PORT GPIOA
#define GTIM_TIMX_CNT_CHY_GPIO_PIN GPIO_PIN_0
#define GTIM_TIMX_CNT_CHY_GPIO_AF GPIO_AF1_TIM2 /* AF功能选择 */
#define GTIM_TIMX_CNT_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define GTIM_TIMX_CNT TIM2
#define GTIM_TIMX_CNT_IRQn TIM2_IRQn
#define GTIM_TIMX_CNT_IRQHandler TIM2_IRQHandler
#define GTIM_TIMX_CNT_CHY TIM_CHANNEL_1 /* 通道Y, 1<= Y <=2 */
#define GTIM_TIMX_CNT_CHY_CLK_ENABLE() do{ __HAL_RCC_TIM2_CLK_ENABLE(); }while(0) /* TIM2 时钟使能 */
void gtim_timx_cnt_chy_init(uint16_t psc); /* 通用定时器 脉冲计数初始化函数 */
uint32_t gtim_timx_cnt_chy_get_count(); /* 通用定时器 获取脉冲计数 */
void gtim_timx_cnt_chy_restart(); /* 通用定时器 重启计数器 */
#endif
5.3 main.c
int main(void)
{
//变量定义:包括新、老计数值、key值、以及循环计数
uint32_t curcnt =0;
uint32_t oldcnt =0;
uint8_t key =0;
uint8_t t =0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
//调用通用定时器通道计数初始化函数与计数器的值重置函数
gtim_timx_cnt_chy_init(0); //通用定时器初始化 不分屏
gtim_timx_cnt_chy_restart(); //计数器重置
while (1)
{
//KEY0控制计数器重置
key = key_scan(0); //扫描按键
if(key == KEY0_PRES)
{
printf("KEY0 PRESS\r\n");
gtim_timx_cnt_chy_restart(); //重置
}
//获取计数值,打印计数值
curcnt = gtim_timx_cnt_chy_get_count();
if (oldcnt != curcnt)
{
oldcnt = curcnt;
printf("CNT:%d\r\n", oldcnt); /* 打印脉冲个数 */
}
//每200msLED0闪烁一次
t++;
if(t>20)
{
t=0;
LED0_TOGGLE();
}
delay_ms(10);
}
}