一、PWM输入模式工作原理
![](https://i-blog.csdnimg.cn/direct/449797beb11a460aa2616e13daa48469.png)
通过PWM输入模式,可以测量PWM的周期、频率、占空比。
时钟源选择内部时钟源,然后设置PSC预分频系数。F1系列内部时钟为72M的,PSC分频系数设置为0,也就是不分频。可以计算出计数器计一个数的时间,也就是量器的精度。
具体配置:例如PWM从通道1输入,配置TI1的两个信号TI1FP1和TI1FP2分别映射到IC1和IC2上面。然后设置IC1为上升沿触发,IC2为下降沿触发。然后当上升沿来的时候,让计数器的值变为0。这个可以通过配置定时器的从模式为复位模式,通过配置TRGI为TI1FP1触发,当TI1FP1信号来的时候,计数器自动清零。由于通道3和通道4没有信号可以触发定时器的从模式,所以只能用通道1和通道2。
二、PWM输入模式时序
![](https://i-blog.csdnimg.cn/direct/b6bd0b98d21e4b3f9554e7e1d30c0d48.png)
首先PWM上升沿来的时候,计数器的值会被清0 ,等待下降沿到来。下降沿来时,计数器的值会转移到CCR2里边,然后上升沿再次来时,计数器的值会被转移到CCR1里边,同时计数器的值再次清零。
三、PWM输入模式配置步骤
1、HAL_TIM_IC_init()函数,配置定时器基础工作参数。,与base_init()函数一样
2、HAL_TIM_IC_MspInit()函数,配置NVIC、CLOCK、GPIO等。
3、HAL_TIM_IC_ConfigChannel()函数,配置输入通道1/2映射、捕获边沿等。
4、HAL_TIM_SlaveConfigSynchro()函数,设置从模式触发源
5、HAL_NVIC_SetPriority()、HAL_NVIC_EnablelRQ()函数,设置优先级,使能中断。
6、HAL_TIM_IC_Start_IT()函数,使能捕获、捕获中断及计数器。
7、TIMx_IROHandler()中断服务函数。
8、HAL_TIM_IC_CaptureCallback()函数,输入捕获中断回调函数。
![](https://i-blog.csdnimg.cn/direct/7c06a7bf06b644bdaf82f2d5c639f6e6.png)
四、PWM输入模式实验
1、寄存器版本
#include "./BSP/TIMER/atim.h"
//配置定时器1的通道1 和 通道1互补输出 PE8 PE9
void Advanced_TIM_Init(void)
{
//开启定时器1时钟
RCC->APB2ENR |= (1 << 11);
//设置ARR寄存器缓冲功能
TIM1->CR1 |= (1 << 7);
//设置计数器向上计数
TIM1->CR1 &= ~(1 << 4);
//TS 设置从模式触发为TI1FP1
TIM1->SMCR |= (1 << 6);
TIM1->SMCR |= (1 << 4);
TIM1->SMCR &= ~(1 << 5);
//SMS为复位模式
TIM1->SMCR |= (1 << 2);
//CC1S 配置IC1到TI1上
TIM1->CCMR1 |= (1 << 0);
//CC2S 配置IC2到TI1上
TIM1->CCMR1 |= (1 << 9);
//设置IC1上升沿捕获
TIM1->CCER &= ~(1 << 1);
//CC1E 使能通道1捕获
TIM1->CCER |= (1 << 0);
//设置IC2下升沿捕获
TIM1->CCER |= (1 << 5);
//CC2E 使能通道2捕获
TIM1->CCER |= (1 << 4);
//CC1IE 使能捕获1中断
TIM1->DIER |= (1 << 1);
//CC2IE 使能捕获2中断
TIM1->DIER |= (1 << 2);
//设置预分频系数为0
TIM1->PSC = 0;
//设置预装载值为65535
TIM1->ARR = 65535;
TIM1->EGR |= (1 << 0);
//开启GPIOE1时钟
RCC->APB2ENR |= (1 << 6);
//设置PE9为输入
GPIOE->CRH &= ~(0X03 << 4);
//GPIOE->CRH |= (1 << 7);
//GPIOE->CRH &= ~(1 << 6);
//使能AFIO时钟
RCC->APB2ENR |= (1 << 0);
//设置TIM1完全重映射 将CH1映射到PE9
AFIO->MAPR |= (0x03 << 6);
//开启TIM1 CC中断
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
//设置中断优先级
HAL_NVIC_SetPriority(TIM1_CC_IRQn, 2, 2);
//使能计数器
TIM1->CR1 |= (1 << 0);
}
uint16_t CNT1 = 0;
uint16_t CNT2 = 0;
void TIM1_CC_IRQHandler(void)
{
//CC1中断
if(TIM1->SR & (1 << 1))
{
CNT1 = TIM1->CCR1;
}
if(TIM1->SR & (1 << 2))
{
CNT2 = TIM1->CCR2;
}
TIM1->SR &= ~(1 << 1);
TIM1->SR &= ~(1 << 2);
}
这个程序是使用TIM8的通道1 PE9测量外部输入PWM信号
2、库函数版本
![](https://i-blog.csdnimg.cn/direct/06e27c9057084e008a96f51fad368f10.png)
atim.h头文件
#ifndef __ATIM_H
#define __ATIM_H
#include "stm32f1xx.h"
void Advanced_TIM_Init(void);
#endif
atim.c源文件
#include "./BSP/TIMER/atim.h"
//配置定时器1的通道1 PE9 测量信号PWM输入频率 周期
TIM_HandleTypeDef htim;
void Advanced_TIM_Init(void)
{
htim.Instance = TIM1;
htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 65535;
htim.Init.Prescaler = 0;
HAL_TIM_IC_Init(&htim);
TIM_IC_InitTypeDef sConfig = {0};
//配置IC1 连接到CH1上 上升沿捕获
sConfig.ICFilter = 0;
sConfig.ICPolarity = TIM_ICPOLARITY_RISING;
sConfig.ICPrescaler = TIM_ICPSC_DIV1;
sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
HAL_TIM_IC_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1);
//配置IC2 连接通道1上 下降沿捕获
sConfig.ICFilter = 0;
sConfig.ICPolarity = TIM_ICPOLARITY_FALLING;
sConfig.ICPrescaler = TIM_ICPSC_DIV1;
sConfig.ICSelection = TIM_ICSELECTION_INDIRECTTI;
HAL_TIM_IC_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_2);
//配置从模式为复位模式
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
//sSlaveConfig.TriggerFilter = ;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
//sSlaveConfig.TriggerPrescaler = ;
HAL_TIM_SlaveConfigSynchro(&htim, &sSlaveConfig);
//启动输入捕获通道1中断
HAL_TIM_IC_Start_IT(&htim, TIM_CHANNEL_1);
//启动输入捕获通道2中断
//HAL_TIM_IC_Start_IT(&htim, TIM_CHANNEL_2);
HAL_TIM_IC_Start(&htim, TIM_CHANNEL_2);
}
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
//使能定时器1时钟
__HAL_RCC_TIM1_CLK_ENABLE();
//使能AFIO时钟
__HAL_RCC_AFIO_CLK_ENABLE();
//开启TIM1重映射
__HAL_AFIO_REMAP_TIM1_ENABLE();
//使能GPIOE时钟
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Mode = GPIO_MODE_INPUT;
GPIO_Init.Pin = GPIO_PIN_9;
GPIO_Init.Pull = GPIO_NOPULL;
//设置PE9 CH1为输入模式
HAL_GPIO_Init(GPIOE, &GPIO_Init);
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
HAL_NVIC_SetPriority(TIM1_CC_IRQn,2,2);
}
uint16_t CNT1 = 0;
uint16_t CNT2 = 0;
void TIM1_CC_IRQHandler(void)
{
//HAL_TIM_IRQHandler(&htim);
if(__HAL_TIM_GET_FLAG(&htim, TIM_FLAG_CC1))
{
CNT1 = HAL_TIM_ReadCapturedValue(&htim, TIM_CHANNEL_1);
//CNT1 = __HAL_TIM_GET_COMPARE(&htim, TIM_CHANNEL_1);
//CNT1 = TIM1->CCR1;
__HAL_TIM_CLEAR_FLAG(&htim, TIM_FLAG_CC1);
}
if(__HAL_TIM_GET_FLAG(&htim, TIM_FLAG_CC2))
{
CNT2 = __HAL_TIM_GET_COMPARE(&htim, TIM_FLAG_CC2);
__HAL_TIM_CLEAR_FLAG(&htim, TIM_CHANNEL_2);
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1)
{
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1))
{
CNT1 = __HAL_TIM_GET_COMPARE(htim, TIM_FLAG_CC1);
}
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2))
{
CNT2 = __HAL_TIM_GET_COMPARE(htim, TIM_FLAG_CC2);
}
}
}
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/atim.h"
#include "./BSP/TIMER/pwm.h"
#define t 1/72000000
extern uint16_t CNT1;
extern uint16_t CNT2;
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_Init(); /* LED初始化 */
usart_init(115200);
TIM_PWM_Init();
Advanced_TIM_Init();
int fre = 0;
double duty = 0;
while(1)
{
LED0(1);
LED1(0);
delay_ms(500);
LED0(0);
LED1(1);
delay_ms(500);
duty = (((double)CNT2 + 1 )) * 100 / ( CNT1 + 1 );
fre = 72000000 / (CNT1 + 1 );
printf("频率为%d,占空比为%f\r\n",fre,duty);
}
}