STM32F4_PWM输出详解

news2024/12/27 19:39:49

目录

1. PWM简介

2. PWM原理

3. 定时器PWM输出比较

4. 定时器PWM捕获/比较通道

5. PWM输出相关寄存器

5.1 捕获/比较模式寄存器 TIMx_CCMR1

5.2 捕获/比较使能寄存器 TIMx_CCER

5.3 捕获/比较寄存器 TIMx_CCR1~4

5.4 刹车(断路)和死区寄存器 TIMx_BDTR

6. 库函数配置PWM输出

7. 实验程序

7.1 main.c

7.2 pwm.c

7.3 pwm.h


1. PWM简介

        脉冲宽度调制:PWM,是英文Pulse Width Modulation的缩写,简称脉宽调制,利用微处理器的数字输出(DAC)来对模拟电路进行控制的一种非常有效的技术。实质就是对脉冲宽度的控制

2. PWM原理

如图是PWM的工作原理图:

        我将通过以往中学数学的一个简单题型来引入PWM的具体工作原理该如何理解:每当看到PWM,总是想起中学数学的一种题型,题目大概意思是这样的:首先我拿到两个复杂的函数,需要先画出函数的图像,当画出两个函数图像时,会明显发现这两个函数交织在一起,通常这个时候出题人总会让我们判断交点所对应的值是多少,进而进行赋值写出分段函数;比如说  1<x<2时y=0; x=2时y=1;x=3时y=2; 3<x<4时y=3;  

其实PWM原理就形似于一个分段函数:

        如图,定时器工作在向上计数模式,也就是计数器这个时候是递增计数的;当计数器CNT的值小于CCRx时,输出低电平0(CNT<CCRx等同于上述的1<x<2,低电平0等同于y=0;输出低电平再次阐述了定时器的输出比较功能);当CNT大于CCRx时,输出高电平1;当CNT=ARR时,重新归零(等同于函数的结点值时赋值);然后重新向上计数,依次循环;这时IO口会跟据PWM输出的比较值产生一个高低电平的时序图;

当我们改变CCRx和ARR的值会有什么影响呢?

        改变CCRx的值:会导致我们IO输出的低电平时间变小,因为总的定时器时间是不变的,理所当然的高电平1的时间会变长。相对专业的讲是改变了PWM输出的占空比;(占空比是一个脉冲周期内,高电平的时间与整个周期时间的比例

        改变ARR的值:改变了PWM输出的频率;(PWM频率的意思是指1秒钟内信号从高电平到低电平再回到高电平的次数

3. 定时器PWM输出比较

我们将定时器分为四部分:选择时钟、时基电路、输入捕获、输出比较。

4. 定时器PWM捕获/比较通道

        每个定时器有四个通道,每一个通道都有一个捕获比较寄存器;将计数器TIMx_CNT的值TIMx_CCRx寄存器的值进行比较,通过比较的结果输出高低电平,实现PWM输出信号。

        每个捕获/比较通道均围绕一个捕获/比较寄存器(包括一个影子寄存器)、一个输入捕获阶段(包括数字滤波、多路复用和预分频器)一个输出比较阶段(包括比较器和输出控制)组成本章PWM输出就是利用定时器PWM输出比较功能实现的。这里我们将输入捕获和输出比较阶段都进行讲解;

极性的作用就是判断有效电平是高电平还是有效电平是低电平。

5. PWM输出相关寄存器

STM32 除了 TIM6 和 TIM7 ,其余的定时器都可以用来产生 PWM 输出。通用定时器可以同时产生 4 路的 PWM 输出。以下介绍的寄存器均是TIM14的相关寄存器。

5.1 捕获/比较模式寄存器 TIMx_CCMR1

捕获/比较模式寄存器 TIMx_CCMR1 (capture/compare mode register1)16位寄存器

因为该寄存器既具有输入捕获功能,又具有输出比较功能所以配置寄存器的相关位会导致在输入模式和输出模式下的功能均不同。

位[1:0]:配置通道方向;也就是该寄存器为输出还是输入;

        00:输出比较

        01:输入捕获

注意:OCXX表示输出位配置(Output);ICXX表示输入位配置(Intput);

           因为本实验程序中只使用了TIM14的1通道,所以只使用了该寄存器的低8位;但不意味着高8位就无效;多通道时,就会启动高8位;

5.2 捕获/比较使能寄存器 TIMx_CCER

捕获/比较使能寄存器 TIMx_CCER (capture/compare enable register)16位寄存器

对于该寄存器的使用,在该实验中需要使能该寄存器;

位0[CC1E]:捕获/比较 1 输出使能

        0:关闭

        1:开启

5.3 捕获/比较寄存器 TIMx_CCR1~4

捕获/比较寄存器 TIMx_CCR1~4 (capture/compare regiater 1)该寄存器一共有四个;分别对应1~4;本实验所使用的是TIM14定时器,该定时器只有1个该寄存器TIM14_CCR1;

5.4 刹车(断路)和死区寄存器 TIMx_BDTR

刹车(断路)和死区寄存器 TIMx_BDTR(break and dead-time register)16位寄存器   该寄存器是高级定时器下PWM主输出使能的,该实验并不会使用。

6. 库函数配置PWM输出

1. 开启TIM14和GPIO时钟,配置PF9选择复用功能AF9(TIM14)输出。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);     //TIM14时钟使能,才能使用定时器TIM14的功能

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);     //开启GPIOF时钟

GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);   //因为STM32的所有引脚都可以当GPIO口,所以需要将GPIOF9复用为定时器TIM14

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;   //GPIO初始化设置模式为复用功能

GPIO_Init(); //GPIO初始化,GPIO口初始化并不只是上述一个复用功能; 

2. 初始化TIM14,设置TIM14的ARR和PSC等参数。TIMx_ARR:自动重载寄存器   TIMx_PSC:预分频寄存器

TIM_TimeBaseInit();  //初始化TIM14

TIM_TimeBaseInitStructure.TIM_Period=arr;   //设置自动重装载值arr;

……………………TIM_TimeBaseInitStructure初始化的其他参数配置

TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);//初始化TIMx

3. 设置TIM14_CH1的PWM模式,使能TIM14的CH1输出

根据对PWM输出原理图的学习,如果我们希望LED灯逐渐亮,又逐渐暗,呈现一个变化趋势。那么我们必须调控CCR1相对于一个频率内所占的比例,这样PWM输出高低电平时的时间也就不同也可以理解为在一个10s周期内,我让LED亮7s,灭3s,那么循环呈现给视觉的效果就是灯相对比较亮;而如果我让LED亮3s,灭7s,结果呈现给视觉的效果就是LED比较暗所以我们需要通过配置TIM14_CCMR1的相关位来控制TIM14_CH1。

PWM通道通过函数TIM_OC1Init()~TIM_OC4Init();如果使用1通道,那么所使用的函数就是TIM_OC1Init();

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);  // PWM通道初始化函数

typedef struct 
{  
uint16_t TIM_OCMode;   //设置模式是PWM还是输出比较
uint16_t TIM_OutputState;  //设置输出比较使能
uint16_t TIM_OutputNState; 
uint16_t TIM_Pulse;  
uint16_t TIM_OCPolarity;  //设置极性高低
uint16_t TIM_OCNPolarity;  
uint16_t TIM_OCIdleState;  
uint16_t TIM_OCNIdleState; 
} TIM_OCInitTypeDef; 

//其余未标记的均是使用高级定时器时才会用到的参数
TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//选择模式为PWM
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//比较输出使能
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;//输出极性低

TIM_OCInit(TIM14,&TIM_OCInitStructure)

4. 使能TIM14

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

5. 修改TIM14_CCR1来控制占空比

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare2);  //修改TIM14_CCR1占空比  第二个参数就是设置的占空比

对于其他通道分别是:

        void TIM_SetComparex( x取值1 2 3 4 )

注:以上设置对大多数寄存器都是通用的;但是高级定时器想要输出PWM,必须还要设置一个MOE位(刹车(断路)和死区寄存器 TIMx_BDTR(break and dead-time register)16位寄存器    的第15位)使能主输出,否则不会输出PWM。

void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState) //高级定时器使能主输出函数

注意:        

        PWM模式下必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器:

        TIM_ARRPreloadConfig(TIM14,ENABLE);//使能自动重装载寄存器

        最后还有设置TIMx_CR1寄存器的ARPE位,(向上计数或中心对称模式)使能自动重装载的预装载寄存器:

        TIM_OC1PreloadConfig(TIM14,ENABLE);//使能预装载寄存器

7. 实验程序

通过该实验程序可以控制LED灯从亮变暗,再从暗变亮;依次循环。

首先解释为什么实验程序内没有LED0相关的程序,最后却能使得LED0的亮度从亮变暗在变亮?

7.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "LED.h"
#include "BEEP.h"
#include "Key.h"
#include "usart.h"
#include "exti.h"
#include "iwdg.h"
#include "wwdg.h"
#include "Timer.h"
#include "pwm.h"


int main(void)
{
	//占空比的意思就是在一个脉冲周期内,高电平的占整个周期的比例;调整设置的占空比就可以设置在一个脉冲周期内
	//高低电平所占的比例,进而使得LED0亮暗交替。
	unsigned int LED0PulseWidthModulation;//设置LED0占空比
	unsigned int ARR=1;//用ARR的状态来判断一个周期是否结束,起始值为1
	//如果ARR=1,表示一个周期回到了起点;如果ARR=0,表示一个周期达到了终点。
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组为2
	delay_init(168);
	TIM14_PWM_Init(500-1,84-1);
	//设置重装载值为500,也就是计数器的峰值为500
	//预分频值为84,定时器时钟为84M,所以计数频率为84M/84=1Mhz;PWM脉冲周期为频率分之一,同中学的T=1/f
	//所以PWM脉冲周期等于1M/500=2Khz;
	
	while(1)
	{
		delay_ms(10);
		//之所以初始化ARR就是1,也就是初始化为脉冲周期的起点,是因为模式为向上,也就是递增;
		//所以只能从起点开始递增,达到终点就开始递减。
		if(ARR==1)//ARR==1表示脉冲周期回到了起点
			LED0PulseWidthModulation++;//占空比++,高电平占脉冲周期的比例逐渐在增大,LED0越来越亮
		else
			LED0PulseWidthModulation--;//否则表示ARR==0,脉冲周期来到了终点,占空比越来越小,高电平比例越来越小,LED越来越暗
		if(LED0PulseWidthModulation>300)//如果占空比大于300,默认达到了脉冲周期的终点,占空比要开始--,变暗
			ARR=0;//ARR=0为上述程序中的else语句,占空比--;
		if(LED0PulseWidthModulation==0)//当占空比减到0时,达到最暗,默认达到了脉冲周期的起点,占空口开始++;变量
			ARR=1;//ARR=1是上述程序if判断下的语句,占空比++;
		
		
		TIM_SetCompare1(TIM14,LED0PulseWidthModulation);  //修改比较值,修改占空比
		//注意该函数的第二个参数就是设置的占空比值
	}
}
//此处之所以将占空比的值与300进行比较,是因为PWM的输出占空比达到这个值时,LED的亮度变化就不大了。
//PWM最大值可以设置为499
//此程序达到的效果是:从起点出发,LED灯越来越亮,当占空比达到300时,默认达到了峰值,LED灯越来越暗;按照这个流程依次进行循环。

7.2 pwm.c

#include "stm32f4xx.h"                  
#include "pwm.h"

//AutomaticReload:自动重装载值    PrioritySendCount:时钟预分频数

void TIM14_PWM_Init(u32 AutomaticReload,u32 PrioritySendCount) //初始化TIM14 
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);//使能TIM14_CH1 1通道时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);// 使能GPIOF引脚
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);//引脚复用PF9引脚复用为TIM14的通道1
	//GPIO的初始化函数,设置初始化的模式为复用
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //设置GPIO模式为复用  对应上述引脚复用PF9引脚复用为TIM14的通道1
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; 
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOF,&GPIO_InitStructure);
	
	//初始化TIM14定时器,设置预分频值和自动重装载值
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数,也就是递增计数
	TIM_TimeBaseInitStructure.TIM_Period=AutomaticReload;//自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler=PrioritySendCount;//时钟预分频值
	TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);
	
	
	//设置TIM14的PWM模式
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;//输出极性低
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//PWM调质模式1
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出比较使能
	TIM_OC1Init(TIM14,&TIM_OCInitStructure);//初始化TIM14通道1
	
	TIM_ARRPreloadConfig(TIM14,ENABLE);//使能自动重装载寄存器
	TIM_OC1PreloadConfig(TIM14,ENABLE);//使能预装载寄存器
	
	TIM_Cmd(TIM14,ENABLE);//使能TIM14
}

7.3 pwm.h

#ifndef _PWM__H_
#define _PWM__H_

void TIM14_PWM_Init(u32 AutomaticReload,u32 PrioritySendCount);

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/425376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python_Scrapy学习笔记(一)】Scrapy框架简介

Scrapy框架简介 前言 Scrapy 框架是一个用 python 实现的为了爬取网站数据、提取数据的应用框架&#xff0c;使用 Twisted 异步网络库来处理网络通讯&#xff0c;可以高效的完成数据爬取。本文主要介绍 Scrapy 框架的构成与工作原理。 正文 1、Scrapy安装 Windows安装&…

【Unity UPR】造个获取深度法线纹理的轮子

描边需要深度法线纹理的加持&#xff0c;效果才能达到最好&#xff0c;但URP下很多版本不支持直接获取_CameraNormalsTexture&#xff0c;而我本人也尝试了一下在12.1.7下偷懒直接拿SSAO里的Depth Normal图&#xff0c; 虽然也能实现吧&#xff0c;但是需要打开SSAO的同时&…

商务接待广州考斯特商务租车详解!

进入四月份以来&#xff0c;全国各个地区都有很多商务活动举办&#xff0c;广州也不例外&#xff0c;广州很多地区都有商务活动的需求。因此不少主办方都需要商务租车来接待客户&#xff0c;而丰田考斯特是市面上常见的一款高端中巴车&#xff0c;主要是因为考斯特的可靠性、安…

【软件设计师13】数据库设计

数据库设计 1. 数据库设计过程 2. E-R模型 3. E-R图向关系模型的转换 例如一对一联系&#xff0c;可以将联系单独做为关系模式&#xff0c;也可以存放到任意一个实体中 而一对多要合并只能合并到多这边&#xff0c;不能存放到1 多对多则联系必须单独转成一个关系模式 4. 案…

赛狐ERP | 亚马逊选品方法与策略详解:如何挑选最优质的产品?

亚马逊作为全球电商巨头&#xff0c;其产品种类之丰富也是无人能及。然而&#xff0c;在如此繁杂的商品体系下&#xff0c;如何选品成为了摆在商家面前的一道难题。本文将从亚马逊选品的目标、方法、策略三个方面进行详细介绍。 一、选品的目标 在进行选择之前&#xff0c;必…

【C语言】位运算 {位运算的应用 :关闭位,判断位,打开位,转置位;位域}

一、基础 参与位运算的对象只能是整型数据(int, unsigned, char)&#xff0c;不能为实型 移位操作符 按位左移n位表示&#xff1a;原数*2^n按位右移n位表示&#xff1a;原数/2^n&#xff08;整除&#xff09;上述运算只适用于左右移位时被溢出舍弃的位不包含1的情况 二、位运…

7.redis-集群

目录 1. 概念 2. 三主三从redis集群配置 3. redis集群读写 4. 主从扩展案例 5.主从降容案例 6.用到的命令 1. 概念 1).分片: 集群中的每个redis实例都被认为是整个数据的一个分片&#xff0c;官方建议是最大1000个 2).槽位: redis集群有16384个哈希槽&#xff0c;每个key…

Mac平台上有哪些好用的常用软件?

我大概分几类给你介绍一下吧。 一、办公类 1.微软的office系列&#xff0c;在mac平台也有office的全家桶&#xff0c;习惯用微软office的也可以安装。 2.wps office&#xff0c;wps可以说是国产最好用的office软件&#xff0c;最重要的是wps可以跨平台&#xff0c;并且云文档…

C/C++程序设计——static关键字

一、修饰局部变量 &#xff08;1&#xff09;称为静态局部变量&#xff0c;改变局部变量的生命周期&#xff0c;生命周期由局部变为全局。 &#xff08;2&#xff09;作用域不发生改变。 &#xff08;3&#xff09;静态局部变量只能被初始化一次。 本质&#xff1a; 改变了局…

获取UNIX系统时间

① 基本认识 UNIX系统时间主要分为两种&#xff1a; 日历时间 和 进程时间 ② 日历时间 该时间是自协调时间时间 1970年1月1日 00:00:00这个特定时间来计算累积的秒数。&#xff08;称为UTC 格林尼治标准时间&#xff09; 时间值是存放在系统类型time_t里面. ③ 进程时间 也称为…

redis哨兵模式配置(配置文件等)

Redis-Sentinel机制主要用三个功能&#xff1a; (1)监控&#xff1a;不停监控Redis主从节点是否安装预期运行 (2)提醒&#xff1a;如果Redis运行出现问题可以 按照配置文件中的配置项 通知客户端或者集群管理员 (3)自动故障转移&#xff1a;当主节点下线之后&#xff0c;哨兵…

OpenGL 简介

OpenGL 简介 GPU 接口规范 对于刚接触 OpenGL 的初学者,常常会有这样一个疑问: OpenGL 的源码在哪里,如何编译? 然而实际上 OpenGL 并不是一个软件实现,更多的是一个标准协议; OpenGL 更像是一种显卡驱动标准,由各个硬件厂家适配,各个硬件厂商根据 OpenGL 接口规范编撰对应的…

【系统集成项目管理工程师】项目进度管理

&#x1f4a5;十大知识领域&#xff1a;项目进度管理 主要考计算题 项目进度管理包括以下 7 个过程: 规划进度管理过程定义活动过程排列活动顺序过程估算活动资源过程估算活动持续时间过程制定进度计划过程控制进度过程 一、规划进度管理过程 制定政策、程序和文档以管理项目进…

亲测:腾讯云轻量应用服务器性能如何?

腾讯云轻量应用服务器性能评测&#xff0c;轻量服务器CPU主频、处理器型号、公网带宽、月流量、Ping值测速、磁盘IO读写及使用限制&#xff0c;轻量应用服务器CPU内存性能和标准型云服务器CVM处于同一水准&#xff0c;所以大家不要担心轻量应用服务器的性能&#xff0c;腾讯云百…

【CSS】13.页面切图和布局实现

页面切图和布局实现 1. 浮动布局 1.1 页面布局 LOGO 部分 NAV 布局 LEFT - SIDEBAR&#xff1a;左边栏布局 CONTENT&#xff1a;内容布局 RIGHT - SIDEBAR&#xff1a;右边栏布局 1.2 流式布局 块的默认布局叫做流式布局 但流式布局并不能满足对页面的需要&#xff0c…

(学习日记)2023.4.10

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

杰林码图像增强算法——超分辨率、图像放大、轮廓和色彩强化算法(二)

一、前言 2023-03-23我发布了基于加权概率模型&#xff08;杰林码的理论模型&#xff09;的图像颜色增强和轮廓预测的应用方法。效果还不太明显&#xff0c;于是我又花了2周的时间进行了技术优化。下面仅提供了x86下的BMP和JPG对应的lib和dll&#xff0c;本文中的算法属于我国…

为什么CPU需要时钟

为什么CPU需要时钟 为什么CPU需要时钟这样一个概念? 什么是时钟脉冲&#xff0c;CPU为什么需要时钟&#xff0c;时钟信号是怎么产生的&#xff1f; 上面这个图的方波就是一个脉冲&#xff0c;类比于人类的脉搏跳动。一个脉冲称之为CPU的一个时钟信号&#xff0c;或者时钟脉冲…

Melis4.0[D1s]:6.mango-MQ-R基于Melis移植lvgl

文章目录1.下载lvgl源码到《D1s-Melis/ekernel/drivers/hal/test/disp2》目录1.1 修改Makefile1.2 快速测试Makefile修改是否有效2.移植刷新显示内存函数dummy_flush_cb3.创建一个定时器调用lvgl心跳lv_tick_inc()4.pack打包出错&#xff1a;5.设置开机启动6.源码下载上一篇文章…

《类和对象》(上)

本文主要对类和对象有一个初步的了解。 文章目录前言1、类的引入和定义2、类的访问限定符及封装2.1 访问限定符2.2 封装3 、类的作用域4 、类的实例化5 、类对象的模型5.1 类对象的大小5.2 类对象存储方式6、this 指针6.1 引子6.2 特性6.3 this指针的一个问题前言 C语言是面向过…