基质喷涂
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

493 lines
16 KiB

//
// Created by iflyt on 2025/2/28.
//
#include "tim_pwm.h"
#include "main.h"
#include <stm32f4xx_hal.h>
/*
可以输出到GPIO的TIM通道:
TIM1_CH1, PA8, PE9,
TIM1_CH2, PA9, PE11
TIM1_CH3, PA10, PE13
TIM1_CH4, PA11, PE14
TIM2_CH1, PA15 (仅限429,439) 407没有此脚
TIM2_CH2, PA1, PB3
TIM2_CH3, PA2, PB10
TIM2_CH4, PA3, PB11
TIM3_CH1, PA6, PB4, PC6
TIM3_CH2, PA7, PB5, PC7
TIM3_CH3, PB0, PC8
TIM3_CH4, PB1, PC9
TIM4_CH1, PB6, PD12
TIM4_CH2, PB7, PD13
TIM4_CH3, PB8, PD14
TIM4_CH4, PB9, PD15
TIM5_CH1, PA0, PH10
TIM5_CH2, PA1, PH11
TIM5_CH3, PA2, PH12
TIM5_CH4, PA3, PI10
TIM8_CH1, PC6, PI5
TIM8_CH2, PC7, PI6
TIM8_CH3, PC8, PI7
TIM8_CH4, PC9, PI2
TIM9_CH1, PA2, PE5
TIM9_CH2, PA3, PE6
TIM10_CH1, PB8, PF6
TIM11_CH1, PB9, PF7
TIM12_CH1, PB14, PH6
TIM12_CH2, PB15, PH9
TIM13_CH1, PA6, PF8
TIM14_CH1, PA7, PF9
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
APB1 定时器的输入时钟 TIMxCLK = SystemCoreClock / 2; 84M
APB2 定时器的输入时钟 TIMxCLK = SystemCoreClock; 168M
*/
/*
*********************************************************************************************************
* 函 数 名: bsp_RCC_GPIO_Enable
* 功能说明: 使能GPIO时钟
* 形 参: GPIOx GPIOA - GPIOI
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_RCC_GPIO_Enable(GPIO_TypeDef* GPIOx)
{
if (GPIOx == GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE();
else if (GPIOx == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE();
else if (GPIOx == GPIOC) __HAL_RCC_GPIOC_CLK_ENABLE();
else if (GPIOx == GPIOD) __HAL_RCC_GPIOD_CLK_ENABLE();
else if (GPIOx == GPIOE) __HAL_RCC_GPIOE_CLK_ENABLE();
else if (GPIOx == GPIOF) __HAL_RCC_GPIOF_CLK_ENABLE();
else if (GPIOx == GPIOG) __HAL_RCC_GPIOG_CLK_ENABLE();
else if (GPIOx == GPIOH) __HAL_RCC_GPIOH_CLK_ENABLE();
else if (GPIOx == GPIOI) __HAL_RCC_GPIOI_CLK_ENABLE();
}
/*
*********************************************************************************************************
* 函 数 名: bsp_RCC_TIM_Enable
* 功能说明: 使能TIM RCC 时钟
* 形 参: TIMx TIM1 - TIM14
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_RCC_TIM_Enable(TIM_TypeDef* TIMx)
{
if (TIMx == TIM1) __HAL_RCC_TIM1_CLK_ENABLE();
else if (TIMx == TIM2) __HAL_RCC_TIM2_CLK_ENABLE();
else if (TIMx == TIM3) __HAL_RCC_TIM3_CLK_ENABLE();
else if (TIMx == TIM4) __HAL_RCC_TIM4_CLK_ENABLE();
else if (TIMx == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
else if (TIMx == TIM6) __HAL_RCC_TIM6_CLK_ENABLE();
else if (TIMx == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
else if (TIMx == TIM8) __HAL_RCC_TIM8_CLK_ENABLE();
else if (TIMx == TIM9) __HAL_RCC_TIM9_CLK_ENABLE();
else if (TIMx == TIM10) __HAL_RCC_TIM10_CLK_ENABLE();
else if (TIMx == TIM11) __HAL_RCC_TIM11_CLK_ENABLE();
else if (TIMx == TIM12) __HAL_RCC_TIM12_CLK_ENABLE();
else if (TIMx == TIM13) __HAL_RCC_TIM13_CLK_ENABLE();
else if (TIMx == TIM14) __HAL_RCC_TIM14_CLK_ENABLE();
else
{
//Error_Handler(__FILE__, __LINE__);
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_RCC_TIM_Disable
* 功能说明: 关闭TIM RCC 时钟
* 形 参: TIMx TIM1 - TIM14
* 返 回 值: TIM外设时钟名
*********************************************************************************************************
*/
void bsp_RCC_TIM_Disable(TIM_TypeDef* TIMx)
{
/*
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
*/
if (TIMx == TIM1) __HAL_RCC_TIM1_CLK_DISABLE();
else if (TIMx == TIM2) __HAL_RCC_TIM2_CLK_DISABLE();
else if (TIMx == TIM3) __HAL_RCC_TIM3_CLK_DISABLE();
else if (TIMx == TIM4) __HAL_RCC_TIM4_CLK_DISABLE();
else if (TIMx == TIM5) __HAL_RCC_TIM5_CLK_DISABLE();
else if (TIMx == TIM6) __HAL_RCC_TIM6_CLK_DISABLE();
else if (TIMx == TIM7) __HAL_RCC_TIM7_CLK_DISABLE();
else if (TIMx == TIM8) __HAL_RCC_TIM8_CLK_DISABLE();
else if (TIMx == TIM9) __HAL_RCC_TIM9_CLK_DISABLE();
else if (TIMx == TIM10) __HAL_RCC_TIM10_CLK_DISABLE();
else if (TIMx == TIM11) __HAL_RCC_TIM11_CLK_DISABLE();
else if (TIMx == TIM12) __HAL_RCC_TIM12_CLK_DISABLE();
else if (TIMx == TIM13) __HAL_RCC_TIM13_CLK_DISABLE();
else if (TIMx == TIM14) __HAL_RCC_TIM14_CLK_DISABLE();
else
{
//Error_Handler(__FILE__, __LINE__);
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_GetAFofTIM
* 功能说明: 根据TIM 得到AF寄存器配置
* 形 参: TIMx TIM1 - TIM14
* 返 回 值: AF寄存器配置
*********************************************************************************************************
*/
uint8_t bsp_GetAFofTIM(TIM_TypeDef* TIMx)
{
uint8_t ret = 0;
if (TIMx == TIM1) ret = GPIO_AF1_TIM1;
else if (TIMx == TIM2) ret = GPIO_AF1_TIM2;
else if (TIMx == TIM3) ret = GPIO_AF2_TIM3;
else if (TIMx == TIM4) ret = GPIO_AF2_TIM4;
else if (TIMx == TIM5) ret = GPIO_AF2_TIM5;
else if (TIMx == TIM8) ret = GPIO_AF3_TIM8;
else if (TIMx == TIM9) ret = GPIO_AF3_TIM9;
else if (TIMx == TIM10) ret = GPIO_AF3_TIM10;
else if (TIMx == TIM11) ret = GPIO_AF3_TIM11;
else if (TIMx == TIM12) ret = GPIO_AF9_TIM12;
else if (TIMx == TIM13) ret = GPIO_AF9_TIM13;
else if (TIMx == TIM14) ret = GPIO_AF9_TIM14;
else
{
//Error_Handler(__FILE__, __LINE__);
}
return ret;
}
/*
*********************************************************************************************************
* 函 数 名: bsp_ConfigTimGpio
* 功能说明: 配置GPIO和TIM时钟, GPIO连接到TIM输出通道
* 形 参: GPIOx : GPIOA - GPIOK
* GPIO_PinX : GPIO_PIN_0 - GPIO__PIN_15
* TIMx : TIM1 - TIM14
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_ConfigTimGpio(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinX, TIM_TypeDef* TIMx)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能GPIO时钟 */
bsp_RCC_GPIO_Enable(GPIOx);
/* 使能TIM时钟 */
bsp_RCC_TIM_Enable(TIMx);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = bsp_GetAFofTIM(TIMx);
GPIO_InitStruct.Pin = GPIO_PinX;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
/*
*********************************************************************************************************
* 函 数 名: bsp_ConfigGpioOut
* 功能说明: 配置GPIO为推挽输出。主要用于PWM输出,占空比为0和100的情况。
* 形 参: GPIOx : GPIOA - GPIOK
* GPIO_PinX : GPIO_PIN_0 - GPIO__PIN_15
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_ConfigGpioOut(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinX)
{
GPIO_InitTypeDef GPIO_InitStruct;
bsp_RCC_GPIO_Enable(GPIOx); /* 使能GPIO时钟 */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Pin = GPIO_PinX;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
/*
*********************************************************************************************************
* 函 数 名: bsp_SetTIMOutPWM
* 功能说明: 设置引脚输出的PWM信号的频率和占空比. 当频率为0,并且占空为0时,关闭定时器,GPIO输出0;
* 当频率为0,占空比为100%时,GPIO输出1.
* 形 参: GPIOx : GPIOA - GPIOK
* GPIO_Pin : GPIO_PIN_0 - GPIO__PIN_15
* TIMx : TIM1 - TIM14
* _ucChannel:使用的定时器通道,范围1 - 4
* _ulFreq : PWM信号频率,单位Hz (实际测试,可以输出100MHz),0 表示禁止输出
* _ulDutyCycle : PWM信号占空比,单位: 万分之一。如5000,表示50.00%的占空比
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetTIMOutPWM(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, TIM_TypeDef* TIMx, uint8_t _ucChannel,
uint32_t _ulFreq, uint32_t _ulDutyCycle)
{
TIM_HandleTypeDef TimHandle = {0};
TIM_OC_InitTypeDef sConfig = {0};
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t pulse;
uint32_t uiTIMxCLK;
const uint16_t TimChannel[6+1] = {0, TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4};
if (_ucChannel > 6)
{
//Error_Handler(__FILE__, __LINE__);
}
if (_ulDutyCycle == 0)
{
//bsp_RCC_TIM_Disable(TIMx); /* 关闭TIM时钟, 可能影响其他通道 */
bsp_ConfigGpioOut(GPIOx, GPIO_Pin); /* 配置GPIO为推挽输出 */
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_RESET); /* PWM = 0 */
return;
}
else if (_ulDutyCycle == 10000)
{
//bsp_RCC_TIM_Disable(TIMx); /* 关闭TIM时钟, 可能影响其他通道 */
bsp_ConfigGpioOut(GPIOx, GPIO_Pin); /* 配置GPIO为推挽输出 */
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_SET); /* PWM = 1 */
return;
}
/* 下面是PWM输出 */
bsp_ConfigTimGpio(GPIOx, GPIO_Pin, TIMx); /* 使能GPIO和TIM时钟,并连接TIM通道到GPIO */
/*-----------------------------------------------------------------------
system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
HCLK = SYSCLK / 1 (AHB1Periph)
PCLK2 = HCLK / 2 (APB2Periph)
PCLK1 = HCLK / 4 (APB1Periph)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
{
/* APB2 定时器时钟 = 168M */
uiTIMxCLK = SystemCoreClock;
}
else
{
/* APB1 定时器 = 84M */
uiTIMxCLK = SystemCoreClock / 2;
}
if (_ulFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 10000 */
usPeriod = (uiTIMxCLK / 10000) / _ulFreq - 1; /* 自动重装的值 */
}
else if (_ulFreq < 3000)
{
usPrescaler = 100 - 1; /* 分频比 = 100 */
usPeriod = (uiTIMxCLK / 100) / _ulFreq - 1; /* 自动重装的值 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _ulFreq - 1; /* 自动重装的值 */
}
pulse = (_ulDutyCycle * usPeriod) / 10000;
HAL_TIM_PWM_DeInit(&TimHandle);
#if 1
// Clock straight from internal clock.
// This can be used to chain clocks to get super-long timer periods
// much longer than maximum settings of a single timer would allow.
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&TimHandle, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
#endif
/* PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
TimHandle.Instance = TIMx;
TimHandle.Init.Prescaler = usPrescaler;
TimHandle.Init.Period = usPeriod;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = 0;
if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
{
//Error_Handler(__FILE__, __LINE__);
}
/* 配置定时器PWM输出通道 */
sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
/* 占空比 */
sConfig.Pulse = pulse;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
{
//Error_Handler(__FILE__, __LINE__);
}
/* 启动PWM输出 */
if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
{
//Error_Handler(__FILE__, __LINE__);
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_SetTIMforInt
* 功能说明: 配置TIM和NVIC,用于简单的定时中断,开启定时中断。另外注意中断服务程序需要由用户应用程序实现。
* 形 参: TIMx : 定时器
* _ulFreq : 定时频率 (Hz)。 0 表示关闭。
* _PreemptionPriority : 抢占优先级
* _SubPriority : 子优先级
* 返 回 值: 无
*********************************************************************************************************
*/
/*
TIM定时中断服务程序范例,必须清中断标志
void TIM6_DAC_IRQHandler(void)
{
if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
{
TIM6->SR = ~ TIM_FLAG_UPDATE;
//添加用户代码
}
}
*/
void bsp_SetTIMforInt(TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, uint8_t _SubPriority)
{
TIM_HandleTypeDef TimHandle = {0};
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
/* 使能TIM时钟 */
bsp_RCC_TIM_Enable(TIMx);
/*-----------------------------------------------------------------------
system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
HCLK = SYSCLK / 1 (AHB1Periph)
PCLK2 = HCLK / 2 (APB2Periph)
PCLK1 = HCLK / 4 (APB1Periph)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
{
/* APB2 定时器时钟 = 168M */
uiTIMxCLK = SystemCoreClock;
}
else
{
/* APB1 定时器 = 84M */
uiTIMxCLK = SystemCoreClock / 2;
}
if (_ulFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 10000 */
usPeriod = (uiTIMxCLK / 10000) / _ulFreq - 1; /* 自动重装的值 */
}
else if (_ulFreq < 3000)
{
usPrescaler = 100 - 1; /* 分频比 = 100 */
usPeriod = (uiTIMxCLK / 100) / _ulFreq - 1; /* 自动重装的值 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _ulFreq - 1; /* 自动重装的值 */
}
/*
定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
*/
TimHandle.Instance = TIMx;
TimHandle.Init.Prescaler = usPrescaler;
TimHandle.Init.Period = usPeriod;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
{
//Error_Handler(__FILE__, __LINE__);
}
/* 使能定时器中断 */
__HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE);
/* 配置TIM定时更新中断 (Update) */
{
uint8_t irq = 0; /* 中断号, 定义在 stm32h7xx.h */
if (TIMx == TIM1) irq = TIM1_UP_TIM10_IRQn;
else if (TIMx == TIM2) irq = TIM2_IRQn;
else if (TIMx == TIM3) irq = TIM3_IRQn;
else if (TIMx == TIM4) irq = TIM4_IRQn;
else if (TIMx == TIM5) irq = TIM5_IRQn;
else if (TIMx == TIM6) irq = TIM6_DAC_IRQn;
else if (TIMx == TIM7) irq = TIM7_IRQn;
else if (TIMx == TIM8) irq = TIM8_UP_TIM13_IRQn;
else if (TIMx == TIM9) irq = TIM1_BRK_TIM9_IRQn;
else if (TIMx == TIM10) irq = TIM1_UP_TIM10_IRQn;
else if (TIMx == TIM11) irq = TIM1_TRG_COM_TIM11_IRQn;
else if (TIMx == TIM12) irq = TIM8_BRK_TIM12_IRQn;
else if (TIMx == TIM13) irq = TIM8_UP_TIM13_IRQn;
else if (TIMx == TIM14) irq = TIM8_TRG_COM_TIM14_IRQn;
else
{
// Error_Handler(__FILE__, __LINE__);
}
HAL_NVIC_SetPriority((IRQn_Type)irq, _PreemptionPriority, _SubPriority);
HAL_NVIC_EnableIRQ((IRQn_Type)irq);
}
HAL_TIM_Base_Start(&TimHandle);
}
/***************************** (END OF FILE) *********************************/