STM32如何使用PWM?

一:PWM介绍

PWM 是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简 称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有 效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应 用的控制方式,其应用领域包括测量,通信,功率控制与变换,电动机控制、伺 服控制、调光、开关电源,甚至某些音频放大器,因此学习 PWM 具有十分重要的 现实意义。

二:PWM输出配置步骤

STM32F1 除了基本定时器 TIM6 和 TIM7,其他定时器都可以产生 PWM 输出。

其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。

而通用定 时器也能同时产生多达 4 路的 PWM 输出,这些在定时器中断章节中已经介绍 过。

(1)使能定时器及端口时钟,并设置引脚复用器映射

复制代码
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能 TIM3 时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 
最后还要记得将 PA7 管脚模式配置为复用推挽输出
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;   //复用推挽输出

(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等

复制代码
要使用定时器功能,必须对定时器内相关参数初始化,其库函数如下:
 voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseI nitStruct); 
这个在定时器中断章节就已经介绍

// 第二步 初始化定时器参数包含自动重装值,分频系数,计数方式等
TIM_TimeBaseInitStruct.TIM_Period = per;                                                  // 自动从装载值设置
TIM_TimeBaseInitStruct.TIM_Prescaler = psc;                     // 预分频该设置
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;         // 时钟分频 不分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;     //向上模式
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);

(3)初始化 PWM 输出参数,包含 PWM 模式、输出极性、使能等

复制代码
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)

主要用到的是 比较输出模式、 比较输出使能、 脉冲宽度、输出极性

(4)开启定时器

复制代码
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

第一个参数是用来选择定时器。 
第二个参数是用来使能或者失能定时器,也就是开启或者关闭定时器功能。
 同样可以选择 ENABLE 和 DISABLE
 
 TIM_Cmd(TIM3,ENABLE); //开启定时

(5)修改 TIMx_CCRx 的值控制占空比

复制代码
其实经过前面几个步骤的配置,PWM 已经开始输出了,
只是占空比和频率是 固定的,例如本章要实现呼吸灯效果,
那么就需要调节 TIM3 通道 2 的占空比, 
通过修改 TIM3_CCR2 值控制。调节占空比函数是:

void TIM_SetCompare2(TIM_TypeDef* TIMx, uint32_t Compare1);

(6)使能 TIMx 在 CCRx 上的预装载寄存器

复制代码
使能输出比较预装载库函数是: 
void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx,uint16_tTIM_OCPreload); 
第一个参数用于选择定时器,
第二个参数用于选择使能还是失能输出比较预 装载寄存器,
可选择为 TIM_OCPreload_Enable、TIM_OCPreload_Disable

(7)使能 TIMx 在 ARR 上的预装载寄存器允许位

复制代码
使能 TIMx 在 ARR 上的预装载寄存器允许位库函数是:
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalStateNewState); 

 第一个参数用于选择定时器,
 第二个参数用于选择使能还是失能。
 
 将以上几步全部配置好后,我们就可以控制通用定时器相应的通道输出 PWM 波形了,
  
 这里要特别提醒下,虽然高级定时器和通用定时器类似,
 但是高级定时 器要想输出 PWM 波形,
 必须要设置一个 MOE 位(TIMx_BDTR 的第 15 位),以使 能主输出,否则不会输出 PWM。
 
 高级定时器特殊函数 
 库函数设置的函数为: 
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalStateNewState);

三:案例 PWM波控制LED:

复制代码
#include "pwm.h"


void TIM3_CH2_PWM_Init(u16 per,u16 psc)
{
        GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        TIM_OCInitTypeDef TIM_OCInitStruct;
        
        // 第1步:(1)使能定时器及端口时钟,并设置引脚复用器映射
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // GPIOA 使能

        // GPIOA 初始化设置
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;  //选择你要设置的IO口
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;         //复用的推挽输出
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;          //设置传输速率
        GPIO_Init(GPIOA,&GPIO_InitStructure);            /* 初始化GPIO */
        GPIO_SetBits(GPIOA,GPIO_Pin_7);  
        
        
        // 第2步:(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等
        TIM_TimeBaseInitStructure.TIM_Period=per;   //自动装载值
        TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
        
        // 第3步(3)初始化 PWM 输出参数,包含 PWM 模式、输出极性、使能等
        TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // PWM1模式
        TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性
        TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;  // 使能
        TIM_OC2Init(TIM3,&TIM_OCInitStruct);
        
        // 第5步 (5)修改 TIMx_CCRx 的值控制占空比
        // 等使用的时候调用 void TIM_SetCompare2(TIM_TypeDef* TIMx, uint32_t Compare1);
        
        // 第6步(6)使能 TIMx 在 CCRx 上的预装载寄存器
        TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
        
        // 第7步(7)使能 TIMx 在 ARR 上的预装载寄存器允许位
        TIM_ARRPreloadConfig(TIM3,ENABLE);
        
        // 第4步(4)开启定时器
        TIM_Cmd(TIM3,ENABLE);
                                        
}


控制main.c
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "pwm.h"

int main()
{
        u8 i=0;
        u16 j = 0;
        u8 fx = 0;
        
        SysTick_Init(72);
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        LED_Init();
        TIM3_CH2_PWM_Init(500,72-1);//频率是 2Kh
        
        while(1)
        {        
                if(fx==0)
                {
                        j++;
                        if(j>=300)fx=1;
                                        
                }
                else
                {
                        j--;
                        if(j==0)fx=0;
                }                
                TIM_SetCompare2(TIM3,j);
                
                i++;
                if(i%10==0)
                        LED0=!LED0;
                delay_ms(10);
        }
}
相关推荐
古译汉书7 小时前
【IoT死磕系列】Day 9:架构一台“自动驾驶物流车”,看8种协议如何协同作战
网络·arm开发·单片机·物联网·tcp/ip·架构·自动驾驶
FreakStudio9 小时前
小作坊 GitHub 协作闭环:fork-sync-dev-pr-merge 实战指南
python·单片机·嵌入式·面向对象·电子diy
cmpxr_14 小时前
【单片机】位域非原子写的风险
单片机·嵌入式硬件
FPGA-ADDA14 小时前
第二篇:RFSoC芯片架构详解——处理系统(PS)与可编程逻辑(PL)
嵌入式硬件·fpga开发·信号处理·fpga·47dr
恒森宇电子有限公司15 小时前
南麟LN1151 超低静态功耗 CMOS 低压差线性稳压器 多种封装形式
单片机·嵌入式硬件
九鼎创展科技17 小时前
国产高性能 MCU 开发板新标杆:PICO2 主板深度解析
单片机·嵌入式硬件
LCG元17 小时前
STM32实战:基于STM32F103的LCD1602液晶屏(并口/模拟时序)驱动
stm32·单片机·嵌入式硬件
可乐鸡翅好好吃18 小时前
从四个 ble_evt_handler 看 Nordic BLE 架构:模块化解耦与优先级控制
单片机·嵌入式硬件
匿名了匿名了18 小时前
直流无刷与直流有刷电机
stm32·嵌入式硬件·mcu
水果里面有苹果18 小时前
26-MT41J64M16LA-187E 美光科技DDR3 SDRAM 1Gb
嵌入式硬件