学习如何让STM32在运行时改变PWM频率和占空比

您所在的位置:网站首页 stm32波形发生器最大频率 学习如何让STM32在运行时改变PWM频率和占空比

学习如何让STM32在运行时改变PWM频率和占空比

2024-07-16 17:04| 来源: 网络整理| 查看: 265

前言

        最近有个需求是关于调节占空比去控制风扇实现三挡风力大小的。由于硬件供电和控制成本等原因,普通的芯片支撑不起几个风扇同时转起来,于是就沿用了一个神奇的电路方案,但是这个方案在输出占空比的时候达不到真正的占空比(这里解释不清),因为电机类需要特别注意频率的大小,频率太高或者太低或多或少都会让人耳接受不了,反正是需要在运行时同时改变PWM频率和占空比,本文着重于应用,不讲原理。

一、定时器介绍

        使用的是野火指南者STM32F103VET6,该板子有8个定时器,其中TIM6和TIM7属于基本定时器,TIM1和TIM8属于高级定时器,本文使用通用定时器TIM3即可。

定时器分类(适用于指南者) TIMx功能基本定时器TIM6、TIM7基本定时,也可用于触发 DAC 外设。通用定时器TIM2、TIM3、TIM4、TIM5输出比较(时序和延迟生成)、单脉冲模式、输入捕获(用于测量 外部信号频率)、传感器接口(编码器和霍尔传感器)等各种场合。  高级定时器TIM1、TIM8除通用功能外,它们还包含一些与电机控制和数字能量转换应用相关的功能:三个带死区控制的互补信号以及紧急关断输入。 单通道或双通道定时器:用作通用定时器,通道数有限。 带互补输出的单通道或双通道定时器:与上一类型相同,只是其中一个通道上具有死区发生器。这样可得到时基与高级定时器无关的互补信号。  

二、PWM的周期、频率、占空比计算

        在stm32中PWM的周期、频率、占空比等计算基本上是使用了TIM的时基单元,下面是时基结构体的介绍。

typedef struct { uint16_t TIM_Prescaler //驱动CNT计数器的分频器1-65536,都有 uint16_t TIM_CounterMode //计数器计数模式,TIMx,x[6,7]没有,其他都有 uint16_t TIM_Period //自动重装载寄存器,都有 uint16_t TIM_ClockDivision //时钟分频因子,TIMx,x[6,7]没有,其他都有 uint8_t TIM_RepetitionCounter //重复计数器的值,TIMx,x[1,8]才有 }TIM_TimeBaseInitTypeDef;

注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有 TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可, 另外三个成员是通用定时器和高级定时器才有。

所以,本文使用该板子上TIM3定时器的通道CH1。

引脚TIMx通道PA6TIM3CH1

输出比较结构体介绍:

typedef struct { uint16_t TIM_OCMode; //PWM模式 uint16_t TIM_OutputState; //输出使能 uint16_t TIM_OutputNState; //指定TIM互补输出比较状态TIMx,x[1,8]才有 uint16_t TIM_Pulse; //要加载到捕获比较寄存器中的脉冲值CCR uint16_t TIM_OCPolarity; //输出通道电平极性配置 uint16_t TIM_OCNPolarity; //指定互补输出极性TIMx,x[1,8]才有 uint16_t TIM_OCIdleState; //指定空闲状态时的TIM输出比较引脚状态TIMx,x[1,8]才有 uint16_t TIM_OCNIdleState; //指定空闲状态时的TIM输出比较引脚状态TIMx,x[1,8]才有 } TIM_OCInitTypeDef;

/* ----------------   PWM信号 周期和占空比的计算--------------- */ ARR :自动重装载寄存器的值 PSC:分频系数 CCR:高电平脉冲值比例,用于计算占空比 CLK_Fre:PWM时钟频率,CLK_Fre = Fre_int / (psc+1)/ARR = 72M/(psc+1)/ARR PWM 信号的周期 T = 1/CLK_Fre = ARR*(PSC+1) / 72M 占空比P=CCR/(ARR+1)

注意:CCR并不都是高电平占比,需要根据TIM_OCInitStructure.TIM_OCPolarity输出的极性进行判断。

三:代码步骤

1、初始化TIM3_CH1的GPIO

void GENERAL_TIM_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 输出比较通道1 GPIO 初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); }

2、配置时基结构体和输出比较结构体

void GENERAL_TIM_Mode_Config(void) { // 开启定时器时钟,即内部时钟CK_INT=72M GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE); /*--------------------时基结构体初始化-------------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period=(100-1); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Prescaler= (72-1); // 驱动CNT计数器的分频器1-65536 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 时钟分频因子 ,配置死区时间时需要用到 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 重复计数器的值,没用到不用管 TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);// 初始化定时器 /*--------------------输出比较结构体初始化-------------------*/ TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 配置为PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置 // 输出比较通道 1 TIM_OCInitStructure.TIM_Pulse = 0; //CCR,间接调节占空比的重要参数 TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure); TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); // 使能计数器 TIM_Cmd(GENERAL_TIM, ENABLE); }

3、编写改变占空比的接口

void PWM_SetPrescaler(uint16_t Prescaler)//改变预分频系数 { TIM_PrescalerConfig(TIM3, Prescaler,TIM_PSCReloadMode_Update); } void PWM_SetCompare1(uint16_t Compare) //改变CCR、高电平的比例 { TIM_SetCompare1(TIM3, Compare); } void PWM_SetARR1(uint32_t Autoreload) //改变自动重装载值 { TIM_Cmd(TIM3,DISABLE); TIM_ARRPreloadConfig(TIM3,DISABLE); TIM_SetAutoreload(TIM3, Autoreload); TIM_ARRPreloadConfig(TIM3,ENABLE); TIM_Cmd(TIM3,ENABLE); }

注意:根据手册,改变ARR需要先失能TIM_ARR配置,但是我在实测的时候没发现有什么不同,不过为了避免出现问题,还是把该有的流程走一遍,预分频器PSC就不用每次都要失能一下。

4、主函数

int main(void) { GENERAL_TIM_GPIO_Config(); GENERAL_TIM_Mode_Config(); Key_GPIO_Config(); LED_GPIO_Config(); while(1) { if(Key_Scan(GPIOA ,GPIO_Pin_0) ==1) { LED1_TOGGLE; Speed += 1; if (Speed > 2)Speed = 0; if(Speed ==0) { PWM_SetCompare1(0); } else if(Speed ==1){ // PWM_SetARR1(200-1); PWM_SetCompare1(30); // PWM_SetPrescaler(36-1); } else if(Speed ==2){ // PWM_SetARR1(100-1); PWM_SetCompare1(50); // PWM_SetPrescaler(36-1); } } } }

四:实验现象

1、单独改变占空比

        根据下面示波器抓到的波形,可以看到,单独改变占空比只需要改变CCR的值就好(但是要注意的是CCR只是间接影响到占空比),不会影响到频率和周期。

(1)PWM_SetCompare1(30);

频率=72000000/(99+1)/(71+1)=10k 周期=1/频率=0.0001s=100us 占空比=30/100=30%

(2)PWM_SetCompare1(50);

占空比=50/100=50%

2、单独改变自动重装载值

PWM_SetARR1(200-1); 频率=72000000/(199+1)/(71+1)=5k 周期=1/频率=0.0002s=200us 占空比=30/200=15%

3、单独改变预分频系数

PWM_SetPrescaler(36-1); 频率=72000000/(99+1)/(35+1)=20k 周期=1/频率=0.00049s=49us 占空比=30/100=30%

总结

        该实验是为了学习多种方式改变PWM频率占空比,实验过程只是一个很简单的例子,也可以换到更高主频的MCU试验。然后,如有错误的地方被看到,一切以手册为准。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3