STM32定时器与PWM对LED灯的控制

news2025/1/19 3:20:42

文章目录

  • 一、定时器——Timer
    • (一)概念
    • (二)分类
    • (三)功能
    • (四)结构
      • 1.模块一——时基单元
      • 2.模块二——输出比较模块
  • 二、实验内容
    • (一)标准库点亮LED灯
      • 1.实验说明
      • 2.设计思路
      • 3.代码部分
      • 4.实验现象
      • 5.keil仿真
    • (二)标准库点亮呼吸灯
      • 1.实验说明
      • 2.设计思路
      • 3.代码部分
      • 4.实验现象
      • 5.kei仿真
  • 三、总结

一、定时器——Timer

(一)概念

定时器,见名知意,是一种专门负责定时功能的片上外设。它的作用是设定一个时间,时间到后通过中断等方式通知STM32执行某些程序。因此,定时器的本质也可认为是计数器。
注意:定时器并不能直接获得现实世界的实时时间,而是当做一个计数器或者计时器来用。

(二)分类

STM32F103C8T6芯片中的定时器有三种八个。(TIM1到TIM8)
在这里插入图片描述

1.基本定时器:TIM6、TIM7。

2.通用定时器:TIM2、TIM3、TIM4、TIM5。

3.高级定时器:TIM1、TIM8。

其中高级定时器挂在总线APB2上,基本定时器和通用定时器挂在总线APB1上。

(三)功能

1.基本定时器:就是时基单元的功能。
2.通用定时器:在基本定时器的基础上增加了输入捕获功能和输出比较功能。
3.高级定时器:在通用定时器的基础上增加了从模式控制器和高级输出控制功能。

我们实验主要采用通用定时器,但我们要尽量了解高级定时器

(四)结构

STM32中单个高级定时器的内部结构如下图所示
在这里插入图片描述

主要可分为四大模块:时基单元输入捕获输出比较(包括绿色框中的高级功能)和从模式控制器。(在这里只介绍常用的时基单元与输出比较模块)

1.模块一——时基单元

在这里插入图片描述
(1)预分频器
RCC传来的脉冲频率很高,一般为72MHz或者为36MHz,而计数器是16位的,因此而一个计数器最多只能计数2的16次方个信号,即65536个脉冲,所以我们理应对该脉冲信号进行分频,分频之后的频率=原频率/(PSC设置的值+1)

(2)计数器与自动重装寄存器
这二者可以看成是捆绑在一起的,自动重装寄存器相当于是计数器的管理员,当自动重装寄存器的值设为n时,要经过n+1个脉冲,计数器的值才会向外输出1个脉冲。即计数器向外输出的脉冲个数=传入寄存器内部的脉冲个数/(ARR设置的值+1)

(3)重复寄存器
仅存在高级定时器中,还是相当于一个分频器。

小节:其实这三者都能起到分频作用,而中间的计数器与自动重装寄存器除此之外还能计数而已。它是时基单元与CCR寄存器建立联系的桥梁。

2.模块二——输出比较模块

二、实验内容

(一)标准库点亮LED灯

1.实验说明

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

2.设计思路

(1)中断的条件
设置为UVE(update event),设置为定时器中的事件更新触发中断。说人话就是,定时器中的计数器溢出一次就出发中断。显然是等周期触发中断,我设置为1ms触发一次中断。每触发一次中断就计时一次,可以用全局变量currentTick来记录中断次数,也可以等同为程序运行的时间。
(2)延时函数的设计
先定义一个我们想要的延时变量命名为ms,其单位也是ms。
再定义一个变量uint64_t expireTime = App_Timer_GetTick() + ms,作为刚开始的定值变量。
接下里在while循环里不断让App_Timer_GetTick()返回的动态变量currentTick去追逐静态的高值变量expireTime,差值恰好为我们想要的延时ms。

3.代码部分

代码中的注释已经很明确了,这里不再逐句赘述。
(1)main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "app_timer.h"


int main()
{
	App_Timer_Init();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);

	
	while(1)
	{
		GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_SET);
		
		App_Timer_Delay(2000);
		
		GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_RESET);
		
		App_Timer_Delay(2000);
		
	}
}

2.app_timer.c文件

#include "app_timer.h"
#include "stdint.h"

static volatile uint64_t currentTick = 0;

void App_Timer_Init()
{
	//对定时器3的复位
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3,DISABLE);
	//1.使能定时器3的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	//2.使能ARR寄存器的预加载特性
	TIM_ARRPreloadConfig(TIM3,ENABLE);
	
	
	//3.初始化实际单元的参数
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 71;      //就是PSC里面的值,先72分频为,72MHz/72 = 1MHz;————>1us
	TIM_TimeBaseInitStruct.TIM_Period = 999;		//1us——————>1ms
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //就是RCR里面的值,重复计数器写0,相当于不再分频。
	//TIM_TimeBaseInitStruct.TIM_ClockDivision ;   //死区时间、输入滤波,暂时不设置
	//TIM_TimeBaseInitStruct.TIM_RepetitionCounter;  //定时器3没有重复计数器,不需要设置
	
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
	
	//这些参数还在影子寄存器里,手动产生中断
	TIM_GenerateEvent(TIM3,TIM_EventSource_Update);
	
	
	
	
	//4.使能Update中断
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);    //重点!!!!中断触发的条件————>更新事件.
								//而更新事件通常指的是定时器的计数器达到自动重载寄存器(ARR)的值时,即完成了一个计数周期,此时硬件会自动置位一个中断标志位(TIM_FLAG_Update)
								//显然就是:1ms触发一次中断!
	
	//5.配置NVIC模块
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
 	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0 ;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0 ;
	
	
	NVIC_Init(&NVIC_InitStruct);
	
	//6.使能定时器
	TIM_Cmd(TIM3,ENABLE);
	
}	


void TIM3_IRQHandler()
{
	if(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update)== SET)	
	//这个函数的本意是得到具体定时器的具体部位的标志位
	//在这里是得到定时器3的更新标志位:当定时器计数器达到自动重载寄存器(ARR)的值并发生更新事件时,硬件会自动置。在这里是1ms
	{
		TIM_ClearFlag(TIM3,TIM_FLAG_Update);   	//中断函数的第一步,清除中断标志位
		currentTick++;					//currentTick计的是毫秒值。每经过1ms,currentTick就加1.
	}

}


uint64_t App_Timer_GetTick()   //获取当前时刻,单位ms
{
	return currentTick;
}

void App_Timer_Delay(uint32_t ms)   //毫秒级延时
{
	uint64_t expireTime = App_Timer_GetTick() + ms;
	while(App_Timer_GetTick() < expireTime);
}
//这个中断函数设计的很巧妙,expireTime是定值,刚进入while循环时,这个大的定值一直与currentTick这个动态值的差值刚好是传入的ms,当currentTick经过ms时间后,循环结束。
//这个动态小值追逐定值大值的过程就是花费的我们设置的延时时间。

4.实验现象

20240531——001

5.keil仿真

在这里插入图片描述
在这里插入图片描述

延时恰好为2s,设计正确。

(二)标准库点亮呼吸灯

1.实验说明

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

2.设计思路

选择定时器的输出比较模式中的PWM模式,输出一个正弦电压到引脚即可。

3.代码部分

(1)main.c文件

#include "stm32f10x.h"
#include "stm32f10x_pal.h"

int main(void)
{
	PAL_Init();
	
	// #1. 将PA8初始化为复用推挽模式
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	// #2. 开启定时器1的时钟
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE);
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
	
	// #3. 初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 71;
	TIM_TimeBaseInitStruct.TIM_Period = 999;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
	
	// #4. 初始化输出比较通道1
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse = 0;
	TIM_OC1Init(TIM1, &TIM_OCInitStruct);
	
	// #5. 闭合MOE
	TIM_CtrlPWMOutputs(TIM1, ENABLE);
	
	// #6. 手动产生UEV
	TIM_GenerateEvent(TIM1, TIM_EventSource_Update);
	
	// #7. 使能定时器
	TIM_Cmd(TIM1, ENABLE);
	
	while(1)
	{
		float t = PAL_GetTick() * 0.001;
		float duty = 0.5 + 0.5 * sin(0.6 *3.14 * t);
		uint16_t ccr = duty * 999;
		TIM_SetCompare1(TIM1, ccr);
	}
}

4.实验现象

20240531——002

5.kei仿真

在这里插入图片描述

我不太明白为啥是频率快的方波,也能达到周期为1~2S的呼吸灯的效果。

三、总结

通过本次实验,学习了定时器的有关概念及其结构。我用标准库通过定时器中断的方式点亮了LED灯。在此过程中我感觉定时器的很多用途都得与中断联系在一起。总的来说,标准库点灯会遇到很多麻烦,和异常的现象,比如keil波形是快频率的方波,实验现象却是呼吸灯的效果。

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

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

相关文章

冯喜运:5.31晚间黄金原油行情分析及尾盘操作策略

【黄金消息面分析】&#xff1a;周五&#xff08;5月31日&#xff09;&#xff0c;最新发布的数据显示&#xff0c;美国4月核心PCE物价指数月率录得0.2%&#xff0c;低于预期(0.3%)&#xff0c;经济学家认为&#xff0c;核心指数比整体指数更能反映通胀。除此之外&#xff0c;美…

电子阅览室能给孩子做什么

电子阅览室为孩子提供了很多活动和资源&#xff0c;可以为他们提供以下服务&#xff1a; 1. 提供电子书籍和儿童读物&#xff1a;电子阅览室通常提供大量的电子书籍和儿童读物&#xff0c;供孩子选择阅读。 2. 提供儿童学习资源&#xff1a;专久智能电子阅览室可以提供各种学习…

收银系统源码-千呼新零售2.0【智慧供应链】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货等连锁店使用。 详细介绍请查看下…

【HTML】通过焦点,获取部分上下文内容

【HTML】通过焦点&#xff0c;获取部分上下文内容 需求 用户从页面中选择部分文字描述&#xff0c;获取这段选中文字&#xff0c;并获取该文字、上两段、下两段内容&#xff0c;作为上下文输入 效果说明 选中绿色框内文字&#xff0c;将黄色框内文字作为上下文传递 代码实…

HackTheBox-Machines--Mirai

Mirai 测试过程 1 信息收集 NMAP 80 端口 指纹识别 目录扫描 http://10.129.141.121/versions http://10.129.141.121/admin 检查 /admin 下接口&#xff0c;发现 http://10.129.141.121/admin/index.php?login 请求&#xff0c;仅密码未知&#xff0c;可以尝试对密码进行爆…

C++青少年简明教程:While和Do-while循环语句

C青少年简明教程&#xff1a;While和Do-while循环语句 C的while和do-while语句都是循环控制语句&#xff0c;用于重复执行一段代码。while语句在循环开始前检查循环条件&#xff0c;而do-while语句在循环结束后检查循环条件。 使用while循环时&#xff0c;如果需要在每次迭代前…

网络安全基础技术扫盲篇名词解释之“证书“

用通俗易懂的话说&#xff1a; 证书就好比是一张身份证&#xff08;类似&#xff0c;但不完全相同&#xff09;&#xff0c;用来证明一个网站的身份是否可信。就像你要确认一个陌生人的身份需要看他的身份证一样&#xff0c;电脑在连接一个网站时&#xff0c;也会查看网站的证…

VS2017中使用qt翻译家,除ui界面外其他用tr包裹的字符串在翻译家中显示为乱码

1、ui界面中的中文,可以正常显示 2、其他用tr包裹的字符串,显示为乱码 3、解决 改为utf8保存。 然后更新翻译文件,重新打开发现已经ok了。 参考博客: https://blog.csdn.net/zhou714534957/article/details/124948822 https://blog.csdn.net/weixin_52689816/article/d…

二进制安装Kubernetes v1.30.1高可用集群

1. kubeadm 和二进制安装 k8s 适用场景分析 kubeadm 是官方提供的开源工具&#xff0c;是一个开源项目&#xff0c;用于快速搭建 kubernetes 集群&#xff0c;目前是比较方便和推荐使用的。kubeadm init 以及 kubeadm join 这两个命令可以快速创建 kubernetes 集群。Kubeadm初始…

为什么都说视频号小店值得做,具体该怎么做?新手必学

大家好&#xff0c;我是电商花花。 所有人都在告诉你2024年应该做视频号小店&#xff0c;但没有人告诉你到底应该怎么做。 今天给大家说一下为什么2024年都推荐大家去做视频号小店&#xff0c;以及分享一些视频号小店的实操干货&#xff0c;可以帮助大家更快更稳的做店。 首先…

IDEA 安装BPMN插件-Activiti BPMN visualizer

IDEA安装BPMN插件 idea 18版本之前idea 18版本之后安装插件 推荐使用 Activiti BPMN visualizer插件注意 创建bpmn文件使用可视化面板 在可视化面板中右键可创建各种节点每个节点上都有连线 删除 设置的按钮 保存图片 idea 18版本之前 可以通过搜索插件actiBPMN直接安装 idea…

Jmeter-使用手册(_5.5版本)

JMeter是一个Java桌面应用程序&#xff0c;具有使用Swing图形API的图形界面。可以进行接口、性能等测试&#xff0c;也可以对任何数据库进行同样的测试&#xff0c;具有可移植性&#xff0c;可跨平台支持Windows&#xff0c;Linux&#xff0c;Mac上使用。 JMeter运行场景不仅可…

大模型之路,从菜鸟到模型大师只需要一步

前言&#xff1a; 在这个数据爆炸的时代&#xff0c;大模型技术正以前所未有的速度发展。从自然语言处理到计算机视觉&#xff0c;从智能推荐到自动驾驶&#xff0c;大模型正逐渐渗透到我们生活的方方面面。那么&#xff0c;如何从菜鸟成长为模型大师呢&#xff1f;本文将为你…

腾讯元宝眼中的我,竟是一个变现20w的AI博主!

文章首发于公众号&#xff1a;X小鹿AI副业 大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 昨天&#xff08;5…

19.Redis之集群

1.集群的基本介绍 集群 这个词.广义的集群,只要你是多个机器,构成了分布式系统, 都可以称为是一个"集群"前面主从结构,哨兵模式,也可以称为是"广义的集群”狭义的集群,redis 提供的集群模式, 这个集群模式之下,主要是要解决,存储空间不足的问题(拓展存储空间) …

5月安全月报 | 钓鱼事件频发,OKLink带你开启“防钓”模式

本月全网安全事件所造成的损失环比上升 27.27%&#xff0c;钓鱼与诈骗事件占比 60% 以上。 安全意识是您保护数字资产的第一道防线&#xff0c;OKLink 提供 40 头部区块链浏览器与一站式查询入口以及地址监控、代币授权查询和地址健康度等工具&#xff0c;为您的资产安全保驾护…

KotlinConf 2024:深入了解Kotlin Multiplatform (KMP)

KotlinConf 2024&#xff1a;深入了解Kotlin Multiplatform (KMP) 在近期的Google I/O大会上&#xff0c;我们推荐了Kotlin Multiplatform (KMP)用于跨移动、网页、服务器和桌面平台共享业务逻辑&#xff0c;并在Google Workspace中采用了KMP。紧接着&#xff0c;KotlinConf 2…

数字水印 | 图像噪声攻击(高斯/椒盐/泊松/斑点)

目录 Noise Attack1 高斯噪声&#xff08;Gaussian Noise&#xff09;2 椒盐噪声&#xff08;Salt and Pepper Noise&#xff09;3 泊松噪声&#xff08;Poisson Noise&#xff09;4 斑点噪声&#xff08;Speckle Noise&#xff09;5 完整代码 参考博客&#xff1a;Python…

ES 生命周期管理

一 .概念 ILM定义了四个生命周期阶段&#xff1a;Hot&#xff1a;正在积极地更新和查询索引。Warm&#xff1a;不再更新索引&#xff0c;但仍在查询。cold&#xff1a;不再更新索引&#xff0c;很少查询。信息仍然需要可搜索&#xff0c;但是如果这些查询速度较慢也可以。Dele…