历史上的今天
返回首页

历史上的今天

今天是:2024年12月09日(星期一)

正在发生

2021年12月09日 | 【STM32】PWM 输出 (标准库)

2021-12-09 来源:eefocus

一、PWM简介

PWM:脉冲宽度调制(Pulse width modulation,PWM)


脉冲宽度调制是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。——百度百科


二、PWM输出模式

PWM 输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装 寄存器 ARR 的值决定,占空比由 比较寄存器 CCR 的值决定。


PWM 模式分为两种,PWM1和 PWM2。区别如下:

image.png?imageView2/2/w/550

三、初始化结构体

1. TIM_TimeBaseInitTypeDef

 typedef struct {   

  uint16_t TIM_Prescaler;          // 预分频器   

uint16_t TIM_CounterMode;        // 计数模式   

uint32_t TIM_Period;             // 定时器周期   

  uint16_t TIM_ClockDivision;      // 时钟分频  

uint8_t TIM_RepetitionCounter;   // 重复计算器  

 } TIM_TimeBaseInitTypeDef; 

结构体具体介绍参见:【STM32】TIM—基本定时器


2. TIM_OCInitTypeDef

/** 

  * @brief  TIM Output Compare Init structure definition  

  */


typedef struct

{

  uint16_t TIM_OCMode;        /*!< Specifies the TIM mode.

                                   This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */


  uint16_t TIM_OutputState;   /*!< Specifies the TIM Output Compare state.

                                   This parameter can be a value of @ref TIM_Output_Compare_State */


  uint16_t TIM_OutputNState;  /*!< Specifies the TIM complementary Output Compare state.

                                   This parameter can be a value of @ref TIM_Output_Compare_N_State

                                   @note This parameter is valid only for TIM1 and TIM8. */


  uint32_t TIM_Pulse;         /*!< Specifies the pulse value to be loaded into the Capture Compare Register. 

                                   This parameter can be a number between 0x0000 and 0xFFFF */


  uint16_t TIM_OCPolarity;    /*!< Specifies the output polarity.

                                   This parameter can be a value of @ref TIM_Output_Compare_Polarity */


  uint16_t TIM_OCNPolarity;   /*!< Specifies the complementary output polarity.

                                   This parameter can be a value of @ref TIM_Output_Compare_N_Polarity

                                   @note This parameter is valid only for TIM1 and TIM8. */


  uint16_t TIM_OCIdleState;   /*!< Specifies the TIM Output Compare pin state during Idle state.

                                   This parameter can be a value of @ref TIM_Output_Compare_Idle_State

                                   @note This parameter is valid only for TIM1 and TIM8. */


  uint16_t TIM_OCNIdleState;  /*!< Specifies the TIM Output Compare pin state during Idle state.

                                   This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State

                                   @note This parameter is valid only for TIM1 and TIM8. */

} TIM_OCInitTypeDef;


(1) TIM_OCMode:比较输出模式选择,总共有八种,常用的为 PWM1/PWM2。它设定 CCMRx寄存器 OCxM[2:0]位的值。


(2) TIM_OutputState:比较输出使能,决定最终的输出比较信号 OCx是否通过外部引脚输出。它设定 TIMx_CCER寄存器 CCxE/CCxNE 位的值。


(3) TIM_OutputNState:比较互补输出使能,决定 OCx的互补信号 OCxN是否通过外部引脚输出。它设定 CCER寄存器 CCxNE 位的值。


(4) TIM_Pulse:比较输出脉冲宽度,实际设定比较寄存器 CCR的值,决定脉冲宽度。可设置范围为 0至 65535。


(5) TIM_OCPolarity:比较输出极性,可选 OCx为高电平有效或低电平有效。它决定着定时器通道有效电平。它设定 CCER寄存器的 CCxP位的值。


(6) TIM_OCNPolarity:比较互补输出极性,可选 OCxN 为高电平有效或低电平有效。它设定 TIMx_CCER寄存器的 CCxNP位的值。


(7) TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出 1或输出 0,即在空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器通道输出高电平或低电平。它设定 CR2寄存器的 OISx位的值。


(8) TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出 1 或输出 0,即在空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器互补通道输出高电平或低电 平,设定值必须与 TIM_OCIdleState 相反。它设定是 CR2 寄存器的 OISxN 位的值。


四、PWM输出实验

编程思路

初始化 LED

初始化延时函数

开启定时器时钟

设置定时器周期和预分频器

初始化定时器

主函数中修改比较值和占空比

pwm.h

// =============================================

# @Time    : 2020-10-24

# @Author  : AXYZdong

# @CSDN    : https://blog.csdn.net/qq_43328313

# @FileName: pwm.h

# @Software: keil5 MDK

// =============================================


#ifndef _TIME_H

#define _TIME_H


#include "stm32f4xx.h"

void TIM3_PWM_Init(u32 ARR , u32 PSC);


#endif


pwm.c

// =============================================

# @Time    : 2020-10-24

# @Author  : AXYZdong

# @CSDN    : https://blog.csdn.net/qq_43328313

# @FileName: pwm.c

# @Software: keil5 MDK

// =============================================


#include "pwm.h"

#include "bsp_led.h"


extern void TIM3_PWM_Init(u32 ARR , u32 PSC);


void TIM3_PWM_Init(u32 ARR , u32 PSC)

{  

//此部分需手动修改IO口设置

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  //TIM3时钟使能    

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟

GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3); //GPIOA6复用为定时器3

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;           //GPIOFA

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉

GPIO_Init(GPIOA,&GPIO_InitStructure);              //初始化PA6

  

TIM_TimeBaseStructure.TIM_Prescaler=PSC;  //定时器分频

TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式

TIM_TimeBaseStructure.TIM_Period=ARR;   //自动重装载值

TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 

TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//初始化定时器3

//初始化TIM14 Channel1 PWM模式  

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低

TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM1 4OC1


TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器

 

    TIM_ARRPreloadConfig(TIM3,ENABLE);//ARPE使能 

TIM_Cmd(TIM3, ENABLE);  //使能TIM3   


main.c

// =============================================

# @Time    : 2020-10-24

# @Author  : AXYZdong

# @CSDN    : https://blog.csdn.net/qq_43328313

# @FileName: main.c

# @Software: keil5 MDK

// =============================================


#include "stm32f4xx.h"

#include "delay.h"

#include "pwm.h"

#include "bsp_led.h"


int main(void)

{

u16 ledpwmval=0;

u8 flag=1;

delay_init(168); //初始化延时函数

  LED_GPIO_Config();     //初始化LED

  TIM3_PWM_Init(100-1,84-1); //初始化定时器

while(1)

{

delay_ms(10);

if(flag)ledpwmval++;

else ledpwmval--;

if(ledpwmval==0)flag=1;

if(ledpwmval==40)flag=0;

TIM_SetCompare1(TIM3,ledpwmval); //修改比较值,修改占空比

  }

}


五、总结

PWM输出,观察到 LED 缓慢变亮又缓慢变暗的状态(呼吸灯)

通过对定时器初始化数据和比较值的修改,可以改变亮暗时间


【参考文献】


[1] 《零死角玩转 STM32—基于野火 F407[霸天虎]开发板 》

推荐阅读

史海拾趣

Deltrol Controls公司的发展小趣事

在电子设备的制造过程中,螺线管是不可或缺的元件之一。然而,传统的螺线管生产方式存在效率低下、质量不稳定等问题。Deltrol Controls通过引进先进的生产设备和技术,实现了螺线管的精细化生产。这一举措不仅提高了生产效率,而且保证了螺线管的质量稳定性。凭借这一优势,Deltrol Controls在电子行业中的竞争力得到了显著提升。

Electro-Term/Hollingsworth公司的发展小趣事

面对全球电子市场的不断变化,Electro-Term公司及时调整了市场布局和战略方向。公司深入分析了不同地区的市场需求和消费者偏好,制定了有针对性的市场推广策略。同时,公司还加强了与国际知名企业的合作,共同开发新技术和产品。这些努力使Electro-Term在全球市场上取得了显著的成绩。

振华新云(CEC)公司的发展小趣事

背景:1966年,在贵州凯里白午山区,国营新云器材厂(后更名为振华新云)正式成立,标志着公司的诞生。

内容:成立初期,公司面临着技术落后、设备陈旧等困难。然而,在老一辈员工的艰苦奋斗下,公司逐渐摸索出适合自身的发展道路。通过引进新技术、优化生产流程,不断提高产品质量和生产效率。

成果:经过几年的努力,振华新云逐渐在电子元器件行业崭露头角,为后续的快速发展奠定了坚实基础。

FORMOSA公司的发展小趣事

在台湾,一家名为“FORMOSA电子元件制造厂”的公司,起初是一家小型电阻器生产商,专注于为本地电子制造商提供基础元件。随着个人电脑和消费电子市场的蓬勃发展,该公司敏锐地捕捉到市场需求,开始投资研发高精度、低成本的电子元件。通过不断的技术创新和质量控制,FORMOSA电子元件逐渐在国际市场上获得认可,成为多家知名电子产品制造商的供应商。公司还积极拓展海外市场,在欧洲和北美设立分支机构,进一步巩固了其在全球电子元件市场的地位。

Free2Move公司的发展小趣事

随着互联网和电子商务的兴起,一家名为“FORMOSA电子商城”的平台应运而生。该平台利用先进的互联网技术,为电子产品制造商、分销商和消费者搭建了一个高效、便捷的在线交易平台。FORMOSA电子商城不仅提供丰富的电子产品选择,还通过智能化的推荐系统和优质的客户服务,为用户提供个性化的购物体验。平台还积极推动供应链的数字化转型,帮助合作伙伴优化库存管理、提高运营效率。在短短几年内,FORMOSA电子商城便成为了电子行业内知名的电子商务品牌。

AIRPAX公司的发展小趣事

近年来,随着数字化技术的快速发展,AIRPAX也开始积极探索数字化转型之路。公司加大了对智能化、自动化生产线的投入,提高了生产效率和质量。同时,AIRPAX还积极利用大数据、云计算等先进技术,对客户需求和市场趋势进行深入分析,以更好地满足客户需求并推动创新发展。

这些故事只是AIRPAX发展历程中的一部分,它们展示了AIRPAX如何在技术、市场、环保和创新等多个方面取得了显著成就。然而,随着电子行业的不断发展和竞争的加剧,AIRPAX仍需继续努力,以保持其在电气保护领域的领先地位。

问答坊 | AI 解惑

系统standby,为了省电外部设备的IO要怎么处理?

系统standby,为了省电外部设备的IO要怎么处理?…

查看全部问答>

关于MC55 TCP 连接 查看网络状态 AT 指令?

关于MC55 TCP 连接 查看网络状态 AT 指令是那些?…

查看全部问答>

wince下如何捕获异常??

使用下面方法不起作用。 try { } catch(CArchiveException e) { } 请问怎么做?谢谢!!!…

查看全部问答>

请教一个问题,大家多多帮忙啊

请问org 和 creg 这两个命令的区别。用Cx51时,其默认的startup.a51中有creg at 0,后面跟着很多代码,请问这样会不会占用中断地址(0x03, 0x0b......)??…

查看全部问答>

求教!8962的中断问题?

不知道那位大虾能指点一下8962中断控制的问题,具体是怎么实现的! 我看了一些资料,说的都太学术了,没有讲中断控制的具体实现步骤! 例外uCosii 中断跟任务管理是怎么实现的,问题实在是太多了,盼高手解救~~~ 多谢!!!…

查看全部问答>

AVRSTUDIO使用求助

 各位坛子的大虾,小弟昨天刚刚下载了个AVRSTUDIO,不知为什么编译程序总是不通过它里面提示是这样的:make: Makefile: No such file or directorymake: *** No rule to make target `Makefile\'.  Stop.是什么回事啊?能告诉我一下吗?急啊 ...…

查看全部问答>

我想DIY一个电子房价牌,求帮忙?

学习了郭天祥的51单片机,晕头了。  我只想做一个固定显示的房价牌,上面是万年历的那种,自己想焊可是无奈水平还不行,有没有朋友能告诉我,需要买什么材料,焊接流程的呢,因为这类房价牌网上有编好的程序,我只想做硬件组装。…

查看全部问答>

为什么手机上的去耦电容用33P+10P ?

可能大家注意到了,手机或相当设备上,在音频的去耦上,习惯用33P及10P的电容。   理论上说,用瓷片电容,容量越大去耦效果越好。实际中,104的电容与33P的电容价格是一样的。 为什么要用33P及10P的呢?   欢迎讨论,好帖加分!…

查看全部问答>

关于NV_INIT与NV_RESTORE的问题

请问各位,只编译NV_RESTORE这一选项与只编译NV_INIT这一选项以及与同时编译NV_INIT和NV_RESTORE这两个选项,这三种编译方式所产生的结果有什么区别吗?希望能得到各位的解答,谢谢 …

查看全部问答>

通过H2F对DDR的读取,求指导

用的是cyclonev soc这块板子,系统已经搭建好了,目前想完成的测试时我在HPS断对FPGA的DDR3进行读取,按照官网给的VIP_demo的例子,已经完成了基本的配置和地址映射,也得到了DDR3的虚拟地址 h2p_memory_addr= axi_virtual_base + ( ( unsigned lon ...…

查看全部问答>