(stm32f103学习总结)—stm32 PMW输出实验
一.PWM简介
PWM是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调 制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控 制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成 为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信, 功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些 音频放大器,因此学习PWM具有十分重要的现实意义。 其实我们也可以这样理解,PWM是一种对模拟信号电平进行数字编码 的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个 具体模拟信号的电平进行编码。PWM 信号仍然是数字的,因为在给定的 任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压 或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去 的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被 断开的时候。只要带宽足够,任何模拟值都可以使用 PWM 进行编码。

二.STM32F1 PWM介绍
STM32F1除了基本定时器TIM6和TIM7,其他定时器都可以产生PWM输出 。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出 。而通用定时器也能同时产生多达 4路的 PWM 输出,这些在定时器中断 章节中已经介绍过。 PWM的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号 ,信号频率是由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。

PWM输出比较模式总共有8种,具体由寄存器 CCMRx 的位 OCxM[2:0] 配置。我们这里只讲解最常用的两种PWM输出模式:PWM1和PWM2,其他几 种模式可以参考《STM32F10x中文参考手册》13、14、15定时器章节。
PWM1和PWM2这两种模式用法差不多,区别之处就是输出电平的极性不 同。

PWM模式根据计数器CNT计数方式,可分为边沿对齐模式和中心对齐模 式。
(1)PWM边沿对齐模式
当 TIMx_CR1 寄存器中的 DIR 位为低时执行递增计数,计数器CNT从 0 计数到自动重载值(TIMx_ARR 寄存器的内容),然后重新从 0 开始 计数并生成计数器上溢事件。 以 PWM 模式 1 为例。只要TIMx_CNT < TIMx_CCRx, PWM 参考信号 OCxREF 便为有效的高电平,否则为无效的低电平。如果 TIMx_CCRx 中 的比较值小于自动重载值(TIMx_ARR 中),则 OCxREF 保持为“ 1”。 如果比较值为 0, 则 OCxREF 保持为“ 0”。

当 TIMx_CR1 寄存器中的 DIR 位为高时执行递减计数,计数器CNT从 自动重载值(TIMx_ARR 寄存器的内容)递减计数到0,然后重新从 TIMx_ARR值开始计数并生成计数器下溢事件。 以 PWM 模式 1 为例。只要TIMx_CNT >TIMx_CCRx, PWM 参考信号 OCxREF 便为无效的低电平,否则为有效的高电平。如果 TIMx_CCRx 中 的比较值大于自动重载值(TIMx_ARR 中),则 OCxREF 保持为“ 1”。 此模式下不能产生0%的PWM波形。
(2)PWM中心对齐模式
在中心对齐模式下,计数器 CNT 是工作做递增/递减模式下。开始的 时候, 计数器CNT 从 0 开始计数到自动重载值减 1(ARR-1),生成计数 器上溢事件;然后从自动重载值开始向下计数到 1 并生成计数器下溢事 件。之后从 0 开始重新计数。

我们以ARR=8,CCRx=4为例进行介绍。第一阶段计数器CNT工作在递增 计数方式,从0开始计数,当TIMx_CNT < TIMx_CCRx时,PWM 参考信号 OCxREF为高电平,当TIMx_CNT >= TIMx_CCRx时,PWM 参考信号 OCxREF 为低电平。第二阶段计数器CNT工作在递减计数方式,从ARR开始递减计 数,当TIMx_CNT > TIMx_CCRx时,PWM 参考信号 OCxREF为低电平,当 TIMx_CNT <= TIMx_CCRx时,PWM 参考信号 OCxREF为高电平。
三.PWM输出配置步骤
(1)使能定时器及端口时钟,并设置引脚复用器映射 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); 可选的参数在 stm32f10x_gpio.h 都已经列出来非常详细
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出

(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等
void TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
(3)初始化PWM输出参数,包含PWM模式、输出极性,使能等
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
(4)开启定时器
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); TIM_Cmd(TIM3,ENABLE); //开启定时器
(5)修改TIMx_CCRx的值控制占空比
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1);
(6)使能TIMx在CCRx上的预装载寄存器 使能输出比较预装载库函数是:
void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
第一个参数用于选择定时器,第二个参数用于选择使能还是失能输出比较预装载寄存器,可选择为TIM_OCPreload_Enable、TIM_OCPreload_Disable。
(7)使能 TIMx 在 ARR 上的预装载寄存器允许位 使能 TIMx 在 ARR 上的预装载寄存器允许位库函数是:
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState); //第一个参数用于选择定时器,第二个参数用于选择使能还是失能。
高级定时器要想输出PWM波形,必须要设置一个 MOE 位(TIMx_BDTR 的第 15 位),以使能主输出,否则不会输出 PWM。库函数设置的函数为:
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

pwm.h
1 #ifndef _pwm_H
2 #define _pwm_H
3
4 #include "system.h"
5
6 void TIM3_CH1_PWM_Init(u16 per,u16 psc);
7
8 #endif
问题一:19行问什么要AFIO使能 27行改变管脚映射怎么回事
27行改变管脚映射是对应第三步而言的,就是将定时器输出的管脚TIM_CH1即PA6管脚映射到PC6管脚输出(这里以TIM_CH1为例)
而管脚映射需要用到AFIO这个外设里面寄存器的配置才能实现
问题二:24行为什么GPIOC使用复用推挽输出,为什么使用复用功能
复用功能是接受其他外设所传递的数据(这里是复用的定时器结构图右下角所输出的数据)然后通过管脚输出


总结:所比较的数据从TIM3_CH1口出来,经过AFIO外设内寄存器的配置将TIM3_CH1管脚即PA6管脚所映射到的PC6管脚上,经过PC6管脚的复用功能输出的模式将TIM3_CH1的数据输出
四、PWM代码
pwm.c
1 #include "pwm.h"
2
3 /*******************************************************************************
4 * 函 数 名 : TIM3_CH1_PWM_Init
5 * 函数功能 : TIM3通道1 PWM初始化函数
6 * 输 入 : per:重装载值
7 psc:分频系数
8 * 输 出 : 无
9 *******************************************************************************/
10 void TIM3_CH1_PWM_Init(u16 per,u16 psc)
11 {
12 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
13 TIM_OCInitTypeDef TIM_OCInitStructure;
14 GPIO_InitTypeDef GPIO_InitStructure;
15
16 /* 开启时钟 */
17 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
18 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
19 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //AFIO使能
20
21 /* 配置GPIO的模式和IO口 */
22 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
23 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
24 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
25 GPIO_Init(GPIOC,&GPIO_InitStructure);
26
27 GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改变指定管脚的映射
28
29 TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值
30 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
31 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
32 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
33 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
34
35 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
36 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
37 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
38 TIM_OC1Init(TIM3,&TIM_OCInitStructure); //输出比较通道1初始化
39
40 TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在 CCR1 上的预装载寄存器
41 TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
42
43 TIM_Cmd(TIM3,ENABLE); //使能定时器
44
45 }
main.c
1 #include "system.h"
2 #include "SysTick.h"
3 #include "led.h"
4 #include "pwm.h"
5
6 int main()
7 {
8 u16 i=0;
9 u8 fx=0;
10 SysTick_Init(72);
11 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
12 LED_Init();
13 TIM3_CH1_PWM_Init(500,72-1); //频率是2Kh
14
15 while(1)
16 {
17
18 if(fx==0)
19 {
20 i++;
21 if(i==300)
22 {
23 fx=1;
24 }
25 }
26 else
27 {
28 i--;
29 if(i==0)
30 {
31 fx=0;
32 }
33 }
34 TIM_SetCompare1(TIM3,i); //i值最大可以取499,因为ARR最大值是499.
35 delay_ms(10);
36 }
37 }
(stm32f103学习总结)—stm32 PMW输出实验的更多相关文章
- (stm32f103学习总结)—待机唤醒实验
一.STM32待机模式介绍 1.1 STM32低功耗模式介绍 很多单片机具有低功耗模式,比如MSP430.STM8L等,我们的STM32 也不例外.默认情况下,系统复位或上电复位后,微控制器进入运行模 ...
- (stm32f103学习总结)—ADC模数转换实验
一.STM32F1 ADC介绍 TM32F103 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可 以使用双重(提高采样率).STM32F1 的 ADC 是 12 位逐次 逼近型的模拟数 ...
- MM32 备份域学习(兼容STM32)
MM32 备份域学习(兼容STM32) 内容提要 备份域工作原理 备份域特性 备份域的保护:侵入检测 备份域侵入检测 备份域电源与主要内容 备份域特性 20字节数据后备寄存器(中容量和小容量产品),或 ...
- 第六周学习总结&第四次实验报告
第六周学习总结&第四次实验报告 学习总结 这周我们简单的学习了一点点关于接口的内容,接口是Java中最重要的概念之一,接口可以理解为一个特殊的类, 里面由全局常量和公共的抽象方法组成,接口摆脱 ...
- MM32看门狗学习(兼容STM32)
MM32看门狗学习(兼容STM32) IWDG独立看门狗 思维导图 IWDG框图与理解 1.独立看门狗分为两个部分,配置寄存器在1.8V供电区,计数器的核心部分在VDD供电区(即使停机/待机模式计数器 ...
- STM32 精确输出PWM脉冲数控制电机(转)
STM32 精确输出PWM脉冲数控制电机 发脉冲两种目的1)速度控制2)位置控制 速度控制目的和模拟量一样,没有什么需要关注的地方发送脉冲方式为PWM,速率稳定而且资源占用少 stm32位置控制需要获 ...
- Redis学习笔记六:持久化实验(AOF,RDB)
作者:Grey 原文地址:Redis学习笔记六:持久化实验(AOF,RDB) Redis几种持久化方案介绍和对比 AOF方式:https://blog.csdn.net/ctwctw/article/ ...
- stm32 PWM输出学习
STM32 的定时器除了 TIM6 和 7,其他的定时器都可以用来产生 PWM 输出.其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.通用定时器也能同时产生多达 4路 ...
- (stm32f103学习总结)—stm32定时器中断
一.定时器介绍 STM32F1的定时器非常多,由2个基本定时器(TIM6.TIM7).4个通 用定时器(TIM2-TIM5)和2个高级定时器(TIM1.TIM8)组成.基本定 时器的功能最为简单,类似 ...
随机推荐
- Docker入坑系列(一)
Docker入坑系列(一) 引用嘛,当然是来引用别人说的东西啦. Docker 是一个开源项目,诞生于 2013 年初,它基于 Google 公司推出的 Go 语言实现. 项目后来加入了 Linux ...
- java复习面向对象(二)
java复习面向对象(二) 1.static关键字 举例图片 静态变量 使用static修饰的成员变量是静态变量 如果一个成员变量使用了关键字static,那么这个变量不属于对象自己,而属于所在的类多 ...
- 用Assert(断言)封装异常,让代码更优雅(附项目源码)
有关Assert断言大家并不陌生,我们在做单元测试的时候,看业务事务复合预期,我们可以通过断言来校验,断言常用的方法如下: public class Assert { /** * 结果 = 预期 则正 ...
- CoLAKE: 如何实现非结构性语言和结构性知识表征的同步训练
原创作者 | 疯狂的Max 论文CoLAKE: Contextualized Language and Knowledge Embedding 解读 01 背景与动机 随着预训练模型在NLP领域各大任 ...
- Lua中如何实现类似gdb的断点调试—08支持通过包名称添加断点
在前一篇中我们支持了通过函数名称来添加断点,我们同时也提到了在Lua中一个函数的名称的并不是确定的.准确的说,Lua中的函数并没有名称,所谓名称其实是保存这个函数值的变量的名称. 于是通过函数名称添加 ...
- 配置DHCP Relay的功能原理是什么?
DHCP中继代理,就是在DHCP服务器和客户端之间转发DHCP数据包.当DHCP客户端与服务器不在同一个子网上,就必须有DHCP中继代理来转发DHCP请求和应答消息.DHCP中继代理的数据转发,与通常 ...
- Unknown column ‘avatar_url‘ in ‘field list‘
报错: Unknown column 'avatar_url' in 'field list' 解决: 查看mysql数据库中字段名前面是否有空格或则换行
- 前端好用API之Fullscreen
前情 在前端开发需求中,特别网页有视频需求时,需要做视频全屏功能,或者在某些可视化大屏项目也要做全屏. Fullscreen介绍 让你可以简单地控制浏览器,使得一个元素与其子元素,如果存在的话,可以占 ...
- 内网渗透----Linux下信息收集
基础信息 1.系统类型 cat /etc/issue查看系统名称 Lsb-release查看系统名称.版本号 2. 内核版本 uname –a 查看所有信息 ls /root |grep vmlinu ...
- 2022IDEA配置启动lilishop的swagger展示
目录 一.概述 二.基本构建 三.Git 导入编译器 四.模块描述浅析 五.配置文档 1.注释配置文件 2.添加配置 3.暂时关闭权限 4.浏览器测试访问 5.其他需要修改模块 六.参考文献 结语 一 ...