STM32——通用定时器脉冲计数实验

2024-01-03 14:29:14

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);
    }
}

文章来源:https://blog.csdn.net/m0_73502349/article/details/135355024
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。