海外购物网站排名,网站开发常用的谷歌插件,开发公司预算员工作内容及职责,做网站会员推广哪个好STM32H7定时器TIM1-TIM17中断、PWM实现 高级定时器硬件框图定时器模式时基输出PWM定时器输入捕获 TIM1-TIM17的中断配置TIM1-TIM17的PWM输出 STM32H7 支持的定时器有点多#xff0c;要简单的区分下。STM32H7 支持 TIM1-TIM8#xff0c;TIM12-TIM17 共14 个定时器#xff0c;… STM32H7定时器TIM1-TIM17中断、PWM实现 高级定时器硬件框图定时器模式时基输出PWM定时器输入捕获 TIM1-TIM17的中断配置TIM1-TIM17的PWM输出 STM32H7 支持的定时器有点多要简单的区分下。STM32H7 支持 TIM1-TIM8TIM12-TIM17 共14 个定时器而中间的 TIM9TIM10TIM11 是不存在的这点要注意。 高级定时器硬件框图
我们直接看最复杂的高级定时器 TIM1TIM8 框图 通过这个框图我们可以得到如下信息 TIMx_ETR 接口 外部触发输入接口。ETR 支持多种输入源输入引脚默认配置、比较器输出和模拟看门狗。 截图左侧的 TIMx_CH1TIMx_CH2TIMx_CH3 和 TIMx_CH4 接口 这四个通道主要用于输入捕获可以计算波形频率和脉宽。 TIMx_BKIN 和 TIMx_BKIN2 接口 断路功能主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关 TRGO 内部输出通道 主要用于定时器级联ADC 和 DAC 的定时器触发。 6 组输出比较单元 OC1 到 OC6 OC1 到 OC4 有对应的输出引脚而 OC5 和 OC6 没有对应的输出引脚主要用于内部控制。 截图右侧的输出比较通道 TIMx_CH1TIMx_CH1NTIMx_CH2 TIMx_CH2NTIMx_CH3 TIMx_CH3N 和 TIMx_CH4 主要用于 PWM 输出注意 CH1 到 CH3 有互补输出而 CH4 没有互补输出。
定时器模式
时基
定时器要工作就需要一个基本时基单元而基本的时基单元是由下面几个寄存器组成的 预分频器寄存器 (TIMx_PSC) 用于设置定时器的分频比如定时器的主频是 200MHz通过此寄存器可以将其设置为 100MHz 50MHz25MHz 等分频值。 注预分频器有个缓冲功能可以让用户实时更改新的预分频值将在下一个更新事件发生时被采用 以递增计数模式为例就是 CNT 计数值达到 ARR 自动重装寄存器的数值时会产生更新事件。 计数器寄存器 (TIMx_CNT) 计数器是最基本的计数单元计数值是建立在分频的基础上面比如通过 TIMx_PSC 设置分频后的频 率为 100MHz那么计数寄存器计一次数就是 10ns。 自动重载寄存器 (TIMx_ARR) 自动重装寄存器是 CNT 计数寄存器能达到的最大计数值以递增计数模式为例就是 CNT 计数器达 到 ARR 寄存器数值时重新从 0 开始计数。 注自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预 装载寄存器的内容既可以立即传送到影子寄存器让设置立即起到效果的寄存器也可以在每次发 生更新事件时传送到影子寄存器。简单的说就是让 ARR 寄存器的数值立即更新还是更新事件发送的 时候更新。 重复计数器寄存器 (TIMx_RCR) 以递增计数模式为例当 CNT 计数器数值达到 ARR 自动重载数值时重复计数器的数值加 1重复 次数达到 TIMx_RCR 1 后就将生成更新事件。 注只有 TIM1TIM8TIM15TIM16TIM17 有此寄存器。 比如我们要配置定时器实现周期性的中断主要使用这几个寄存器即可。
输出PWM
使用定时器时基单元的那几个寄存器仅仅能设置周期还不能设置占空比。针对这个问题还需要比 较捕获寄存 CCR 的参与这样就可以设置占空比了。 为了方便大家理解以 PWM 边沿对齐模式递增计数配置为例 当计数器 TIMx_CNT 比较捕获寄存器 TIMx_CCRx 期间PWM 参考信号 OCxREF 输出高电平。 当计数器 TIMx_CNT 比较捕获寄存器 TIMx_CCRx 期间PWM 参考信号 OCxREF 输出低电平。 当比较捕获寄存器 TIMx_CCRx 自动重载寄存器 TIMx_ARROCxREF 保持为 1。 当比较捕获寄存器 TIMx_CCRx 0则 OCxRef 保持为 0。
定时器输入捕获
与 PWM 一样使用定时器实现输入捕获仅靠时基单元的那几个寄存器是不行的我们需要一个寄 存器来记录发生捕获时的具体时间这个寄存器依然由比较捕获寄存器 TIMx_CCRx 来实现。 比如我们要测量一路方波的周期 配置定时器为输入捕获模式上升沿触发设置分频自动重装等寄存器比如设置的 CNT 计数器计数 1 次是 1 微秒。 当有上升沿触发的时候TIMx_CCRx 寄存器就会自动记录当前的 CNT 数值然后用户就可以通过CC 中断在中断复位程序里面保存当前的 TIMx_CCRx 寄存器数值。等下次再检测到上升沿触发两次时间求差就可以得到方波的周期。 不过这里要特别注意一点如果 CNT 发生溢出比如 16 位定时器计数到 65535 就溢出了 就需要特别处理下将 CNT 计数溢出考虑进来。
TIM1-TIM17的中断配置
/*
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);/*-----------------------------------------------------------------------bsp.c ÎļþÖÐ void SystemClock_Config(void) º¯Êý¶ÔʱÖÓµÄÅäÖÃÈçÏÂ: System Clock source PLL (HSE)SYSCLK(Hz) 400000000 (CPU Clock)HCLK(Hz) 200000000 (AXI and AHBs Clock)AHB Prescaler 2D1 APB3 Prescaler 2 (APB3 Clock 100MHz)D2 APB1 Prescaler 2 (APB1 Clock 100MHz)
D2 APB2 Prescaler 2 (APB2 Clock 100MHz)
D3 APB4 Prescaler 2 (APB4 Clock 100MHz)因为 APB1 prescaler ! 1, 所以 APB1 上的 TIMxCLK APB1 x 2 200MHz;
因为 APB2 prescaler ! 1, 所以 APB2 上的 TIMxCLK APB2 x 2 200MHz;APB4 上面的 TIMxCLK 没有分频所以就是 100MHz;APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14LPTIM1APB2 定时器有 TIM1, TIM8 , TIM15, TIM16TIM17APB4 定时器有 LPTIM2LPTIM3LPTIM4LPTIM5----------------------------------------------------------------------- */if ((TIMx TIM1) || (TIMx TIM8) || (TIMx TIM15) || (TIMx TIM16) || (TIMx TIM17)){/* APB2 定时器时钟 200M */uiTIMxCLK SystemCoreClock / 2;}else {/* APB1 定时器 200M */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; /* 自动重装的值 */
98. }}else /* APB1 定时器 200M */{usPrescaler 0; /* 分频比 1 */usPeriod uiTIMxCLK / _ulFreq - 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_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 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 if (TIMx TIM15) irq TIM15_IRQn;else if (TIMx TIM16) irq TIM16_IRQn;else if (TIMx TIM17) irq TIM17_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);
}TIM1-TIM17的PWM输出
/*
2. ******************************************************************************************************
3. * 函 数 名: bsp_ConfigTimGpio
4. * 功能说明: 配置 GPIO 和 TIM 时钟 GPIO 连接到 TIM 输出通道
5. * 形 参: GPIOx : GPIOA - GPIOK
6. * GPIO_PinX : GPIO_PIN_0 - GPIO__PIN_15
7. * TIMx : TIM1 - TIM17
8. * 返 回 值: 无
9. ******************************************************************************************************
10. */
void bsp_ConfigTimGpio(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinX, TIM_TypeDef* TIMx)
{GPIO_InitTypeDef GPIO_InitStruct;bsp_RCC_GPIO_Enable(GPIOx);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);
}
/*
2. ******************************************************************************************************
3. * 函 数 名: bsp_ConfigGpioOut
4. * 功能说明: 配置 GPIO 为推挽输出。主要用于 PWM 输出占空比为 0 和 100 的情况。
5. * 形 参: GPIOx : GPIOA - GPIOK
6. * GPIO_PinX : GPIO_PIN_0 - GPIO__PIN_15
7. * 返 回 值: 无
8. ******************************************************************************************************
9. */
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);
}
/*
24. * 函 数 名: bsp_SetTIMOutPWM
25. * 功能说明: 设置引脚输出的 PWM 信号的频率和占空比. 当频率为 0并且占空为 0 时关闭定时器GPIO 输出 0
26. * 当频率为 0占空比为 100%时GPIO 输出 1.
27. * 形 参: GPIOx : GPIOA - GPIOK
28. * GPIO_Pin : GPIO_PIN_0 - GPIO__PIN_15
29. * TIMx : TIM1 - TIM17
30. * _ucChannel使用的定时器通道范围 1 - 4
31. * _ulFreq : PWM 信号频率单位 Hz (实际测试可以输出 100MHz. 0 表示禁止输出
32. * _ulDutyCycle : PWM 信号占空比单位: 万分之一。如 5000表示 50.00%的占空比
33. * 返 回 值: 无
34. ******************************************************************************************************
35. */
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[61] {0, TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4, TIM_CHANNEL_5, TIM_CHANNEL_6};if (_ucChannel 6){Error_Handler(__FILE__, __LINE__);}if (_ulDutyCycle 0){ bsp_ConfigGpioOut(GPIOx, GPIO_Pin); GPIOx-BSRRH GPIO_Pin; /* PWM 0 */ return;}else if (_ulDutyCycle 10000){bsp_ConfigGpioOut(GPIOx, GPIO_Pin); GPIOx-BSRRL GPIO_Pin; return;}bsp_ConfigTimGpio(GPIOx, GPIO_Pin, TIMx); if ((TIMx TIM1) || (TIMx TIM8) || (TIMx TIM15) || (TIMx TIM16) || (TIMx TIM17)){uiTIMxCLK SystemCoreClock / 2;}else {uiTIMxCLK SystemCoreClock / 2;}if (_ulFreq 100){usPrescaler 10000 - 1; usPeriod (uiTIMxCLK / 10000) / _ulFreq - 1; }else if (_ulFreq 3000){usPrescaler 100 - 1; usPeriod (uiTIMxCLK / 100) / _ulFreq - 1; }else {usPrescaler 0; usPeriod uiTIMxCLK / _ulFreq - 1; }pulse (_ulDutyCycle * usPeriod) / 10000;HAL_TIM_PWM_DeInit(TimHandle);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__);}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__);}if (HAL_TIM_PWM_Start(TimHandle, TimChannel[_ucChannel]) ! HAL_OK){Error_Handler(__FILE__, __LINE__);}
}