STM32 PWM输出实验总结

article/2025/10/29 5:24:55

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

1 TIM14主要特性

关于TIM14的相关介绍可以在中文参考手册的16.3章节查看,该定时器只有一个独立通道,可用于输出捕获、输出比较、PWM生成(边沿对齐模式)、单脉冲模式输出。
在这里插入图片描述
下图为高级定时器和通用定时器的引脚分布图。
在这里插入图片描述
STM32 PWM工作过程(通道1为例)
在这里插入图片描述

2 相关寄存器

首先是基础的时基单元包含的:计数器寄存器(TIMx-CNT)、预分频器寄存器(TIMxPSC)、自动重载寄存器(TIMx_ARR)这三个,除此之外还会用到 4 个寄存器(通用定时器则只需要 3 个),来控制 PWM 的输出。这四个寄存器分别是:捕获/比较模式寄存器( TIMx_CCMR1/2)、捕获/比较使能寄存器( TIMx_CCER)、捕获/比较寄存器( TIMx_CCR1~4) 以及刹车和死区寄存器( TIMx_BDTR)。其中刹车和死区寄存器( TIMx_BDTR)只有当使用高级定时器进行PWM输出时才会用到

1. 捕获/比较模式寄存器( TIMx_CCMR1/2)
该寄存器总共有 2 个, TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。该寄存器的各位描述如下:

寄存器分了 2层,上面一层对应输出时的设置而下面的则对应输入时的设置。模式设置位 OCxM,此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,这 3 位必须设置为110/111。这两种 PWM 模式的区别就是输出电平的极性相反。 另外 CCxS 用于设置通道的方向(输入/输出)默认设置为 0,就是设置通道作为输出使用。

  • 110:PWM模式1在,向上计数时,一旦TIMx_CNT <TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT >TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
  • 111:PWM模式2-在向上计数时,一旦 TIMx_CNT <TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT >TIMx_CCR1时通道1为有效电平,否则为无效电平。

该寄存器的OC1PE位输出比较 1 预装载使能()也同样值得注意,该位描述如下,看不懂没关系,后面有详细讲解,先有个印象就行。

  • 0:禁止与 TIMx_CCR1 相关的预装载寄存器。可随时向 TIMx_CCR1 写入数据,写入后将立即使用新值。
  • 1:使能与 TIMx_CCR1 相关的预装载寄存器。可读/写访问预装载寄存器。TIMx_CCR1 预装
    载值在每次生成更新事件时都会装载到活动寄存器中。

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

PWM输出实验只用到了 CC1E 位,该位决定了输入捕获/比较寄存器 1 (TIMx_CCR1) 是否能够实际捕获到计数器的值,是输入/捕获 1 输出使能位,要想PWM 从 IO 口输出,这个位必须设置为 1。

3. 捕获比较寄存器(TIMx-CCR1-4)
该寄存器总共有 4 个,对应 4 个输通道 CH1~4。

当通过CCMR1寄存器的CCxS 位将通道CC1设置输出使用时:
CCR1 为要装载到实际捕获/比较 1 寄存器的值(预装载值),即用来与TIMx_CNT 作比较的那个值。
如果没有通过 TIMx_CCMR 寄存器中的 OC1PE 位来使能预装载功能,写入的数值会被直接传
输至当前寄存器中。否则只在发生更新事件时生效(拷贝到实际起作用的捕获/比较寄存器1)
实际捕获/比较寄存器中包含要与计数器 TIMx_CNT 进行比较并在 OC1 输出上发出信号的值。

4. 刹车和死区寄存器(TIMx_BDTR)

该寄存器总共有 2 个, TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。该寄存器的各位描述如下:

该寄存器,我们只需要关注最高位: MOE 位,要想高级定时器的 PWM 正常输出,则必须设置 MOE 位为 1,否则不会有输出。注意:通用定时器不需要配置这个。

3 PWM输出实验步骤

使用定时器14的PWM功能,输出占空比可变的PWM波,用来驱动LED灯,从而达到LED【PF9]亮度由暗变亮,又从亮变暗,如此循环。

  1. 当TIM14的通道TIM_CH1选择到PF9时,GPIOF9与DS0刚好硬件相连,可以直接控制等亮灭。
    在这里插入图片描述
    因此此次实验主要用到TIM14的通道TIM_CH1和GPIOF9,首先使能TIM14和F9的时钟。
    使能TIM14时钟:RCC_APB1PeriphClockCmd();
    使能GPIOF时钟:RCC_AHB1PeriphClockCmd ();
  2. 初始化PF9口为复用功能输出。函数:GPIO_Init();
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  3. GPIOF9复用映射到TIM14
    GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
  4. 初始化定时器:设置TIM14的ARR,PSC等:TIM_TimeBaseInit();
  5. 设置 TIM14_CH1 的 PWM 模式及通道方向, 使能 TIM1 的 CH1 输出;
    在库函数中, PWM 通道设置是通过函TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道 1,所以使用的函数是 TIM_OC1Init()。
    结构体 TIM_OCInitTypeDef的定义:
typedef struct
{
uint16_t TIM_OCMode;	//设置模式是 PWM 还是输出比较;
uint16_t TIM_OutputState;//设置比较输出使能,也就是使能 PWM 输出到端口;
uint16_t TIM_OutputNState; 	//高级定时器 TIM1 和 TIM8 才用到的
uint16_t TIM_Pulse;			//比较值,写CCRx
uint16_t TIM_OCPolarity;	//设置极性是高还是低;
uint16_t TIM_OCNPolarity;	//高级定时器 TIM1 和 TIM8 才用到的
uint16_t TIM_OCIdleState;	//高级定时器 TIM1 和 TIM8 才用到的
uint16_t TIM_OCNIdleState;	//高级定时器 TIM1 和 TIM8 才用到的
} TIM_OCInitTypeDef;
  1. 使能预装载寄存器: TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
  2. 使能自动重装载的预装载寄存器允许位,TIM_ARRPreloadConfig(TIM14,ENABLE);
  3. 使能定时器,TIM_Cmd(TIM1, ENABLE);
  4. 普通定时器在完成以上设置了之后, 就可以输出 PWM 了,但是高级定时器,我们还需要使能刹车和死区寄存器( TIM1_BDTR)的 MOE 位,以使能整个 OCx(即 PWM)输出。 库数的设置函数为:
    TIM_CtrlPWMOutputs(TIM1,ENABLE);
  5. 不断改变比较值CCRx,达到不同的占空比最后,在经过以上设置之后, PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改 TIM1_CCR1 则可以控制 CH1 的输出占空比。继而控制 DS0 的亮度。
    在库函数中,修改 TIM1_CCR1 占空比的函数是:
    void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

********************************* pwm.c *********************************

//TIM14 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM14_PWM_Init(u32 arr,u32 psc)
{		 					 //此部分需手动修改IO口设置GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);  	//TIM14时钟使能    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 	//使能GPIOF时钟	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9复用为定时器14//设置该引脚为复用输出功能,输出TIM1_CH1的PWM脉冲波形GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //GPIOF9为TIM_CH1GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉GPIO_Init(GPIOF,&GPIO_InitStructure);              //初始化PF9TIM_TimeBaseStructure.TIM_Prescaler=psc;  //定时器分频TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseStructure.TIM_Period=arr;   //自动重装载值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定时器14//初始化TIM14 Channel1 PWM模式	 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低TIM_OC1Init(TIM14, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMxTIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);  //使能TIM14在CCR1上的预装载寄存器TIM_ARRPreloadConfig(TIM14,DISABLE);//ARPE使能 TIM_Cmd(TIM14, ENABLE);  //使能TIM14}  

********************************* main.c *********************************

int main(void)
{ u16 led0pwmval=0;    u8 dir=1;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2delay_init(168);  //初始化延时函数uart_init(115200);//初始化串口波特率为115200TIM14_PWM_Init(500-1,84-1);	//84M/84=1Mhz的计数频率,重装载值500,所以PWM频率为 1M/500=2Khz.     while(1) //实现比较值从0-300递增,到300后从300-0递减,循环{delay_ms(10);	 if(dir)led0pwmval++;//dir==1 led0pwmval递增else led0pwmval--;	//dir==0 led0pwmval递减 if(led0pwmval>300)dir=0;//led0pwmval到达300后,方向为递减if(led0pwmval==0)dir=1;	//led0pwmval递减到0后,方向改为递增TIM_SetCompare1(TIM14,led0pwmval);	//修改比较值,修改占空比}
}

4 影子寄存器、预装载寄存器,TIM_OC1PreloadConfig和TIM_ARRPreloadConfig的作用

针对pwm.c中的TIM_OC1PreloadConfig()和TIM_ARRPreloadConfig()函数可能有的人跟我一样刚开始存在疑惑,这里参考这篇博客总结了下,可以对照着理解下。

首先看定时器的框图:

在这里插入图片描述
图中有阴影的小方框,代表该功能对应的寄存器有影子寄存器,也就是:PSC预分频器、自动重装载寄存器、REP寄存器和4个通道的捕获/比较寄存器。

可以看到这几个寄存器都是经常用到的,而且存在定时器工作过程中修改他们的可能性。在定时器工作过程中修改他们的值,就会出现一个问题了:如果上次ARR的值是200,通道1的比较寄存器CCR1值是100,产生占空比为50%的PWM。这个时候我要改变PWM的频率,我把ARR的值改为100,CCR1的值还没来得及更改,那么占空比肯定就会出问题,所以我就需要让他们同步修改。以前ARR=200,CCR1=100,提高频率后ARR=100,CCR1=50,我需要这两个寄存器的值同步修改,最好还是让他们计数完一个周期后再修改,那么进入下一个周期ARR、CCR1同步修改过去,对PWM的占空比就没有一点影响了。

为了达到这个目的,就得先用一个寄存器A把修改的值保存好(ARR_A=100,CCR1_A=50),一旦上一个周期结束,给一个信号,立即就把寄存器A的值赋值过去,立即生效,这样就完成了最理想的在定时器运行中修改寄存器的过程。下面对应到stm32中:

有影子寄存器的寄存器实际上对应了两个寄存器:一个是用户可以写入或读出数据的寄存器,称为preload register(预装载寄存器),另一个是用户看不见的、但在操作中真正起作用的寄存器称为shadow register(影子寄存器)。我们修改的定时器周期、预分频系数、通道的比较值等都是修改的表面那个预装载寄存器,要让这个修改起作用,就还要把预装载寄存器的值赋给影子寄存器才行。

从ARR预装载寄存器传送到影子寄存器,有两种方式,一种是立刻更新,一种是等触发事件之后更新;这两种方式主要取决于寄存器TIMx->CR1中的“APRE”位:
APRE=0,当ARR值被修改时,同时马上更新影子寄存器的值;
APRE=1,当ARR值被修改时,必须在下一次事件UEV发生后才能更新影子寄存器的值;

这就是TIM_ARRPreloadConfig(TIM14, ENABLE);函数的作用,同理TIM_ARRPreloadConfig()的作用就是通过TIMX_CCMR寄存器的OC1PE位实现在下一个周期将写入预装载寄存器的值写入实际起作用的影子寄存器中。


http://chatgpt.dhexx.cn/article/O9NSY7NK.shtml

相关文章

matlab信号与系统实验总结

求特征根 特征方程的求解 A[1 7 16 12] rroots(A)结果 求线代数方程组 format rat A[3 0 0; 4 3 0;2 2 3]; %左边 C[1 2 0]; %右边 Binv(A)*C求单位冲激响应 a2; t0:0.01:5; A[1 a]; B[0 a]; impulse(B,A,t)零状态冲激响应 syms t; y1exp(-2*t)*cos(3*t)*heaviside(t);%原…

DNS配置实验小结

DNS server是完成域名和IP之间正向、反向查询的一台服务提供者,由于互联网上的各种类型(例如Web、Mail、FTP等)的服务器地址都是由IP 构成,不方便记忆也不方便使用,因此需要使用一段方便记忆的文字(即域名)来翻译它进行使用,而DNS就是完成这个翻译过程的一个系统,DNS服务器…

11.10 VLAN实验总结

VLAN&#xff1a;虚拟局域网&#xff0c;隔离广播域&#xff08;将原本的一个广播域逻辑的切分成多个广播域&#xff09;—通过在交换机上创建不同的VLAN&#xff0c;并且将不通的接口 划入相应的VLAN&#xff0c;让交换机在洪泛时按照不同的VLAN发送数据&#xff0c;实现广播域…

Spark SQL实验小结(2022.4.10)

Spark SQL实验小结&#xff08;2022.4.10&#xff09; 说实话&#xff0c;这作业写的也是真够久的&#xff0c;给我累到了~但是&#xff0c;我不能让我辛辛苦苦学的东西过几天就忘了&#xff0c;所以呢&#xff0c;所以呢&#xff0c;学一下大佬的学习方法&#xff0c;写个博客…

嵌入式综合实验小结

一&#xff1a;实验目的 利用CC2530 的GPIO读取按键值并相应对进行LED发光二极管的亮灭操作&#xff1b;利用CC2530的串口0进行数据收发通讯。 二&#xff1a;实验环境 1.硬件&#xff1a;通用节点、USB仿真器、USB电缆、PC机&#xff1b; 2.软件&#xff1a;IAR Embedded Wor…

Windows 实验总结

关于DLL的生成地址 在CreateDLL.cpp文件中&#xff0c;我定义了两个函数&#xff0c;同时这里 __stdcall&#xff1a;Windows API默认的函数调用协议。 在头文件做好相对应的定义&#xff1a; __declspec(dllexport) 将一个函数声名为导出函数&#xff0c;就是说这个函数要…

java实验总结_java第一次实验总结第三周总结

Java第一次实验报告&#xff0c;java开发环境与简单的Java程序 一.实验目的 1.熟悉JDK开发环境 2.熟练掌握结构化程序设计方法 二.实验内容 打印输出所有的“水仙花数”&#xff0c;所谓“水仙花数”是指一个3位数&#xff0c;其中各位数字立方和等于该数本身。例如&#xff0c…

关于计算机网络安全实验报告总结,信息安全实验总结报告

信息安全实验总结报告 篇一:信息安全实验报告 课程名称: 信息安全 实验名称: 共五次实验 班级: 姓名: 同组人: 指导教师评定: 签名: 实验一 木马攻击与防范 一、实验目的 通过对木马的练习,使读者理解和掌握木马传播和运行的机制;通过手动删除木马,掌握检查木马和删…

Android Studio实验小结

hello&#xff0c;刚上手AS的小白总是会遇到各种问题。现在写个博客&#xff0c;记录一下这次实验遇到的问题 1、AS运行时总是Wating for Target Device to Come Online 状况&#xff1a;明明看见进度条已经到头了&#xff0c;app却仍然不能launch 解决方法&#xff1a;最直…

springboot-安全认证security+jwt总结

目录 一、背景 二、基本jar依赖引入 三、security模块 1、编写配置类 2、UnauthorizedHandler代码 3、security验证用户名和密码的部分 四、jwt模块 1、jwt原理部分 2、jwt一共需要四个类 五、总结 一、背景 要做一个后台管理系统&#xff0c;会引入多个系统&#x…

璀璨盛启·焕美升级 上颜集团杭州医学旗舰中心盛大启幕

2023年4月26日&#xff0c;「璀璨盛启焕美升级」上颜杭州医学旗舰中心启幕盛典在杭州滨江钱龙大厦耀新启幕。上颜用审美、匠心构建城市的活力与色彩&#xff0c;致力于为客户带来全新的美丽方式和一流的品质服务。 &#xff08;上台剪彩嘉宾从左至右依次为&#xff09;上颜集团…

尚品汇项目难点及解决

v-router重写push、replace方法 问题描述&#xff1a;当页面再次进入同一个路由地址时&#xff0c;控制台报错 解决方法&#xff1a;修改vue-router的配置文件&#xff0c;也就是router/index.js文件 //重写VueRouter.prototype身上的push方法了 VueRouter.prototype.push …

技术·融合·治理|众享链网2021发布会暨试运行启动仪式成功举办

2021年6月&#xff0c;工业和信息化部、中央网信办共同发布《关于加快推动区块链技术应用和产业发展的指导意见》&#xff0c;建设多方协同共赢的先进产业链&#xff0c;打造多技术融合的区块链生态体系已成为新的发展方向。如何能让所有人都有机会参与这场区块链的产业变革&am…

尚品汇前端项目难点

尚品汇前端项目 1.如何运行后浏览器自动打开 ​ 解决方法&#xff1a;找到package.json 找到 script serve 后面加 –open 2.打开后发现第一次打开网页显示http://0.0.0.0:8080/ 的网页可能暂时无法连接&#xff0c;或者它已永久性地移动到了新网址。 解决方法&#xff1a;…

九龙证券|券商春季策略扎堆来袭 风格切换成焦点

2月以来&#xff0c;国泰君安、中信建投、国金证券等10余家券商组织相继发布2023年春季战略。综合来看&#xff0c;组织对A股持达观预期&#xff0c;未来两三个月A股商场或迎来重要切换。风格上&#xff0c;“中心财物&#xff0c;生长接力”或许成为上半年装备主线&#xff0c…

分击合进,锦江之星酒店与白玉兰酒店再领投资热潮

2022年11月11日&#xff0c;「山水画中游&#xff0c;暇享好时光」品牌品鉴会在广西桂林隆重召开。锦江酒店&#xff08;中国区&#xff09;旗下两大酒店品牌锦江之星酒店和白玉兰酒店携手亮相本次活动。 &#xff08;品牌矩阵品鉴会活动现场&#xff09; 后疫情时代&#xff…

盛世昊通打造好品艺拍线上交易平台,助力推广中国艺术文化

艺术品交易市场这两年的发展可谓是空前热烈&#xff0c;诸多艺术品皆迎来变现需求。新时代背景下&#xff0c;有数字技术的加持&#xff0c;数字文化资产作为数字经济发展的重要组成部分&#xff0c;成就了文化交易市场蓝海。 为响应国务院“全面复兴传统文化”&#xff0c;“提…

上海亚商投顾:沪指高开低走涨0.45% 大消费王者归来

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 沪指今日高开低走&#xff0c;深成指、创业板指较为强势&#xff0c;盘中均涨超2%&#xff0c;午后涨幅有所收窄。…

《扬帆优配》互联互通扩容提升港股市场活力

作为国际最敞开的自由港和重要的国际金融中心之一&#xff0c;香港衔接内地与国际的优势不断稳固。自2022年以来&#xff0c;互联互通机制屡获打破性进展&#xff0c;港交所发挥“超级联系人”的效果不断提高。 今年3月&#xff0c;跟着港股通进一步扩容&#xff0c;一批成长型…

活动回顾丨研发效能度量线下沙龙圆满举办

2月18日&#xff0c;由跬智信息&#xff08;Kyligence&#xff09;联合甄知科技主办的研发效能度量线下沙龙圆满举办。本次沙龙在 Kyligence 上海总部举办&#xff0c;Kyligence 联合创始人兼 CTO 李扬、腾讯 Tech Lead 茹炳晟&#xff0c;以及甄知科技创始人兼 CTO 张礼军在现…