STM32 PWM脉冲宽度调制介绍

目录

背景

[PWM 模式](#PWM 模式)

影子寄存器和预装载寄存器

PWM对齐模式

[PWM 边沿对齐模式](#PWM 边沿对齐模式)

向上计数配置

向下计数的配置

[PWM 中央对齐模式](#PWM 中央对齐模式)

程序

第一步、使能GPIOB组、AFIO、TIM3外设时钟

第二步、输出通道端口配置​编辑

第三步、定时器配置产生频率

第四步、PWM输出配置

第五步、使能预装载寄存器

第六步、使能定时器TIM3

第七步、应用中设置捕获比较寄存器


背景

PWM是单片机的常用功能。比如我可以使用来调节LED的亮度等。通过本篇文章可以了解PWM的工作原理以及STM32如何来控制脉冲的占空比。

PWM****模式

脉冲宽度调制模式可以产生一个由 TIMx_ARR 寄存器确定频率、由 TIMx_CCRx 寄存器确定占空
比的信号。

上图为向上计数且有效电平为低时的图片。什么是向上计数,什么是有效电平可以查看下文


在 TIMx_CCMRx 寄存器中的 OCxM 位写入 '110'(PWM 模式 1) 或 '111'(PWM 模式 2) ,能够独立地设
置每个 OCx 输出通道产生一路 PWM 。必须设置 TIMx_CCMRx 寄存器 OCxPE 位以使能相应的预
装载寄存器,最后还要设置 TIMx_CR1 寄存器的 ARPE 位, ( 在向上计数或中心对称模式中 ) 使能
自动重装载的预装载寄存器。
自动装载寄存器是预先装载的,写或读自动重装载寄存器将访问 预装载寄存器
仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计
数之前,必须通过设置 TIMx_EGR寄存器中的UG 位来初始化所有的寄存器
OCx的极性 可以通过软件在 TIMx_CCER 寄存器中的 CCxP 位设置, 它可以设置为高电平有效或
低电平有效TIMx_CCER 寄存器中的 CCxE 位控制 OCx 输出使能。详见 TIMx_CCERx 寄存器的
描述。
PWM模式(模式1或模式2) 下, TIMx_CNT 和 TIMx_CCRx 始终在进行比较, ( 依据计数器的计数
方向 ) 以确定是否符合 TIMx_CCRx ≤ TIMx_CNT 或者 TIMx_CNT ≤ TIMx_CCRx 。然而为了与
OCREF_CLR 的功能 ( 在下一个 PWM 周期之前, ETR 信号上的一个外部事件能够清除 OCxREF)
一致, OCxREF 信号只能在下述条件下产生:
● 当比较的结果改变,或
● 当输出比较模式 (TIMx_CCMRx 寄存器中的 OCxM 位 ) 从"冻结" ( 无比较, OCxM='000') 切
换到某个 PWM 模式 (OCxM='110' 或 '111') 。
这样在运行中可以通过软件强置 PWM 输出。
根据 TIMx_CR1 寄存器中 CMS 位的状态,定时器能够产生边沿对齐的 PWM 信号或中央对齐的
PWM 信号。

影子寄存器和预装载寄存器



我们查看通用定时器框图可以知道PSC预分频器、自动重装寄存器、捕获比较寄存器都有阴影。
这阴影部分就表示各自的影子寄存器。我们软件可以更改的是各自的预装载寄存器
一个是我们可以写入或读出的寄存器,称为 预装载寄存器 ,另一个是我们看不见的、无法真正对其读写操作的,但在使用中真正起作用的寄存器,称为 影子寄存器。 在每一次更新事件(比如说溢出)时才把预装载寄存器的内容传送到影子寄存器。通过准备好预装载寄存器,通过溢出的更新事件,会同时把预装载寄存器的内容搬运到影子寄存器当中( 实现多个寄存器设置的同步)。
PSC预分频器的影子寄存器是默认开启的 。在编程时对PSC,ARR,CCR写入值,这些直接写入的我称之为预装载寄存器。影子寄存器和预装载寄存器之间会有某种作用关系,我们称之为预装载功能
预加载不使能 :预装载寄存器与影子寄存器直连,立即更新影子寄存器的值。
预加载使能 : 预装载寄存器 在更新事件(计数器溢出,比较输出等事件)产生后再更新影子寄存器保护了原来的计数周期不受影响,在更新事件(UEV)产生后再开始新的计数

PWM对齐模式

PWM****边沿对齐模式

向上计数配置

当 TIMx_CR1 寄存器中的 DIR 位为低的时候执行向上计数。
下面是一个 PWM 模式 1 的例子。当 TIMx_CNT<TIMx_CCRx 时 PWM 信号参考 OCxREF 为高,否
则为低。如果 TIMx_CCRx 中的比较值大于自动重装载值 (TIMx_ARR) ,则 OCxREF 保持为 '1' 。
如果比较值为 0 ,则 OCxREF 保持为 '0' 。

向下计数的配置

当 TIMx_CR1 寄存器的 DIR 位为高时执行向下计数。
在 PWM 模 式 1 , 当 TIMx_CNT>TIMx_CCRx 时参考信号 OCxREF 为低,否则为高。如果
TIMx_CCRx 中的比较值大于 TIMx_ARR 中的自动重装载值,则 OCxREF 保持为 '1' 。该模式下不
能产生 0 %的 PWM 波形。

PWM****中央对齐模式

当 TIMx_CR1 寄存器中的 CMS 位不为 '00' 时,为中央对齐模式 ( 所有其他的配置对 OCxREF/OCx
信号都有相同的作用 ) 。根据不同的 CMS 位设置,比较标志可以在计数器向上计数时被置 '1' 、在
计数器向下计数时被置 '1' 、或在计数器向上和向下计数时被置 '1' 。 TIMx_CR1 寄存器中的计数方
向位 (DIR) 由硬件更新,不要用软件修改它。

程序

void TIM3_PWM_Init(u16 arr,u16 psc){  //TIM3 PWM初始化 arr重装载值 psc预分频系数
    GPIO_InitTypeDef     GPIO_InitStrue;
    TIM_OCInitTypeDef     TIM_OCInitStrue;
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseInitStrue;
    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3和相关GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟(LED在PB0引脚)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)
    
    GPIO_InitStrue.GPIO_Pin=GPIO_Pin_0;     // TIM_CH3
    GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;    // 复用推挽
    GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;    //设置最大输出速度
    GPIO_Init(GPIOB,&GPIO_InitStrue);                //GPIO端口初始化设置
    
//    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //映射,重映射只用于64、100、144脚单片机
   //当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1
   //当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1 (GPIO_PartialRemap_TIM3)
   //当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9 (GPIO_FullRemap_TIM3) 
	      
    TIM_TimeBaseInitStrue.TIM_Period=arr;    //设置自动重装载值
    TIM_TimeBaseInitStrue.TIM_Prescaler=psc;        //预分频系数
    TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up;    //计数器向上溢出
    TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1;        //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue);        //TIM3初始化设置(设置PWM的周期)
    
    TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM1;        // PWM模式1:CNT < CCR时输出有效电平
    TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效电平为:高电平
    TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
    TIM_OC3Init(TIM3,&TIM_OCInitStrue);        //TIM3的通道3 PWM 模式设置

    TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);        //使能预装载寄存器
    
    TIM_Cmd(TIM3,ENABLE);        //使能TIM3

本例子时使用PB0作为PWM的输出通道。也就是说TIM3_CH3的默认通道时PB0。

第一步、使能GPIOB组、AFIO、TIM3外设时钟

如果硬件上PB0被用作其他的功能模块使用,可以使用重映像功能。本离职中TIM3_CH3只能时PB0.

但是TIM3_CH2如果PA7被其他功能使用掉的话,可以使用重映像映射到其他的端口。

第二步、输出通道端口配置

重映射用不到!

第三步、定时器配置产生频率




查看RCC配置可以知道PCLK2为72MHZ

因为PCLK1的时钟通过2分频设置为36MHZ,所以到TIM2 3 4的时钟频率时36*2 = 72MHZ

这里面的预分频设置就是截图中的红框。

如果设置为7200-1,说明 计数器的时钟频率为72MHZ/7200 =10000HZ

TIM_Prescaler为什么要减1 ‌,主要是因为硬件会自动将设置的值加1,以防止预分频器(PSC)的值为0。在STM32中,预分频器(Prescaler)用于对输入时钟信号进行分频,从而降低定时器计数器的计数频率。预分频器的值(TIM_Prescaler)是一个无符号整数,它决定了输入时钟信号要经过多少次计数才会使定时器计数器加1。具体来说,当定时器的预分频器寄存器(TIMx_PSC)中的值为N时,输入时钟信号要经过N + 1个时钟周期,定时器计数器才会加1。因此,为了得到期望的分频系数,需要将计算得到的理论分频系数减1后再赋值给TIM_Prescaler‌

TIM_Period

TIM_Period的作用和设置方法

TIM_Period为什么要减1 ‌,主要是因为定时器的计数是从0开始的,当计数达到设定的值时才会产生中断或更新事件。因此,为了确保在计数到最后一个值时产生中断,需要将设定的值减1,这样计数器就可以在达到这个减1后的值时产生中断‌

TIM_Period代表定时器的自动重装载值(Auto-reload value),当定时器的计数值达到这个值时,定时器就会产生一个中断或更新事件。在实际使用中,需要将TIM_Period设置为所需计数值减去1,以确保在达到最大计数值时产生中断‌.

如果我们想要产生定周期为100HZ的PWM,我们可以设置为TIMx预分频后的频率/(TIM_Period设置为所需计数)值 -1(即 10000HZ/(100-1))

第四步、PWM输出配置

要特别注意TIM_OC3Init中的3表示的时TIMx定时器中的Channel3的意思。

第五步、使能预装载寄存器

第六步、使能定时器TIM3

第七步、应用中设置捕获比较寄存器

调节占空比

TIM_SetCompare3(TIM3,4500);        //改变比较值TIM3->CCR2达到调节占空比的效果

TIM_SetCompare3中的3同样表示更改的是TIMx的通道3

相关推荐
【云轩】34 分钟前
【零基础实战】用STM32玩转DRV8313电机驱动:从原理到无人机/机器人控制
stm32·机器人·无人机
2301_764602232 小时前
stm32hal库寻迹+蓝牙智能车(STM32F103C8T6)
stm32·单片机·嵌入式硬件
楼台的春风2 小时前
PWM(脉宽调制)技术详解:从基础到应用实践示例
c语言·stm32·单片机·嵌入式硬件·mcu·物联网·嵌入式
深圳市青牛科技实业有限公司 小芋圆4 小时前
芯谷D2761:为扬声器保护而生的音频限幅器
人工智能·科技·单片机·嵌入式硬件·机器人·音视频
海的预约5 小时前
51单片机-定时器中断
stm32·单片机·51单片机
Johnson Sheng9 小时前
STM32MP157A单片机移植Linux驱动
linux·stm32·单片机
Qingniu0110 小时前
芯谷D2038:高集成度六通道电子音量控制电路的音频解决方案
科技·单片机·嵌入式硬件·音视频·安防·智能插头
西城微科方案开发10 小时前
国产芯片汽车气压表pcba方案
单片机·嵌入式硬件
嵌入式学习菌10 小时前
1、FreeRTOS基础知识
单片机·嵌入式硬件
TianYaKe-天涯客11 小时前
利用AFE+MCU构建电池管理系统(BMS)
单片机·嵌入式硬件