STM32 的定时器除了 TIM6 和 7,其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。通用定时器也能同时产生多达 4路的 PWM 输出。

今天的实验,我们仅利用 TIM3的 CH2 通道产生一路 PWM 输出。

1.相关寄存器介绍

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

捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器总共有 2 个,TIMx  _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制 CH3 和 CH4。

OCxx描述了通道在输出模式下的功能(上行),ICxx描述了通道在输出模式下的功能(下行)。因此必须注意,同一个位在输出模式和输入模式下的功能是不同的。

这里我们需要说明的是模式设置位 OCxM,此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,所以这 3 位必须设置为 110/111。这两种PWM 模式的区别就是输出电平的极性相反。

这里的有效电平或者无效电平是可以配置的。

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

3)捕获/比较寄存器(TIMx_CCR1~4)

该寄存器总共有 4 个,对应 4 个通道 CH1~CH4。因为这 4 个寄存器都差不多,我们仅以 TIMx_CCR1 为例介绍。

我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽。

2. TIM3_REMAP 重映射

我们要利用 TIM3 的 CH2 输出 PWM 来控制 LED的亮度,但是 TIM3_CH2 默认是接在 PA7上面的,而我们的 LED接在 PB5 上面,如果是普通 MCU,可能就只能用飞线把 PA7 飞到 PB5上;不过,我们用的是 STM32,可以通过重映射功能,把 TIM3_CH2映射到 PB5 上。

3.代码难点分析

1)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能TIM3时钟
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);  
//使能GPIOB时钟(PB5连接LED)和AFIO复用功能时钟

为什么要使能RCC_APB2Periph_AFIO呢?

参考手册上说:

对寄存器AFIO_EVCR(事件控制寄存器),AFIO_MAPR( 复用重映射和调试I/O配置寄存器),AFIO_EXTICRX(外部中断配置寄存器)进行读写操作前,应当首先打开AFIO的时钟。

因为我们在这个实验中用到了AFIO_MAPR,所以要打开AFIO时钟。

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

3)GPIO配置

//设置该引脚为复用输出功能,输出TIM3-CH2的PWM波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //推挽复用输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

4)TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

可以参考捕获/比较使能寄存器(TIMx_CCER)位0, 输出使能。

5)TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

可以参考捕获/比较使能寄存器(TIMx_CCER)位1, 高/低 电平有效。

6)TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 预装载使能

可以参考捕获/比较模式寄存器 (TIMx_CCMR1/2) 位3.

7)TIM_SetCompare2(TIM3,300);

参考捕获/比较寄存器(TIMx_CCR1~4),这里设置比较值为300.

4. 代码参考

//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);   //使能TIM3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIOB时钟(PB5连接LED)和AFIO复用功能时钟GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射,TIM3_CH2->PB5    //设置该引脚为复用输出功能,输出TIM3-CH2的PWM波形GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化TIM3TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //TIM3 Channel2 PWM 初始化TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM2模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //捕获/比较使能寄存器(TIMx_CCER) 输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高电平有效TIM_OC2Init(TIM3, &TIM_OCInitStructure);  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //预装载使能TIM_Cmd(TIM3, ENABLE);  //开启TIM3}

main函数如下

int main(void)
{   TIM3_PWM_Init(999,71); //72/(71+1)=1MHz, T=1us*(999+1) = 1msTIM_SetCompare2(TIM3,300); //脉宽= 300/1000 *1ms = 0.3mswhile(1){;    }
}

仿真说明:我们的代码设置为:

PWM2模式,向上计数,高电平有效。

所以,TIMx_CNT<TIMx_CCRx时通道x为低,否则为高。

5.仿真效果图如下

6. 疑问

如果调换main函数两句的顺序,则无法达到预期效果。

<span style="font-size:18px;">int main(void) //实验失败
{   TIM_SetCompare2(TIM3,300);  //脉宽= 300/1000 *1ms = 0.3msTIM3_PWM_Init(999,71); //72/(71+1)=1MHz, T=1us*(999+1) = 1mswhile(1){;       }
}</span>

至于原因,这里不讨论,留待以后思考。

7. 用PWM控制LED的亮度

int main(void)
{       u16 led0pwmval = 0; //比较值u8 dir = 1;  delay_init();            TIM3_PWM_Init(899,0);   while(1){delay_ms(10);  if(dir)led0pwmval++;else led0pwmval--;if(led0pwmval>300)dir=0;if(led0pwmval==0)dir=1;                                      TIM_SetCompare2(TIM3,led0pwmval);         }
}

这里,我们将 led0pwmval 这个值设置为 PWM 比较值,也就是通过 led0pwmval 来控制 PWM 的占空比,进而控制LED的平均电流,达到控制LED亮度的目的。

led0pwmval 的值从 0 变到 301,然后又从 301 变到 0,如此循环,LED的亮度也会跟着从暗变到亮,然后又从亮变到暗。至于这里的值,我们为什么取 300,是因为 PWM 的输出占空比达到并且超过这个值的时候, LED 亮度变化就不明显了。

stm32 PWM输出学习相关推荐

  1. STM32 PWM输出之TIM_SetCompare函数的应用

    STM32 PWM输出之TIM_SetCompare函数的应用 想必输出PWM大家都应该会了吧,但是如何更加灵活方便的使用PWM,可能大家还存在着问题,今天我给大家介绍一下TIM_SetCompare ...

  2. 【学习记录】 STM32 PWM输出实验

    STM32 PWM工作过程 以通道1为例: CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值. CCMR1: OC1M[2:0]位: 对于PWM方式下,用于设置PWM模式1[110]或 ...

  3. STM32 PWM输出实验总结

    本实验是基于STM32 407的板子,使用的是通用定时器TIM14,相关的博文其实有很多,本文主要是基于他们结合个人学习理解总结整理,并非完全原创,只希望能帮助更好理解PWM输出的过程尤其是TIM_A ...

  4. STM32 PWM输出(映射)

    STM32 的定时器除了 TIM6 和 7.其他的定时器都可以用来产生 PWM 输出.其中高级定 时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.而通用定时器也能同时产生多达 ...

  5. STM32 PWM输出实验

    定时器用来产生PWM输出: STM32 的定时器除了 TIM6 和 7.其他的定时器都可以用来产生 PWM 输出.其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.而通 ...

  6. STM32 PWM输出原理和直流电机PWM驱动原理详解及例程

    这次讲一讲STM32输出PWM的原理以及PWM可以作为信号传输数据的原理. PWM会有很多地方用到,有控制灯的亮度,控制电机,控制舵机或者其他一些外设,有时候你的单片机所输出的PWM是作为信号去控制, ...

  7. STM32学习笔记(五 定时器及应用 3 PWM输出实验 )

    一.PWM 简介 脉冲宽度调制(PWM) Pulse Width Modulation (调制) 简单来说就是对脉冲宽度的控制. 高级定时器 TIM1 和 TIM8: 可以同时产生多达 7 路的 PW ...

  8. STM32学习之PWM输出

    PWM: Pluse Width Modulation 的缩写,称作脉冲宽度调制,是利用CPU的数字输出来对模拟电路的一种控制,即通过对脉冲宽度的控制. 接下来随笔者看几个概念: PWM的周期:即频率 ...

  9. STM32学习笔记—PWM输出

    1.pwm输出介绍 2.函数配置 3.源码 1.pwm输出介绍 脉冲调制(pwm),其根本原理就是通过控制占空比来控制输出.STM32的定时器除了TIM6和7之外都可以产生pwm输出,其中高级定时器1 ...

最新文章

  1. php最常见代码,PHP常见算法合集代码实例
  2. python找最大值的函数_Python 获取最大值函数
  3. laravel 中添加自定义辅助函数helpers.php
  4. 有没有通过代码退出程序的方法--官方解答
  5. 【转】C++中的字符串(String)和数值转换
  6. NSArray与NSSet的区别
  7. arm linux samba,嵌入式linux系统教你制作samba服务器
  8. Oracle11新特性——初始化文件管理
  9. matlab简介,Matlab简介及各历史版本
  10. Java 生成条形码 订单条形码
  11. 他 25 岁进贝尔实验室,32 岁提信息论,40 岁办达特茅斯会议,晚年患上阿兹海默 | 人物志...
  12. 乐鑫esp8266学习rtos3.0笔记第3篇: 一篇文章带你搞掂存储技术 NVS 的认识和使用,如何利用NVS保存整型、字符串、数组以及结构体。(附带demo)
  13. 【K8S实战】-超详细教程(三)
  14. DNS服务器未响应是什么意思
  15. 导出word单元格间隔空白问题
  16. SVN使用教程(一)
  17. 机器人瓦力有什么西方的风格_机器人瓦力中英文对照影评
  18. struts上传word和excel文件到oracle,Struts文件上传,下载,重传,预览
  19. vue2+vue3小白零基础教程—vue2篇,全网2021最详细教程
  20. created不能异步_详解vue中async-await的使用误区

热门文章

  1. hdu 4556 Stern-Brocot Tree
  2. JAVA中JPasswordField实现密码的确认
  3. BZOJ 1412 [ZJOI2009]狼和羊的故事(最小割)
  4. asp.net怎样解决高并发问题
  5. C语言中的位域 bit field [转]
  6. 做毕设时遇到的一些问题,以及一些小技巧
  7. WPF开发中遇到的问题及解决系列(一):How can I programmatically click a Button
  8. runat=server
  9. 使用tensorflow出现 ImportError: DLL load failed: 找不到指定的程序
  10. 编程方法学7:循环与一半