【正点原子学习笔记:stm32高级定时器PWM输入模式实验,原子教程笔记】

  1. List item

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

stm32高级定时器PWM输入模式实验,原子教程笔记

一、工作原理

在这里插入图片描述芯片手册上,高级定时器PWM输入模式下,只能采用ch1和ch2口子。当上升沿来的时候进入中断将进入到IC1中,同时看到TI1FP1触发从模式选择:复位模式,将计数器清零,这样随后下降沿来的时候,进入中断,将CCR2+1即得到一个周期高电平时间(CCR2 为输入捕获 2 事件 (IC2) 发生时的计数器值),总之上升沿复位比直接CCR2-CCR1简单一些,下一次上升沿时CCR1的计数也就是一个周期的时间。看图片右下角。

**

1. 时序图

**
在这里插入图片描述
可以看到第一次上升沿复位清零,IC1和IC2分别在不同边沿被捕获,后续上升沿不会复位,第二个上升沿CCR1+1就是周期,当然这里讲的是向上计数。

二、参数配置

1.HAL库函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一个结构体只用前2个,第二个结构体用前3个

其中输入触发源选择是选蓝色部分,极性选择是紫色不是是上升沿触发还是下降沿,这里选上升沿
在这里插入图片描述

三、实验代码

以下是代码
函数1:atim_timx_pwmin_chy_init
用来完成输入捕获到初始化配置
函数2:HAL_TIM_IC_MspInit
一般是gpio口,以及NVIC中断的配置
函数3:TIM8_CC_IRQHandler
单纯添加定时器的句柄作为参数
函数4:atim_timx_pwmin_chy_restart
重启输入捕获
函数5:HAL_TIM_IC_CaptureCallback
中断回调函数,进入中断后会调用读函数读寄存器的值

#include "./BSP/TIMER/atim.h"


TIM_HandleTypeDef g_timx_pwmin_chy_handle;   /* 定时器x句柄 */

/* PWM输入状态(g_timxchy_cap_sta)
 * 0,没有成功捕获.
 * 1,已经成功捕获了
 */
uint8_t g_timxchy_pwmin_sta  = 0;   /* PWM输入状态 */
uint16_t g_timxchy_pwmin_psc  = 0;  /* PWM输入分频系数 */
uint32_t g_timxchy_pwmin_hval = 0;  /* PWM的高电平脉宽 */
uint32_t g_timxchy_pwmin_cval = 0;  /* PWM的周期宽度 */

/* PWM输入模式 初始化函数,采样时钟频率为72Mhz,精度约13.8ns */
void atim_timx_pwmin_chy_init(void)
{
    TIM_SlaveConfigTypeDef slave_config = {0};
    TIM_IC_InitTypeDef tim_ic_pwmin_chy = {0};

    g_timx_pwmin_chy_handle.Instance = TIM8;                        /* 定时器8 */
    g_timx_pwmin_chy_handle.Init.Prescaler = 0;                     /* 定时器预分频系数 */
    g_timx_pwmin_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;  /* 递增计数模式 */
    g_timx_pwmin_chy_handle.Init.Period = 65535;                    /* 自动重装载值 */
    HAL_TIM_IC_Init(&g_timx_pwmin_chy_handle);
    
    /* 从模式配置,IT1触发更新 */
    slave_config.SlaveMode = TIM_SLAVEMODE_RESET;                   /* 从模式:复位模式 */
    slave_config.InputTrigger = TIM_TS_TI1FP1;                      /* 定时器输入触发源:TI1FP1 */
    slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;      /* 上升沿检测 */
    slave_config.TriggerFilter = 0;                                 /* 不滤波 */
    HAL_TIM_SlaveConfigSynchro(&g_timx_pwmin_chy_handle, &slave_config);

    /* IC1捕获:上升沿触发TI1FP1 */
    tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_RISING;            /* 上升沿检测 */
    tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_DIRECTTI;        /* 选择输入端IC1映射到TI1 */
    tim_ic_pwmin_chy.ICPrescaler = TIM_ICPSC_DIV1;                  /* 不分频 */
    tim_ic_pwmin_chy.ICFilter = 0;                                  /* 不滤波 */
    HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, TIM_CHANNEL_1);

    /* IC2捕获:下降沿触发TI1FP2 */
    tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_FALLING;           /* 下降沿检测 */
    tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_INDIRECTTI;      /* 选择输入端IC2映射到TI1 */
    HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, TIM_CHANNEL_2);

    HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1);
    HAL_TIM_IC_Start(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2);
	/*
	 
	在STM32的HAL(硬件抽象层)库中,HAL_TIM_IC_Start_IT 和 HAL_TIM_IC_Start 是与TIM(定时器)模块的输入捕获(Input Capture, IC)功能相关的函数。

	HAL_TIM_IC_Start_IT:
	功能:启动TIM输入捕获的中断。
	当定时器计数器的值与预设的捕获值匹配时,这个函数会启动一个中断请求。这通常用于测量脉冲的宽度或频率。
	当你希望使用中断来处理输入捕获事件时,你会使用这个函数。
	注意:在调用这个函数之前,你需要配置好TIM输入捕获的相关参数,如预分频器、捕获通道、捕获极性等。
	HAL_TIM_IC_Start:
	功能:启动TIM输入捕获功能,但不启动中断。
	与HAL_TIM_IC_Start_IT类似,这个函数也会启动输入捕获功能,但不会生成中断请求。
	你可能需要在主循环或其他非中断上下文中定期检查TIM的输入捕获状态。
	注意:同样,在调用这个函数之前,你需要配置好TIM输入捕获的相关参数。
	简单来说,HAL_TIM_IC_Start_IT和HAL_TIM_IC_Start的主要区别在于是否启动中断。
	如果你想要实时响应输入捕获事件,你应该使用HAL_TIM_IC_Start_IT;如果你希望在主循环中检查输入捕获状态,你可以使用HAL_TIM_IC_Start。
	
	*/
}

/* 定时器 输入捕获 MSP初始化函数,输入捕获GPIO引脚配置 */
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM8)
    {
        GPIO_InitTypeDef gpio_init_struct = {0};

        __HAL_RCC_TIM8_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE();

        gpio_init_struct.Pin = GPIO_PIN_6;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;		//输入,推挽式复用
        gpio_init_struct.Pull = GPIO_PULLDOWN;			//下拉,也可以不用
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;	//高速,输入不用设置
        HAL_GPIO_Init(GPIOC, &gpio_init_struct);
        
        /* TIM1/TIM8有独立的输入捕获中断服务函数 */
        HAL_NVIC_SetPriority(TIM8_CC_IRQn, 1, 3);//开启了输入捕获中断
        HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);
    }
}

/* 定时器8 输入捕获 中断服务函数,仅TIM1/TIM8有这个函数,其他普通定时器没有这个中断服务函数! */
void TIM8_CC_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_pwmin_chy_handle); /* 定时器共用处理函数 */
}

/* PWM输入模式 重新启动捕获 */
void atim_timx_pwmin_chy_restart(void)
{
    sys_intx_disable();                     /* 关闭中断 */

    g_timxchy_pwmin_sta = 0;                /* 清零状态,重新开始检测 */
    g_timxchy_pwmin_hval=0;
    g_timxchy_pwmin_cval=0;

    sys_intx_enable();                      /* 打开中断 */
}

/* 定时器输入捕获中断处理回调函数 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM8)
    {
        if(g_timxchy_pwmin_sta == 0)
        {
            if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
            {
                g_timxchy_pwmin_hval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2) + 1 + 1;
                g_timxchy_pwmin_cval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1) + 1 + 1;
                g_timxchy_pwmin_sta = 1;
            }
        }
    }
}

以下代码是PWM输出比较代码,用于输出pwm

#include "./BSP/TIMER/gtim.h"


TIM_HandleTypeDef g_timx_pwm_chy_handle;

/* 通用定时器PWM输出初始化函数 */
void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc)
{
    TIM_OC_InitTypeDef timx_oc_pwm_chy;
    
    g_timx_pwm_chy_handle.Instance = TIM3;							/*选择pwm的定时器x*/
    g_timx_pwm_chy_handle.Init.Prescaler = psc;						/*这个定时器的分频系数*/
    g_timx_pwm_chy_handle.Init.Period = arr;						/*自动重装载值*/
    g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;	/*up计数*/
    HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);
    
    timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;						/*oc是输出,这里选择输出pwm1*/
    timx_oc_pwm_chy.Pulse = arr / 2;								/*ccr比较值*/
    timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW;				/*输出极性*/
    HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_2);/*两个句柄加一个定时器pwm输出通道选择*/
    HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_2);/*开启pwm以及通道输出pwm*/
}

/* 定时器输出PWM MSP初始化函数 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM3)
    {
        GPIO_InitTypeDef gpio_init_struct;
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_TIM3_CLK_ENABLE();

        gpio_init_struct.Pin = GPIO_PIN_5;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;            /* 推挽复用 */
        gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;      /* 高速 */
        HAL_GPIO_Init(GPIOB, &gpio_init_struct);
        
        __HAL_RCC_AFIO_CLK_ENABLE();/*使能AFIO时钟,从而允许对GPIO引脚进行复用配置和重映射操作。*/
        __HAL_AFIO_REMAP_TIM3_PARTIAL();/*将TIM3引脚复用*/
    }
}

接着是main函数

/**
 ****************************************************************************************************
 * @file        main.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-04-20
 * @brief       跑马灯 实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 STM32F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/atim.h"
#include "./BSP/TIMER/gtim.h"


extern uint16_t g_timxchy_pwmin_sta;    /* PWM输入状态 */
extern uint16_t g_timxchy_pwmin_psc;    /* PWM输入分频系数 */
extern uint32_t g_timxchy_pwmin_hval;   /* PWM的高电平脉宽 */
extern uint32_t g_timxchy_pwmin_cval;   /* PWM的周期宽度 */

int main(void)
{
    uint8_t t = 0;
    double ht, ct, f, tpsc;

    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */
    delay_init(72);                             /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    gtim_timx_pwm_chy_init(10 - 1, 72 - 1);		//配置pwm输出
    
    TIM3->CCR2 = 3;								/*设置输出pwm的占空比*/
    
    atim_timx_pwmin_chy_init();
    
    while (1)
    {
        delay_ms(10);
        t++;

        if (t >= 20)    /* 每200ms输出一次结果,并闪烁LED0,提示程序运行 */
        {
            if (g_timxchy_pwmin_sta)    /* 捕获了一次数据 */
            {
                printf("\r\n");                                     /* 输出空,另起一行 */
                printf("PWM PSC  :%d\r\n", g_timxchy_pwmin_psc);    /* 打印分频系数 */
                printf("PWM Hight:%d\r\n", g_timxchy_pwmin_hval);   /* 打印高电平脉宽 */
                printf("PWM Cycle:%d\r\n", g_timxchy_pwmin_cval);   /* 打印周期 */
                tpsc = ((double)g_timxchy_pwmin_psc + 1) / 72;      /* 得到PWM采样时钟周期时间 */ 
                ht = g_timxchy_pwmin_hval * tpsc;                   /* 计算高电平时间 */
                ct = g_timxchy_pwmin_cval * tpsc;                   /* 计算周期长度 */
                f = (1 / ct) * 1000000;                             /* 计算频率 */
                printf("PWM Hight time:%.3fus\r\n", ht);            /* 打印高电平脉宽长度 */
                printf("PWM Cycle time:%.3fus\r\n", ct);            /* 打印周期时间长度 */
                printf("PWM Frequency :%.3fHz\r\n", f);             /* 打印频率 */ 
                atim_timx_pwmin_chy_restart(); /* 重启PWM输入检测 */
            } 

            LED1_TOGGLE();  /* LED1(GREEN)闪烁 */
            t = 0;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值