历史上的今天
返回首页

历史上的今天

今天是:2025年03月13日(星期四)

正在发生

2019年03月13日 | 【STM32】通用定时器的PWM输出(实例:PWM输出)

2019-03-13 来源:eefocus

STM32F1xx官方资料:


《STM32中文参考手册V10》-第14章  通用定时器


通用定时器PWM概述

STM32定时器输出通道引脚


道引脚


这里以TIM3为例来讲解。STM32的通用定时器分为TIM2、TIM3、TIM4、TIM5,而每个定时器都有独立的4个通道可以用来作为:输入捕获、输出比较、PWM输出、单脉冲模式输出等。


STM32的定时器除了TIM6和TIM7(基本定时器)之外,其他的定时器都可以产生PWM输出。其中,高级定时器TIM1、TIM8可以同时产生7路PWM输出,而通用定时器可以同时产生4路PWM输出,这样STM32最多可以同时产生30路PWM输出!


从图中的内容可以看出,TIM3的4个通道相对应的各个引脚以及重映射情况下的各个引脚的位置。


PWM的工作原理



在通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、右下部分(PWM输出)这三个部分。这里主要讲解一下右下部分(PWM输出),其他两个部分可以参考文章:【STM32】通用定时器的基本原理(实例:定时器中断)。


下面以向上计数为例,简单地讲述一下PWM的工作原理:



在PWM输出模式下,除了CNT(计数器当前值)、ARR(自动重装载值)之外,还多了一个值CCRx(捕获/比较寄存器值)。

当CNT小于CCRx时,TIMx_CHx通道输出低电平;

当CNT等于或大于CCRx时,TIMx_CHx通道输出高电平。

这个时候就可以对其下一个准确的定义了:所谓脉冲宽度调制模式(PWM模式),就是可以产生一个由TIMx_ARR寄存器确定频率,由TIMx_CCRx寄存器确定占空比的信号。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。


PWM的通道概览

每一个捕获/比较通道都是围绕着一个捕获/比较寄存器(包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)。


捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器。


在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中。 

在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较。



CCR1寄存器:捕获/比较值寄存器:设置比较值;

CCMR1寄存器:OC1M[2:0]位:对于PWM方式下,用于设置PWM模式1或者PWM模式2;

CCER寄存器:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。

CCER寄存器:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。

PWM输出的模式区别

通过设置寄存器TIMx_CCMR1的OC1M[2:0]位来确定PWM的输出模式:


PWM模式1:在向上计数时,一旦TIMx_CNT

PWM模式2:在向上计数时,一旦TIMx_CNT

注意:PWM的模式只是区别什么时候是有效电平,但并没有确定是高电平有效还是低电平有效。这需要结合CCER寄存器的CCxP位的值来确定。


例如:若PWM模式1,且CCER寄存器的CCxP位为0,则当TIMx_CNT


PWM的计数模式

向上计数模式


下面是一个PWM模式1的例子。当TIMx_CNT



向下计数模式


在PWM模式1,当TIMx_CNT>TIMx_CCRx时参考信号OCxREF为低,否则为高。如果TIMx_CCRx中的比较值大于TIMx_ARR中的自动重装载值,则OCxREF保持为’1’。该模式下不能产生0%的PWM波形。


中央对齐模式


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


自动加载的预加载寄存器

在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。


在TIMx_CRx寄存器的ARPE位,决定着是否使能自动重装载的预加载寄存器。



根据TIMx_CR1位的APRE位的设置,APRE=0时,预装载寄存器的内容就可以随时传送到影子寄存器,此时两者是互通的;APRE=1时,在每一次更新事件时,才将预装在寄存器的内容传送至影子寄存器。


简单的说:ARPE=1,ARR立即生效;APRE=0,ARR下个比较周期生效。


PWM相关配置寄存器

捕获/比较模式寄存器1(TIMx_CCMR1)



捕获/比较模式寄存器总共2个,TIMx_CCMR1和TIMx_CCMR2。TIMx_CCMR1控制CH1和CH2,TIMx_CCMR2控制CH3和CH4。该寄存器的某些位在不同模式下功能不一样,上面一层对应输出而下面一层对应输入。


其中模式设置位OCxM位,此位由3位组成,一共可以配置成7种模式,我们使用的是PWM模式,所以这三位必须为110/111。



作用:在PWM输出模式下,确定PWM的模式、使能相应的预装载寄存器等操作。


捕获/比较使能寄存器(TIMx_CCER)


作用:在PWM输出模式下,确定PWM的输出极性和输出使能。


捕获/比较寄存器1(TIMx_CCR1)



作用:在PWM输出模式下,确定比较的值。


PWM相关配置库函数

1个输出初始化函数

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

作用:在四个通道中选择一个,初始化PWM输出模式、比较输出极性、比较输出使能、比较值CCRx的值。


1个参数设置函数

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);

void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);

void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

作用:在四个通道中选择一个,设置比较值。通常在初始化函数中已经设置了比较值,此函数用于除初始化之外的修改。


2个使能函数

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

作用:前者在四个通道中选择一个,使能输出比较预装载,后者使能自动重装载的预装载寄存器允许位。


PWM的一般步骤

实例要求:使用TIM3来产生PWM输出,并使用TIM3的通道2,把通道2重映射到PB5,产生PWM来控制DS0的亮度。


使能定时器和相关IO口时钟。调用函数:RCC_APB1PeriphClockCmd();RCC_APB2PeriphClockCmd();

初始化IO口为复用功能输出。调用函数:GPIO_Init();  

这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,所以需要开启AFIO时钟。同时设置重映射。调用函数:RCC_APB2PeriphClockCmd();GPIO_PinRemapConfig();

初始化定时器。调用函数:ARR,PSC等:TIM_TimeBaseInit();

初始化输出比较参数。调用函数:TIM_OC2Init();

使能预装载寄存器。调用函数:TIM_OC2PreloadConfig();

使能定时器。调用函数:TIM_Cmd();

不断改变比较值CCRx,达到不同的占空比效果。调用函数:TIM_SetCompare2()。

下面按照这个一般步骤来进行一个简单的PWM输出程序:


//TIM3 PWM部分初始化 

//PWM输出初始化

//arr:自动重装值

//psc:时钟预分频数

void TIM3_PWM_Init(u16 arr,u16 psc)

{  

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;


 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟


GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    

 

   //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

 

   //初始化TIM3

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值

TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 

TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

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

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位


//初始化TIM3 Channel2 PWM模式  

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

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

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高

TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

 

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

 

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


 

}

 int main(void)

 {

  u16 led0pwmval=0;

u8 dir=1;

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

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

uart_init(115200); //串口初始化为115200

  LED_Init();      //LED端口初始化

  TIM3_PWM_Init(899,0); //不分频。PWM频率=72000000/900=80Khz

    while(1)

{

  delay_ms(10);  

if(dir)led0pwmval++;

else led0pwmval--;

 

  if(led0pwmval>300)dir=0;

if(led0pwmval==0)dir=1;  

TIM_SetCompare2(TIM3,led0pwmval);    

}  

 }



推荐阅读

史海拾趣

E Connector Solutions公司的发展小趣事

人才是企业发展的核心竞争力。E Connector Solutions公司高度重视人才培养和团队建设。公司建立了完善的人才培养机制,通过内部培训、外部引进等方式不断提升员工的专业技能和综合素质。同时,公司还注重团队建设,鼓励员工之间的协作与交流,营造积极向上的工作氛围。这种注重人才培养和团队建设的做法为公司的发展提供了坚实的人才保障。

请注意,以上故事均为虚构,旨在为您提供一个关于电子连接器解决方案公司发展起来的故事框架。如果您需要了解特定公司的具体发展情况,建议您查阅相关公司的官方网站或行业报告。

Excellence Optoelectronics Inc公司的发展小趣事

EOI深知客户的重要性,因此公司一直致力于提供优质的服务。无论是售前咨询还是售后服务,EOI都认真对待每一个客户的需求和问题。公司建立了完善的客户服务体系,为客户提供及时、专业的支持。同时,EOI还定期举办客户培训和技术交流活动,提高客户的技术水平和使用效果。这些努力使得EOI赢得了客户的信任和忠诚度。

Advanced Optoelectronic Technology Corp公司的发展小趣事

在追求经济效益的同时,AOTC也积极履行社会责任。公司注重环保和可持续发展,采用环保材料和节能技术生产产品,降低对环境的影响。此外,公司还积极参与公益事业,支持教育、科研等领域的发展,为社会做出了积极贡献。

这些故事虽然是虚构的,但它们反映了一个电子行业中公司可能经历的一些典型发展阶段和挑战。在真实情况中,公司的发展路径会受到市场环境、技术变革、竞争态势等多种因素的影响。

聚辰(Giantec)公司的发展小趣事

面对电子行业的快速变革和市场需求的不断变化,港源公司始终保持敏锐的市场洞察力和持续的创新精神。公司不断加大研发投入,推动产业升级和产品结构优化。通过技术创新和高效智造系统构建,港源公司实现了产品自动化制造的高覆盖率,并在精密小型化的塑胶五金零部件领域取得了突破性技术优势。这些努力不仅使港源公司在市场竞争中保持领先地位,还为公司未来的发展奠定了坚实的基础。

CalAmp公司的发展小趣事

CalAmp公司以其卓越的无线产品、设备和方案供应能力,赢得了业界的广泛认可。某年,CalAmp与全球知名的电子分销商Mouser签署了全球分销协议。这一合作使得Mouser能够备有CalAmp公司的一系列产品,如UHF和VHF收发器模块、遥感勘测模块以及适用于不同频带的无线通信装置。这些产品广泛应用于各种无线通信领域,其方便快速集成的特点大大加快了客户产品的上市时间,同时提供了性价比极高的无线解决方案。这一协议的签署不仅进一步巩固了CalAmp在全球无线产品市场的领导地位,也为Mouser带来了更多的业务机会。

Condor公司的发展小趣事

随着物联网技术的快速发展,车队管理成为了一个重要的应用领域。CalAmp公司凭借其深厚的技术积累和市场洞察力,成功推出了一款车队管理新解决方案。该方案通过直观的用户界面(UI)设计,为企业、政府和建筑机构提供了更为便捷、高效的车队管理工具。用户可以通过该界面轻松获取关键业务数据,如资产位置、驾驶行为和车辆状态等,从而加快智能决策,提高车队运营效率,降低成本并增强安全性。这一创新解决方案的推出,进一步巩固了CalAmp在车队管理领域的领先地位。

问答坊 | AI 解惑

CEPB (5.0)上, Tools --> Windows CE Remote Call Profiler 工具如何使用?

CEPB (5.0)上, Tools  -->  Windows CE Remote Call Profiler 工具如何使用? (我想用它来看 开发板上EVC写的程序消耗的资源) launch --> EVC写的程序 后, 提示接收等待数据.... 但EVC写的程序的运行和消耗的资源等 数据无 ...…

查看全部问答>

USB驱动请教各位

我用DDK做了一个USB驱动,已经能正常通讯了,但是在循环写Pipe1端口,写几次驱动就不响应了,调试发现停在status = KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );,以下时通讯程序,这会是什么原因呢????   & ...…

查看全部问答>

高分求51单片机的程序一份

硬件电路图已有,求程序,汇编、C语言编写均无不可。求善人帮忙,有意联系 QQ:226600569 甚急!QQ在线等…

查看全部问答>

在makeimg时出现错误,打包失败,该如何解决?

将一个应用的配置文件SL50FBgb.mnu打包到内核,在platform.bib中加入了这样一行: SL50FBgb.mnu       $(_FLATRELEASEDIR)\\SL50FBgb.mnu                  NK U ...…

查看全部问答>

EVC++下不支持GetRunningObjectTable( )函数?

在移植陆老师的SAMPLEPLAYER到WINCE下,但编译报不支持GetRunningObjectTable( )和CreateItemMoniker( )这两个函数,请问为什么?我自己导出的SDK包不全面?还是跟.NET组件加没加有关?我的SDK包没加.NET组件 ...…

查看全部问答>

STM32 v3.5固件库systick ms延时

《如何从STM32F10xxx固件库V2.0.3升级为STM32F10xxx标准外设库V3.0.0》一文中的“3.3.2 SysTick”讲到:在标准外设库中移除了SysTick的驱动,因此用户必须调用CMSIS定义的函数。CMSIS只提供了一个SysTick设置的函数,替代了STM32原有SysTick驱动的 ...…

查看全部问答>

如何从DSP和M4转到FPGA

以前我玩过DSP和M4,不知道怎么转到FPGA才好,原理图都看不懂... 怎么一个FPGA非要分成这么多个模块...…

查看全部问答>

简易数字信号传输分析仪

本帖最后由 paulhyde 于 2014-9-15 03:19 编辑 2011年国赛题简易数字信号传输分析仪中提取曼彻斯特编码的同步时钟,有没有什么好的方案??    …

查看全部问答>

STM32F767 FMC驱动TFT屏幕并成功移植EMWIN(记录一下))

本帖最后由 ihalin 于 2016-8-12 00:19 编辑 经过一段时间琢磨stm32F767用fmc来驱动屏幕发现老是不成功,后来发现原来是 F7直接用FSMC驱动MCU接口的屏会有问题的!因为Cache在搞鬼!使用MPU(内存保护单元)对SRAM区做保护才可以驱动MCU屏还有一 ...…

查看全部问答>