嵌入式物联网开发(三)如何配置N32G45的TIM实现PWM调光
要改变小功率LED灯的亮度,通常可以通过PWM控制LED电源的通断来实现,N32G452的PWM功能可以通过TIM的比较输出来实现,下面我们通过以下几个步骤来实现输出一个2Khz,占空比从0%-100%可调的PWM波形:
- 配置GPIO为TIM的比较输出通道,这里使用的是TIM2-CH2, 对应的是GPIOA_1管脚,需要设置为复用功能
void GPIO_Configuration(void)
{GPIO_InitType GPIO_InitStructure;/* 配置GPIO输出,继电器开关 */GPIO_InitStructure.Pin = GPIO_PIN_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure); GPIO_WriteBit(GPIOB, GPIO_PIN_2, Bit_RESET); // 初始化时默认关灯/* 配置 TIM2-CH2 作为PWM调光输出 */GPIO_InitStructure.Pin = GPIO_PIN_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
- 使能GPIOA和TIM2及IO复用功能的时钟
void RCC_Configuration(void)
{/* Enable GPIO & AFIO clock */GPIO_APBxClkCmd(RCC_APB2_PERIPH_AFIO, ENABLE);GPIO_APBxClkCmd(RCC_APB2_PERIPH_GPIOA, ENABLE);/* Enable TIM2 clock */RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);
}
- 配置TIM2实现PWM输出功能,根据手册,TIM2属于AHB1总线下的设备,其时钟最大是36Mhz,初始化代码也将其配置为了36Mhz,它由144M的HCLK经过4分频而来,当AHB1的分频不是1时,TIM2的时钟为AHB1的2倍,即36M*2 = 72M。
/*** @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1* prescalers.*/
static void SetSysClock(void)
{ /* 其他代码略 *//* PCLK1 max 36M */if (SYSCLK_FREQ > 72000000){RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV4;}else if (SYSCLK_FREQ > 36000000){RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV2;}else{RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV1;}/* 其他代码略 */
}
为了实现输出2K的频率,需要进行如下配置
void TIM2_PWM_Init(void)
{/*** 以下配置会在TIM2-CH2通道(GPIOA_1)产生2KHz的PWM输出* 特殊占空比: 当Pulse设置为0时,PWM输出保持为低电平, Pulse=100(>Period)时,PWM持续输出高电平,* 由于这个特性,当关灯或开灯时,不必用切换PWM为GPIO的方式来输出高低电平,直接配置PWM的Pulse即可*/uint16_t PrescalerValue = 0;TIM_TimeBaseInitType TIM_TimeBaseStructure;OCInitType TIM_OCInitStructure;uint16_t CCR2_Val = 0; // Pulse: 0-100, 初始化时默认0%/* TIM2 clock enable */RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);/* Compute the prescaler value *//*** AHB1的时钟是36Mhz,分频不是1,则TIM2的时钟为AHB1的2倍 * 预分频值 = TIM2_CLK / (2000 * (AAR+1)) - 1 = 72000000 / (2000 * (99+1) ) - 1 = 359*/PrescalerValue = 359; /* Time base configuration */TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);/* 为了方便直接输出高电平,设置Pulse为100即可 */TIM_TimeBaseStructure.Period = 99;TIM_TimeBaseStructure.Prescaler = PrescalerValue;TIM_TimeBaseStructure.ClkDiv = 0;TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP;TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure); /* PWM1 Mode configuration: Channel1 */TIM_InitOcStruct(&TIM_OCInitStructure);TIM_OCInitStructure.OcMode = TIM_OCMODE_PWM1;TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;TIM_OCInitStructure.Pulse = CCR2_Val;TIM_OCInitStructure.OcPolarity = TIM_OC_POLARITY_HIGH;TIM_InitOc2(TIM2, &TIM_OCInitStructure);TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);TIM_ConfigArPreload(TIM2, ENABLE);/* TIM3 enable counter */TIM_Enable(TIM2, ENABLE);
}
其中TIM2的预分频值PSC及重载值AAR(Period)根据以下公式计算:
4. 实现一个动态修改占空比的函数:
static void PWM_Output_Controll(int channel, int value)
{/* 继电器的控制 */if ( value == 0){GPIO_WriteBit(GPIOB, GPIO_PIN_2, Bit_RESET);}else if ( value == 100){GPIO_WriteBit(GPIOB, GPIO_PIN_2, Bit_SET);}else{GPIO_WriteBit(GPIOB, GPIO_PIN_2, Bit_SET);} /* 修改占空比 */TIM_Enable(TIM2, DISABLE); /* 先停止定时器 */TIM2->CCDAT2 = value; /* 修改计数值 */TIM_Enable(TIM2, ENABLE); /* 重新使能定时器 */
}
- 验证测试:
/*** @brief Main program*/
int main(void)
{/* Init the Logger */Logger_Init();TIM2_PWM_Init();int dimm = 0;while(1){printf("dimm: %d\r\n", dimm);PWM_Output_Controll(0, dimm); HAL_Delay(100);dimm++;dimm %= 101;}return (0);
}
上述代码初始化了TIM2的通道2为比较输出模式,然后每隔100毫秒占空比步进1%,通过观察逻辑分析仪抓取GPIOA_1管脚输出的信号,可以看到由正确的波形产生:
从低电平开始到占空比1%
占空比50%
占空比从99%到持续高电平(100%)
如此,PWM调光的核心功能就实现了。