STM32 定时器与PWM的LED控制

学习目标:

1.  使用定时器的某一个通道控制LED周期性亮灭;

2. 采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭。

一、定时器

1、STM32定时器介绍

STMicroelectronics是STM32微控制器中的重要块,具有丰富的外设和功能,其中包括定时器(Timer),用于执行任务或生成时间延迟。STM32的定时器包括基本、通用和高级类型,分别用于不同的应用场景,如PWM输出、输入捕获等。通过STM32定时器,开发人员可以实现时间测量、周期性任务执行、PWM输出控制等功能,满足各种需求。在STM32开发中,熟练掌握定时器的配置和使用至关重要。

下图为STM32定时器分类:

2、常见的定时器 

SysTick定时器

SysTick系统时钟位于Cortex-M3内核,是一个24位递减计数器

主要用于:

精确延时:在多任务操作系统中为系统提供时间基准(时基);

任务切换:为每个任务分配时间片。

WatchDog看门狗 

看门狗设计是用来监视MCU程序运行状态的,是确保系统可靠稳定运行的一种有效措施。

当微控制器受到外部干扰或程序中出现不可预知的逻辑故障导致应用程序脱离正常的执行流程时(俗称程序跑飞),在一定的时间间隔内使系统复位,回到初始状态。

其中,看门狗又分为两类: 

独立看门狗IWDG:

采用独立时钟,不受其他时钟和总线影响,可在停机和待机模式下工作。

适用于独立于主程序之外、能够独立工作且对时间精度要求不高的场合

窗口看门狗WWDG:

计数值有一个上限时间下限时间,低于下限时间或高于上限时间都会触发MCU复位 。

适用于精确计时窗口起作用的应用程序。 

3、STM32定时器模块

基本定时器

 STM32有2个基本定时器TIM6和TIM7,可用作: 通用的16位计数器;产生DAC触发信号。基本定时器的计数模式只有向上计数模式。

 

通用定时器

TIM2、TIM3、TIM4、TIM5为STM32的4个独立的16位通用定时器,具有定时、测量输入信号的脉冲长度(输入捕获)、输出所需波形(输出比较、产生PWM、单脉冲输出等)等功能。

高级定时器

TIM1和TIM8是STM32的2个16位的高级定时器;高级定时器相比基本定时器、通用定时器,功能更为强大。

作用:通用定时功能(TIM1还提供控制三相六步电机的接口,具有刹车功能、死区时间控制等功能,主要用于电机控制。)

二、PWM

1、PWM介绍

 PWM(Pulse Width Modulation,脉冲宽度调制)是一种利用脉冲宽度即占空比实现对模拟信号进行控制的技术,即是对模拟信号电平进行数字表示的方法。广泛应用于电力电子技术中,比如PWM控制技术在逆变电路中的应用;PWM还应用于直流电机调速,如变频空调的交直流变频调速,除实现调速外,还具有节能等特性。

占空比(Duty Cycle),是指在一个周期内,高电平时间占整个信号周期的百分比,即高电平时间与周期的比值: 占空比 = Tp / T 

2、工作原理

  • STM32的定时器除了TIM6和TIM7,其他定时器都可以用来产生PWM输出;
  • 高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出;
  • 通用定时器能同时产生多达4路的PWM输出; STM32中每个定时器有4个输入通道:TIMx_CH1~TIMx_CH4;
  • 每个通道对应1个捕获/比较寄存器TIMx_CRRx,将寄存器值和计数器值相比较,通过比较结果输出高低电平,从而得到PWM信号;
  • 脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。

任务实现

1、使用定时器的某一个通道控制LED周期性亮灭

要求

使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮灭。

代码示例

Timer.c

#include "stm32f10x.h"                  // Device header/*** 函    数:定时中断初始化* 参    数:无* 返 回 值:无*/
void Timer_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	/*中断输出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位//TIM_TimeBaseInit函数末尾,手动产生了更新事件//若不清除此标志位,则开启中断后,会立刻进入一次中断//如果不介意此问题,则不清除此标志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2//即抢占优先级范围:0~3,响应优先级范围:0~3//此分组配置在整个工程中仅需调用一次//若有多个中断,可以把此代码放在main函数内,while循环之前//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/

LED.c 

#include "stm32f10x.h"                  // Device headervoid LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);
}

 main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "LED.h"int main(void)
{LED_Init();Timer_Init();	while (1){}
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)((1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))));TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

实践结果

最后效果即绿色小灯泡间隔 亮 - 灭 - 亮 - 灭。

2、采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭

要求

采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整占空比变化到一个满意效果;使用Keil虚拟示波器,观察 PWM输出波形。

代码示例

PWM.c

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO重映射*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			//开启AFIO的时钟,重映射必须先开启AFIO的时钟
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式		/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;					//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);						//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "PWM.h"uint8_t i;			//定义for循环的变量int main(void)
{/*模块初始化*/PWM_Init();			//PWM初始化while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i);			//依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮Delay_ms(15);			//延时500ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i);	//依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗Delay_ms(15);		//延时500ms}}
}

实验结果

本人在keil仿真观察波形图时遇到了一些问题,无法更新,目前也在寻找方法不断尝试,等尝试成功会第一时间更新博客

总结

学习定时器和PWM仿佛打开了时间控制与信号调节的大门,为单片机开发提供了新的视角。通过定时器,我能够精确地控制任务执行的时间点,实现预期的动作;而PWM的应用则使LED灯的控制更加灵活多样,可以通过调节脉冲宽度和频率实现各种亮度和闪烁效果。这不仅提升了我对时间和信号调节的理解,也为后续舵机等外设的学习奠定了扎实基础。透过这些学习,我不仅增强了技能,更激发了创造力和探索精神,为未来的单片机开发之路注入了更多动力。

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

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

相关文章

Dijkstra求最短路篇一(全网最详细讲解两种方法,适合小白)(python,其他语言也适用)

前言&#xff1a; Dijkstra算法博客讲解分为两篇讲解&#xff0c;这两篇博客对所有有难点的问题都会讲解&#xff0c;小白也能很好理解。看完这两篇博客后保证收获满满。 本篇博客讲解朴素Dijkstra算法&#xff0c;第二篇博客讲解堆优化Dijkstra算法Dijkstra求最短路篇二(全网…

从C++示例理解开闭原则

开闭原则要求我们在编写代码时&#xff0c;尽量不去修改原先的代码&#xff0c;当出现新的业务需求时&#xff0c;应该通过增加新代码的形式扩展业务而不是对原代码进行修改。 假如我们现在有一批产品&#xff0c;每个产品都具有颜色和大小&#xff0c;产品其定义如下&#xf…

父子进程概述

父子进程概述 总结了两篇博客&#xff0c;对父子进程涉及的问题进行了简要总结&#xff08;参考博客在文章末尾&#xff09; 创建进程的目的一般有两个&#xff1a; 一是父进程希望生成一份自己的副本&#xff0c;执行同一个程序中不同的代码片段。二是让子进程执行不同的程序…

python with 和 上下文管理器

with with操作写法简单又安全 文件操作使用with会自动调用关闭文件操作&#xff0c;即使出现异常也会自动调用文件关闭操作 上下文管理器 with语句强大的根本是由上下文管理器支持的 通过open打开的的文件&#xff0c;赋值给的一个变量file&#xff0c;file就是文件对象&am…

linux docker常用命令记录

一、防火墙 1. 开启防火墙 systemctl start firewalld 2.查看防火墙状态 systemctl status firewalld 二、docker 1.启动docker systemctl start docker 2.关闭docker systemctl stop docker 3.重启docker systemctl restart docker4.查看docker 运行状态 systemc…

Kotlin 函数

文章目录 函数的定义函数的返回值参数默认值 & 调用时参数指定函数作用域Lambda 表达式匿名函数内联函数扩展函数中缀函数递归函数 & 尾递归函数 函数的定义 函数可以理解成一个小小的加工厂&#xff0c;给入特定的原材料&#xff0c;它就会给出特定的产品。 fun [接…

知识运维概述

文章目录 知识运维研究现状技术发展趋势 知识运维 由于构建全量的行业知识图谱成本很高&#xff0c;在真实的场景落地过程中&#xff0c;一般遵循小步快走、快速迭代的原则进行知识图谱的构建和逐步演化。知识运维是指在知识图谱初次构建完成之后&#xff0c;根据用户的使用反馈…

小白跟做江科大32单片机之对射式红外传感器计次

原理部分 1中断示意图&#xff0c;中断会打断主函数的执行&#xff0c;终端执行完成之后再返回主函数继续执行 2.STM32中断 这些灰色的是内核中断 这些白色的是普通中断 3.NVIC统一管理中断&#xff0c;每个中断通道都拥有16个可编程的优先等级&#xff0c;可对优先级进行分组…

独孤思维:10个T的赚钱资料,要不要

01 今天有一个通过网站引流过来的粉丝。 问我&#xff0c;为啥网站不设置付费&#xff0c;这样直接转化成网站vip。 我说&#xff0c;我想把用户沉淀到私域。 其实这个问题&#xff0c;独孤在早年做网站的时候也思考过。 前端给资料&#xff0c;是为了后端引流加个人号&am…

java-this关键字

Java 中的 this 关键字是一个特殊的引用&#xff0c;它代表当前对象。在 Java 中&#xff0c;this 关键字可以在类的构造函数、方法、块和初始化语句中使用。this 关键字的主要作用是&#xff1a; 1. 引用当前对象的属性&#xff08;Field&#xff09;&#xff1a;使用 this 关…

OCP题库

Q2.分析下面的语句和输出: mysql> SHOW GRANTS FOR jsmith; ------------------------------------------------------------------------------------------------------------------- IGrants for jsmith% | -----------------------------------------------------------…

Redis缓存(笔记一:缓存介绍和数据库启动)

目录 1、NoSQL数据库简介 2、Redis介绍 3、Redis(win系统、linux系统中操作) 3.1 win版本Redis启动 3.2 linux版本Redis启动 1、NoSQL数据库简介 技术的分类&#xff1a;&#xff08;发展史&#xff09; 1、解决功能性的问题&#xff1a;Java、Jsp、RDBMS、Tomcat、HTML、…

Filter和ServletContext和Listener

目录 Filter案例 解决全站乱码问题 登录权限校验 ServletContext对象 Listener&#xff08;监听器&#xff09; Filter案例 解决全站乱码问题 我们每次访问每个servlet都要书写处理请求和响应乱码的代码&#xff0c;这样代码十分冗余&#xff0c;所以我们可以在过滤中 We…

Java——变量

一、变量介绍 变量就是申请内存来存储值。也就是说&#xff0c;当创建变量的时候&#xff0c;需要在内存中申请空间。内存管理系统根据变量的类型为变量分配存储空间&#xff0c;分配的空间只能用来储存该类型数据。 1、变量声明和初始化 变量的声明&#xff1a; int a; i…

44-1 waf绕过 - WAF的分类

一、云 WAF 通常包含在 CDN 中的 WAF。在配置云 WAF 时&#xff0c;DNS 需要解析到 CDN 的 IP 上。请求 URL 时&#xff0c;数据包会先经过云 WAF 进行检测&#xff0c;如果通过检测&#xff0c;再将数据包流向主机。 二、硬件IPS/IDS防护、硬件WAF 硬件IPS/IDS防护&#xff…

VS Code 开发小技巧

VS Code的开发小技巧 添加代码片段 平时开发的时候&#xff0c;可以快速创建一个空白的模板。 一个快速生成代码片段的网站&#xff1a;https://snippet-generator.app/ 打开网站&#xff0c;把常用的模板代码复制进去&#xff0c;就会自动生成VS Code可以使用的代码片段了。…

最低要求条件下的商环定义

从一篇老外的书籍看到的&#xff0c;感觉挺不错&#xff0c;记录下&#xff01;&#xff01;&#xff01; 【商环定义】&#xff08;最低要求&#xff09; 设 R ≠ { 0 } R \neq \left\{ 0 \right\} R{0}为交换幺环&#xff0c;设子集 S ⊆ R S \subseteq R S⊆R满足乘法运…

从零到一建设数据中台 - 关键技术汇总

一、数据中台关键技术汇总 语言框架&#xff1a;Java、Maven、Spring Boot 数据分布式采集&#xff1a;Flume、Sqoop、kettle 数据分布式存储&#xff1a;Hadoop HDFS 离线批处理计算&#xff1a;MapReduce、Spark、Flink 实时流式计算&#xff1a;Storm/Spark Streaming、…

没有 rr 头的 kamailio 路由脚本

分享下笔者最近编写的 kamailio 路由脚本 不用 rr 模块&#xff0c;因为有些 sip 协议栈不支持 rr 头处理 sip 注册直接回 200 OK&#xff0c;这部分目前不是重点更换 contact 头&#xff0c;换成 kamailio 自己目前只支持 sip transport 为 udp&#xff0c;以后可能支持 tcp&…

2024.05.30更新票星球抢购软件

文章目录 软件功能订阅须知早期代码软件功能 自持自定义搜索演唱会信息支持添加、删除观影人信息支持多账号并发抢票支持捡漏模式支持IP代理订阅须知 订阅后如果有问题,请联系博主,如果不懂可以免费提供讲解和远程服务早期代码 def enter_concert(self):print(u###打开浏览器…