PWM,是英文“ Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,就是对脉冲宽度的控制。脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。PWM普遍使用在电机调速和灯具调光方面等,
图中,我们假定定时器工作在向上计数 PWM模式,且当 CNT<CCRx 时,输出 0,当 CNT>=CCRx 时输出 1。那么就可以得到如上的 PWM示意图:当 CNT 值小于 CCRx 的时候, IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的频率,这就是 PWM 输出的原理。
使用 NUCLEO-STM32F767ZI 的 TIM3_CH3(PB0) 输出 PWM,实现 LD1 的呼吸灯效果。板子上的 PB0 可以控制 LD1 的亮灭,刚好 PB0 是定时器TIM3的CH3通道,可以用来输出PWM信号。
NUCLEO-STM32F767ZI
NUCLEO-F767上的LD1部分原理图
代码部分:注释很清楚了
/******************************************************************************
* File Name : timer.c
* Description : This file provides code for the configuration
* of the TIM instances.
arr:自动重装值, psc:时钟预分频数 ,Ft=定时器工作频率,单位:Mhz, 定时器 3 挂在 APB1 上,时钟为 HCLK/2
Tout=((arr+1)*(psc+1))/Ft us.
******************************************************************************/
#include "timer.h"
TIM_HandleTypeDef HTIM3;
TIM_OC_InitTypeDef sConfigOC;
/* TIM3 init function,APB1 Clock:108MHz*/
void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
HTIM3.Instance = TIM3;
HTIM3.Init.Prescaler = 108-1; //预分频值PSC 108MHz/108=1MHz
HTIM3.Init.CounterMode = TIM_COUNTERMODE_UP;//向上计数
HTIM3.Init.Period = 500-1; //自动重装载值ARR PWM频率:1MHz/500 =2kHz
HTIM3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;//设置时钟分频因子
HTIM3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;//
if (HAL_TIM_Base_Init(&HTIM3) != HAL_OK)//初始化定时器 3
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;//时钟源使用内部时钟APB1 --- 108MHz
if (HAL_TIM_ConfigClockSource(&HTIM3, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_PWM_Init(&HTIM3) != HAL_OK)//初始化PWM
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&HTIM3, &sMasterConfig) != HAL_OK)//
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;//PWM1 Mode
sConfigOC.Pulse = 0; //捕获比较值
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;//输出极性高
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; //快速模式
if (HAL_TIM_PWM_ConfigChannel(&HTIM3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
HAL_TIM_PWM_Start(&HTIM3, TIM_CHANNEL_3);//开启TIM3通道3的PWM
HAL_TIM_MspPostInit(&HTIM3);
//HAL_TIM_Base_Start_IT(&HTIM3); //使能定时器 3 和定时器 3 更新中断
}
//定时器底册驱动,开启时钟,设置中断优先级
//此函数会被 HAL_TIM_Base_Init()函数调用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
/* TIM3 clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* TIM3 interrupt Init */
HAL_NVIC_SetPriority(TIM3_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/* USER CODE BEGIN TIM3_MspInit 1 */
/* USER CODE END TIM3_MspInit 1 */
}
}
//此函数会被 HAL_TIM_PWM_Init()函数调用
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(htim->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
__HAL_RCC_TIM3_CLK_ENABLE();
/* USER CODE END TIM3_MspPostInit 0 */
/**TIM3 GPIO Configuration
PB0 ------> TIM3_CH3
*/
GPIO_InitStruct.Pin = PWM_LD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用推挽输出
GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(PWM_LD1_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(timHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
/**TIM3 GPIO Configuration
PB0 ------> TIM3_CH3
*/
GPIO_InitStruct.Pin = PWM_LD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//复用推挽输出
GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(PWM_LD1_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspDeInit 0 */
/* USER CODE END TIM3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM3_CLK_DISABLE();
/* TIM3 interrupt Deinit */
HAL_NVIC_DisableIRQ(TIM3_IRQn);
/* USER CODE BEGIN TIM3_MspDeInit 1 */
/* USER CODE END TIM3_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
//设置 TIM3 通道 3 的占空比 compare:比较值 //compare/100 * ARR
void TIM_SetTIM3Compare(uint32_t compare)
{
TIM3->CCR3=compare;
}
//TIM3,Compare2/100 * ARR
void TIM3_CH3_SetCompare(TIM_TypeDef *TIMx,uint32_t compare)
{
sConfigOC.Pulse=compare;
HAL_TIM_PWM_ConfigChannel(&HTIM3,&sConfigOC,TIM_CHANNEL_3);
}
//呼吸灯
uint8_t LD1_dir = 0;
uint16_t LD1_PWM_Value = 0;
void TIM3_CH3PWM_BreatheLED(void)
{
if(LD1_dir == 0)
{
LD1_PWM_Value ++;
if(LD1_PWM_Value >= 300)
{
LD1_dir = 1;
}
}
else
{
LD1_PWM_Value --;
if(LD1_PWM_Value <= 10)
{
LD1_dir = 0;
}
}
TIM_SetTIM3Compare(LD1_PWM_Value);
}
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
//滴答时钟
uint16_t Breathe_Count;
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
/* USER CODE BEGIN SysTick_IRQn 1 */
TempVref_count++;
Breathe_Count++;
if(Breathe_Count >= BREATHE_TIMER)//10ms
{
TIM3_CH3PWM_BreatheLED();//呼吸灯
Breathe_Count = 0;
}
/* USER CODE END SysTick_IRQn 1 */
}
|