【STM32】通用定时器的PWM输出(实例:PWM输出)

发布者:脑洞飞扬最新更新时间:2019-03-13 来源: eefocus关键字:STM32  通用定时器  PWM输 手机看文章 扫描二维码
随时随地手机看文章

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);    

}  

 }



关键字:STM32  通用定时器  PWM输 引用地址:【STM32】通用定时器的PWM输出(实例:PWM输出)

上一篇:【STM32】通用定时器的输入捕获(实例:输入捕获)
下一篇:【STM32】通用定时器的基本原理(实例:定时器中断)

推荐阅读最新更新时间:2024-03-16 16:25

STM32的开漏模式和外接上拉电阻问题
首先介绍开漏模式的意义。 (1) 浮空输入_IN_FLOATING 浮空输入,可以做KEY识别,RX1 (2)带上拉输入_IPU IO内部上拉电阻输入 (3)带下拉输入_IPD IO内部下拉电阻输入 (4) 模拟输入_AIN 应用ADC模拟输入,或者低功耗下省电 (5)开漏输出_OUT_OD IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能 (6)推挽输出_OUT_PP IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的
[单片机]
<font color='red'>STM32</font>的开漏模式和外接上拉电阻问题
STM32学习笔记:adc采样得到的电压值用485发送给pc
采用adc1的通道10,将采集到的电压值用485发送给PC显示, 先上原理图, 源代码见附件, 这里想说的是几个要注意的问题: 1,ad输入的电压经过了R42和R44进行分压,所以pc显示的电压值将会减半, 2、采用这个函数进行发送数据的时候,每次都是发送一个8位的数据(即一个字节),也就是最大值为256,。超过1个字节默认发送地位,即你要发送的数据位0x0145,只会发送45,具体可以参考数据手册,下图, USART_SendData(USART3,ADC_Value_B);1 3,pc 机上收集到的数据,如果没有勾选“以HEX显示”则显示的是acsii码,而我们发送数据给PC机发送的则是hex,所以这里要进行一次转换
[单片机]
<font color='red'>STM32</font>学习笔记:adc采样得到的电压值用485发送给pc
STM32的GPIO口能够承受多大电压? 哪些IO口能容忍5V?
STM32的部分IO口可以容忍5V,部分IO口只能是3.3V容忍。 到底哪些能够容忍,查看数据手册,引脚标注”FT 的是可以容忍5V的。 比如:STM32F103xCDE_DS_CH_V5.pdf 在我们光盘“8,STM32参考资料STM32中文数据手册 下面 STM32F4的IO电平兼容性问题,STM32F4的绝大部分IO口,都兼容5V, 至于到底哪些是兼容5V的,请看STM32F40x的数据手册(注意是数据手册,不是中文参考手册!!), 见 表:Table 6 STM32F40x pin and ball definitions,凡是有FT/FTf标志的,都是兼容5V电平 的IO口,可以直接接5V的外设 (注意
[单片机]
利用树莓派打造STM32无线在线调试器!
不知各位嵌入式开发者有没有遇到这样的经历:J-link的线长限制了我们编程的姿势,很多时候我们的工程都需要板子产生一些位移(比如调小车之类的),这时候J-link的线会让我们Debug的过程变得非常痛苦。。。那么有没有办法让我们解决这个数据线的痛苦呢??答案是当然有的!只要有着一颗折腾的心,办法总是会慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢想出来的。本人最近一直在弄一个相关工程,因为被线限制的非常痛苦,于是就考虑出了使用树莓派作为J-link的服务器然
[单片机]
利用树莓派打造<font color='red'>STM32</font>无线在线调试器!
关于STM32正交编码器边沿的理解
STM32中的TIM_EncoderInterfaceConfig()函数。其配置的定时器有编码器接口等功能,一般是定时器的通道1和通道2才能作为编码器的输入口,对应编码器输出的两项。 TIMx参数就是使用哪个定时器作为编码器接口的捕捉定时器。 一般一个编码器占用一个定时器。 TIM_EncoderMode参数是模式,是单相计数(只能反映速度)还是两相计数(速度和方向)。 TIM_IC1Polarity和TIM_IC2Polarity参数就是通道1、2的捕捉极性。 但是一般来说,STM32对应的都是两相计数,一项计数容易误判,也就是说,你可以按一路计数,但是接线时好像两相的编码线A,B都是需要接上的,否则容易误判。
[单片机]
关于<font color='red'>STM32</font>正交编码器边沿的理解
STM32 USB 从机HID分析
概述 将STM32的USB初始化为USB从机,使用标准HID协议。控制板自带VBUS供电,因此不需要VBUS、GND引脚。 只要连接2根数据线到电脑即可。 源码分析 当使用USB线连接电脑端后,收到电脑端的USB复位包 USBD_OTG_ISR_Handler -- DCD_HandleSof_ISR -- /* Clear interrupt */ OTG_HS_GINTSTS- SOF:在设备模式下,模块将该位置 1 时,指示 USB 上已接收到一个 SOF 令牌。应用程序可通过读取设备状态寄存器来获得当前的帧编号。只有在模块以 FS 模式运行时,才会出现此中断。 GINTS
[单片机]
STM32 CAN 控制器
CAN简介 CAN是ControllerAreaNetwork的缩写(以下称为CAN),是ISO国际标准化的串行通信协议。在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个LAN,进行大量数据的高速通信”的需要,1986年德国电气商博世公司开发出面向汽车的CAN通信协议。此后,CAN通过ISO11898及ISO11519进行了标准化,现在在欧洲已是汽车网络的标准协议。 CAN控制器根据两根线上的电位差来判断总线电平。总线电平
[单片机]
基于STM32的红光治疗仪控制系统
一 STM32 ADC 采样 频率的确定 先看一些资料,确定一下STM32 ADC 的时钟: (1),由时钟控制器提供的ADCCLK 时钟和PCLK2(APB2 时钟)同步。CLK 控制器为ADC 时钟提供一个专用的可编程预分频器。 (2)一般情况下在程序 中将 PCLK2 时钟设为 与系统时钟 相同 RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK2Config(RCC_HCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); (3)在时钟配置寄存器(RCC_CFGR) 中 有 为ADC 时钟提供一个专用的可编程预分器 位15:14 ADCPRE:A
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved