细说STM32单片机使用通用定时器生成固定占空比和可变占空比PWM波的方法

目录

一、本实例测试的目的

二、硬件和CubeMX项目配置

1、硬件开发板 

2、项目配置

(1)定时器TIM2_CH1

(2)时钟和Debug

(3) NVIC

(4)GPIO

3、输出固定占空比的PWM波源码

(1)启动定时器

(2)控制LED

(3)下载与测试

4、输出可变占空比的PWM波

(1)改变占空比的方法

5、输出可变占空比的PWM波源码

(1)新增变量

(2)启动定时器

(3)控制LED

(4)下载与测试


一、本实例测试的目的

        使用TIM2的CH1输出生成PWM波, 首先输出固定占空比的PWM波,然后再改动程序后输出可变占空比的PWM波。

二、硬件和CubeMX项目配置

1、硬件开发板 

        开发板型号NUCLEO-G474RE,MCU型号STM32G474RET6,该MCU有1个高精度定时器、3个高级控制定时器、7个通用定时器(TIM2~TIM5、TIM15~TIM17)和2个基础定时器。此外还有2个看门狗定时器和1个SysTick定时器。

        开发板上TIM2的CH1连接的引脚PA5。PA5引脚不能设置为GPIO_Output,而要设置为TIM2_CH1。在开发板上,PA5管脚本身就是指示灯LD2,高电平亮。本实验不仅要控制LD2开与关还要控制它的明亮程度。

        开发板上PB11设置为LED1,PB11输出高电平时LED1亮,否则,LED1灭。可以用TIM2的CH1输出PWM波控制LED1的开与关(以PWM的频率)。PB11引脚设置为GPIO_Output。

2、项目配置

(1)定时器TIM2_CH1

        Channel1选择PWM Generation CH1;Clock Source选择Internal Clock;

  • Prescaler,预分频寄存器值,设置为16999,所以预分频系数为17000。定时器使用内部时钟信号频率为170MHz,经过预分频后进入计数器的时钟频率就10kHz,即

  • Counter Period,计数周期(ARR的值),设置为199,所以一个计数周期是

        

  • Internal Clock Division,内部时钟分频,是在定时器控制器部分对内部时钟进行分频,可以设置为1、2或4分频,选项No Division就是无分频,使得CK_PSC等于CK INT。
  • auto-reload preload,自动重载预装载,即设置TIM2_CR1寄存器中的ARPE位。如果设置为Disable,就是不使用预装载,设置的新ARR的值立即生效;如果设置为Enabled, 设置的新ARR的值在下一个UEV事件时才生效。
  • Mode,PWM模式,选项有PWM Mode 1(PWM模式1)和PWM Mode 2(PWM模式2)。这两种模式的定义如下:

        PWM模式1:在递增计数模式下,只要CNT<CCR,通道就是有效状态,否则为无效状态。在递减计数模式下,只要CNT<CCR,通道就变为无效状态,否则为有效状态。

        PWM模式2:其输出与PWM模式1正好相反,例如,在递增计数模式下,只要CNT<CCR,通道就是无效状态,否则为有效状态。

  • Pulse,PWM脉冲宽度,就是设置32位的捕获/比较寄存器CCR的值。脉冲宽度的值应该小于计数周期的值,这里设置为50,因为计数器的时钟频率是10kHz,所以脉冲宽度为5ms。
  • Output compare preload,输出比较预装载。CCR有预装载功能,寄存器TIMx_CCMRy中的OCyPE(Output Capture y Preload Enable)位可以使能或禁用其预装载功能。这个参数就是设置这个位的值,设置为Enable时,修改CCR的值需要到下一个UEV事件时才生效,否则立刻生效。
  • Fast Mode,是否使用输出比较快速模式,就是设置寄存器TIMx_CCMR1中的OC1FE位,用于加快触发输入事件对CC输出的影响,一般设置为Disable即可。
  • CH Polarity,通道极性,就是CCR与CNT比较输出的有效状态,可以设置为高电平 (High)或低电平(Low)。通道极性和PWM模式的组合可以生成不同的PWM波形。 

(2)时钟和Debug

        HSE选择外部晶振,24MHZ,APB1 = APB2 = 170MHz;

        Debug选择Serial Wire;

(3) NVIC

        Time Base修改为0;

        TIM2 global interrupt设置为1;

(4)GPIO

        设置PB11为GPIO OUTPUT,默认高电平,PP,高速,别名LED1。

        经过这样的设置,在启动定时器TIM2后,在引脚PA5(TIM2_CH1通道)上输出的PWM 波形:通道极性为高,PWM模式为1。PWM波的周期为20ms,由ARR的值决定;高电平脉冲宽度为5ms,由CCR的值决定。

        同时扩展板上的PB11的LED1闪烁。

3、输出固定占空比的PWM波源码

(1)启动定时器

/* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim2);				//以中断方式启动TIM2HAL_TIM_PWM_Start_IT(&htim2,TIM_CHANNEL_1);	//TIM2通道1,启动生成PWM
/* USER CODE END 2 */

        MX_TIM2_Init()是定时器TIM2的初始化函数。要启动TIM2的PWM波输出,需要先执行函数HAL_TIM_Base_Start_IT()启动定时器,再执行函数HAL_TIM_PWM_Start IT()启动CH1的PWM波输出。 

(2)控制LED

         控制LED1(PB11)的开与关。

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM2)HAL_GPIO_TogglePin (LED1_GPIO_Port,LED1_Pin);
}
/* USER CODE END 4 */

        控制LD2(PA5),自动生成。

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(htim->Instance==TIM2){/* USER CODE BEGIN TIM2_MspPostInit 0 *//* USER CODE END TIM2_MspPostInit 0 */__HAL_RCC_GPIOA_CLK_ENABLE();/**TIM2 GPIO ConfigurationPA5     ------> TIM2_CH1*/GPIO_InitStruct.Pin = GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN TIM2_MspPostInit 1 *//* USER CODE END TIM2_MspPostInit 1 */}}

(3)下载与测试

        下载到开发板连续运行,用示波器可以观察PA5引脚上输出的固定占空比的PWM波形。用眼睛可以看到闪烁的LED1(PB11)和恒亮的LD2(PA5)。改变PWM高电平脉冲宽度可以改变LD2的亮度,因为PA5引脚为高电平时LED亮,所以PWM脉冲宽度越大,LD2越亮。在函数MX_TIM2_Init()的代码里,直接修改PWM参数结构体变量sConfigOC的成员变量的赋值,可以观察不同参数取值的影响,例如,修改PWM模式参数OCMode、有效极性参数OCPolarity、脉冲宽度参数Pulse等。

//sConfigOC成员
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 50;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

4、输出可变占空比的PWM波

(1)改变占空比的方法

        LD2的亮度是由PWM波的占空比控制的,例1的程序输出PWM波是固定占空比,所以 LD2的亮度是固定的。如果在程序运行过程中动态修改PWM的占空比,就可以使LD2从暗到明、从明到暗地变化,形成一种呼吸的效果。LED1的亮度不受影响。

        在程序中动态改变PWM波的占空比,就是要修改寄存器TIMx_CCR1的值。下图是动态修改PWM波的占空比的示意图。在本示例中,PWM波的周期是200个时钟周期,在发生比较匹配事件时,会产生TIM_IT_CC1中断事件(置位CCyF中断标志位),可以在此中断里修改CCR的值。

 

        CCR是有预装载功能的。如果禁止CCR预装载功能,对CCR的修改立即生效;如果启用了CCR预装载功能,设置新的CCR值需要在下一个UEV事件时才生效。参数Output compare preload控制是否启用CCR的预装载功能,本例里需要设置为 Enable。

        如果CCR的值等于定时器计数器的值,就会置位中断事件标志位CCyIF,即产生TIM_IT_CCy中断事件。生成PWM波是输出比较,HAL_TIM_PWM_PulseFinishedCallback() 是对应的回调函数,可以在这个回调函数里修改CCR的值。当CCR预装载功能使能时,在下次UEV事件时对CCR的修改就会生效,从而可以动态地改变PWM波的占空比。

        使用宏函数__HAL_TIM_SET_COMPARE()可以设置CCR的值,其原型定义为:        

__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)

        其中,__HANDLE__是定时器对象指针,__CHANNEL__是定时器通道,__COMPARE__是需要为CCR设置的值。例如,将TIM2的CH1通道的CCR设置为0x0037的语句为:

__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,0x0037);

        另外,宏函数__HAL_TIM_GET_COMPARE()可以获取CCR当前的值,其函数原型定义如下,这个函数返回结果是16位或32位整数,与具体定时器的CCR的长度有关。

__HAL_TIM_GET_COMPARE(__HANDLE__ ,__CHANNEL__)

5、输出可变占空比的PWM波源码

(1)新增变量

/* USER CODE BEGIN PV */
uint16_t pulseWidth = 50; //脉宽
uint8_t dirInc = 1;       //脉宽变化方向,1=递增,0=递减
/* USER CODE END PV */

(2)启动定时器

  /* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim2);				//以中断方式启动TIM2HAL_TIM_PWM_Start_IT(&htim2,TIM_CHANNEL_1);	//TIM2通道1,启动生成PWM/* USER CODE END 2 */

(3)控制LED

         控制LED1开与关的频率不变,亮度不受影响。LD2的亮度受PWM占空比的影响,呈现呼吸状态。

/* USER CODE BEGIN 4 */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim){HAL_GPIO_TogglePin (LED1_GPIO_Port,LED1_Pin);if (htim->Instance != TIM2)return;if(dirInc == 1) //脉宽递增{pulseWidth++;if (pulseWidth >= 195){pulseWidth = 195;dirInc=0; //脉宽递减}}else{pulseWidth--;if (pulseWidth <= 5){pulseWidth = 5;dirInc=1;//脉宽递增}}__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,pulseWidth);//设置CCR的值
}
/* USER CODE END 4 */

 

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(htim->Instance==TIM2){/* USER CODE BEGIN TIM2_MspPostInit 0 *//* USER CODE END TIM2_MspPostInit 0 */__HAL_RCC_GPIOA_CLK_ENABLE();/**TIM2 GPIO ConfigurationPA5     ------> TIM2_CH1*/GPIO_InitStruct.Pin = GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN TIM2_MspPostInit 1 *//* USER CODE END TIM2_MspPostInit 1 */}}

(4)下载与测试

        该方法实现了按脉宽递增或递减方向修改CCR的值,因为开启了CCR预装载功能,所以新设置的CCR的值在下一个UEV事件时才生效。下载并运行此程序,我们就可以观察到LD2 由明到暗,再由暗到明的循环往复变化效果。

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

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

相关文章

docker进入容器运行命令详细讲解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; 在 Docker 中&#xff0c;进入容器并运行命令是常见的操作&#xff0c;尤其是当你想要调试、检查日志或手动运行某些程序时。Docker 提供了几种方式来进入容器和执行命令。 前提条件 确保你的 Docker 容器…

Vulnhub:BlueSky

靶机下载地址 信息收集 主机发现 nmap扫描攻击机同网段存活主机。 nmap 192.168.31.0/24 -Pn -T4 靶机ip&#xff1a;192.168.31.171。 端口扫描 nmap 192.168.31.171 -A -p- -T4 开放端口22,8080。 目录扫描 访问8080端口&#xff0c;如图&#xff0c;是tomcat管理页面…

unity3d入门教程七

unity3d入门教程七 17.1物理系统17.2静态刚体17.3刚体的碰撞17.4刚体的反弹18.1运动学刚体18.2碰撞检测18.3碰撞事件回调18.4目标的识别18.5碰撞的规避 17.1物理系统 在物理系统中的物体具有质量和速度的是刚体 不用写代码就会自由落体运动了 17.2静态刚体 给 ‘地面’ 添…

学习笔记JVM篇(四)

垃圾回收器 说完垃圾回收算法接下来就需要对应的垃圾回收器去回垃圾回收器。接下来介绍几种垃圾回收器 1、Serial 串行回收器&#xff0c;是单线程版本&#xff0c;暂停所有的应用。在单CPU的情况下效率是很高的&#xff0c;因为不涉及线程的上下文切换。适用于小型程序和客…

【C语言】分支和循环(下)

分支和循环&#xff08;下&#xff09; 5、练习&#xff1a;判断年份是否为闰年6、短路7、switch语句7.1 if语句和switch语句的对比7.2switch语句中的break语句7.3switch语句中的default7.4 switch语句中的case和default的顺序问题 8、while循环8.1 if和while的对比8.2 while语…

C++_20_多态

多继承会造成 菱形继承** 使用虚继承来解决 不是给爷爷类加 也不是给子类加 是给父类加 虚基指针和虚基表 多态 概念&#xff1a; 概念&#xff1a; 一个事物的多种形态&#xff0c;简称多态 如&#xff1a; 对象的多态 ​ 张三 ​ 在对象面前 怂 ​ 在朋友面前 谄媚 ​ 在父…

搜索二叉树BSTree的原理及实现

目录 一、简介 二、功能的实现 节点的实现 这里为什么模板参数采用的是K而不是T呢&#xff1f; 树体的实现 非递归版本 Insert函数 Find函数 Erase函数 递归版本 中序遍历 FindR InsertR EraseR 构造函数 析构函数 拷贝构造 赋值重载 一、简介 BSTree&#x…

【CS110L】Rust语言 Lecture3-4 笔记

文章目录 第三讲 所有权:移动与借用&例1例2例3 错误处理&#xff08;开头&#xff09;为什么空指针如此危险&#xff0c;我们能做什么以应对&#xff1f;— 引出Optionis_none()函数unwrap_or()函数常见用法 第四讲 代码实践:链表Box节点和链表的定义节点和链表的构造函数判…

Hack the 21LTR: Scene 1 靶机

靶机配置 kali配置 虚拟网络适配器配置 不行的时候关闭虚拟机&#xff0c;多点几次生成 主机发现和端口扫描 主机发现 arp-scan -l 端口扫描 端口扫描发现21&#xff0c;22&#xff0c;80端口开放 nmap -sV -A -T4 192.168.2.120 访问80端口 http://192.168.2.120/ 查看页…

SOMEIP_ETS_108: SD_Deregister_from_Eventgroup

测试目的&#xff1a; 验证DUT在接收到StopSubscribeEventgroup消息并取消订阅后&#xff0c;不会响应TestEventUINT8触发的事件。 描述 本测试用例旨在确保DUT在取消对事件组的订阅后&#xff0c;不会对随后的事件触发做出响应。 测试拓扑&#xff1a; 具体步骤&#xff1…

.NET内网实战:通过命令行解密Web.config

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏&#xff0c;主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧&#xff0c;对内网和后渗透感兴趣的朋友们可以订阅该电子报刊&#xff0c;解锁更多的报刊内容。 02基本介绍 本文内容部分节选自小报童…

Spring Boot集成Akka Cluster快速入门Demo

1.什么是Akka Cluster&#xff1f; Akka Cluster将多个JVM连接整合在一起&#xff0c;实现消息地址的透明化和统一化使用管理&#xff0c;集成一体化的消息驱动系统。最终目的是将一个大型程序分割成若干子程序&#xff0c;部署到很多JVM上去实现程序的分布式并行运算&#xf…

编译原理之预处理

目录 生成预处理文件的的命令 预处理做了什么 实验 --------------------------------------------------------------------------------------------------------------------------------- 本篇文章主要是带着大家一起看看预处理阶段编译器都做了些什么 --------------…

十四,在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明

十四&#xff0c;在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明 文章目录 十四&#xff0c;在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明1. 基本介绍2. 准备工作&#xff1a;3. 内置 Tomcat 的配置3.1 第…

Git项目管理工具

分布式版本控制系统

62. 不同路径、64. 最小路径和

思路 dp&#xff1a;代表到达当前位置的总方式 初始化&#xff1a;第一行的位置dp[0][j]&#xff1a;当前位置只能由左边的位置向右移动得到 所以只有1种方式 d[0][j]1, d[0][0]1 第一列的位置 dp[i][0]&#xff1a;当前位置只能由上一个位置向下移动得到 除此之外的位置可以由…

【Python】基本使用

目录 变量的类型 整数 int 浮点数 float 字符串 str 字符串长度 格式化字符串 布尔类型 动态类型 注释 获取输入 浮点数比较 多元赋值 for循环 函数的定义和调用 创建函数/定义函数 调用函数/使用函数 列表 创建列表 切片操作 遍历列表 新增元素 判断元…

2024最全网络安全工程师面试题(附答案),金九银十找工作必看!

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…

[matlab]matlab调用python的各种方法

前言 在MATLAB中&#xff0c;可以使用 py 函数来调用Python模块和函数。在此基础上&#xff0c;我们可以很轻易的调用python中的各种模块&#xff0c;方便我们在神经网络上的应用仿真。 以下是使用MATLAB调用Python模块的基本步骤&#xff1a; 确保你的系统已经正确安装了Py…

文心一言 VS 讯飞星火 VS chatgpt (347)-- 算法导论23.2 6题

六、假定一个图中所有的边权重均匀分布在半开区间[0,1)内。Prim算法和Kruskal算法哪一个可以运行得更快&#xff1f;如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 在比较Prim算法和Kruskal算法在特定条件下的性能时&#xff0c;我们需要考虑几个因素&#xff…