当前位置: 首页 > news >正文

【STM32F103】TIM定时器PWM

定时器分类

STM32F1中除了互联型产品(STM32F103C8T6为64KB Flash 中容量产品),其余有8个定时器。

可以8个定时器分为高级,通用,基本三种。

高级定时器有两个,分别是TIM1和TIM8。

通用定时器有四个,是TIMx(x=2~4)

基本定时器有两个,是TIMx(x=6~7)

功能上高级>通用>基本

不过高级定时器一般也用不着,如果只是普通的计时的话基本定时器也就够用了,但是基本定时器没有输出比较,没法实现PWM(脉冲宽度调制),因此我们主要使用的是通用定时器,并且STM32F103中通用定时器的资源也是最多的。

下图截自《ARM Cortex-M3嵌入式原理及应用(基于STM32F103微控制器)》的第150页。

通用定时器

 下图截自《STM32F10xxx参考手册(中文)》第253页

不太严谨地介绍一下定时器的工作流程。时钟源每传来n(n=预分频器的值)次脉冲,都会使得计数器工作一次。如果选择的是向上计数模式,那么计数器每工作一次都会使得计数器的值+1,直到值等于了自动重装载寄存器的值,那么触发一次中断,并且计数器清零。

如果选择的是向下计数模式,那么计数器每工作一次都会使得计数器的值-1,直到值等于0,那么触发一次中断,并且计数器的值变为自动重装载寄存器的值。

如果选择向上向下计数模式,那么计数器工作一次会使得计数器的值+1或者-1,计数器的值不会被重置,会一直在0和自动重装载寄存器的值之间上下跳动。

一般情况下这三种工作模式对于计数的效果都是一样的,但是当我们需要利用到计数器里的值的时候就有差别了(例如PWM),通常我们使用的是向上计数模式,这也比较符合我们的直觉。

 上述的介绍中提到的是以下三个寄存器。

可以看出它们都是只有16位,也就是说可以设置的最大数值为2^16-1(65535)。

并且从工作流程中也可以得知,定时器溢出的频率公式为

时钟源频率/(自动重装载寄存器的值+1)/(预分频器的值+1)=CK_INT/(ARR+1)/(PSC+1)

PWM脉冲宽度调制

STM32F103中每个通用定时器都可以输出4路PWM,而每个高级定时器都可以输出7路PWM,所以理论上,STM32最多是可以同时产生30路PWM。

PWM简单来说就是一段有高电平也有低电平的脉冲信号。

我们一般点亮一个LED灯,就是把LED灯的短脚接地,然后通过GPIO口从LED灯的长脚传入高电平,我们假设此刻LED的亮度为100。如果我们改用PWM来代替原本的高电平,并且PWM传入的脉冲信号中高低电平各占50%,那么此刻LED的亮度就为50%了,因为人眼大概只能接受每秒25帧左右的图像,因此只要PWM够快,那么我们就看不出LED实际上是亮灭亮灭的,由于人眼的残留影像,我们看到的只是LED灯变得暗了些。

之所以把PWM和定时器放在一起,是因为定时器的硬件中就含有捕获比较寄存器。

我们可以给这个寄存器设置一个阈值,当定时器的计数器的值小于这个阈值的时候我们就输出高电平,反之输出低电平(具体看选择的PWM输出模式)。

综上我们可以得知,PWM输出的频率等于定时器的溢出中断频率。

固件库函数

定时器相关的函数还是非常多的,接下来就以计数1ms为目的来说明相关函数。

首先需要打开相关定时器的外设时钟,不过不属于定时器库函数里的,就不介绍。

下一步选择时钟源,默认是使用内部时钟源(72MHz),所以也可以不指定。

然后初始化时基单元(配置自动重装载寄存器,预分频器,时钟分频,计数模式)

接着是中断使能以及配置NVCI相关的中断优先级

最后是使能计数器就可以开始计数了。

TIM_InternalClockConfig

上面三个函数是常用的用来指定时钟源的函数。

第一个也是默认的,使用的是内部时钟作为时钟源。

第二个可以将其他定时器的溢出信号作为时钟源,也就是两个定时器联动,这样可以将最大的计时数平方一次,也就是可以记更久的时间,不过我们也是可以使用软件来完成这种效果的。

第三个可以将时钟源接到外部的时钟。

TIM_TimeBaseInit

初始化时基单元,参数一指定定时器资源,参数二传入一个TIM_TimeBaseInitTyepDef类型的结构体变量用于初始化配置。

TIM_Prescale:预分频器的值,0~65535。

TIM_CounteMode:计数器模式,一般使用向上计数TIM_CounterMode_Up

TIM_Period:自动重装载计数器的值,0~65535。

TIM_ClockDivision:时钟分频,TIM_CKD_DIV1

TIM_RepetitionCounter:重复计数器的值,只有高级定时器才用的到,基本定时器和通用定时器随便给个0就行。

TIM_ITConfig

中断使能,参数一选择定时器资源,参数二选择中断源,参数三给个ENABLE。

中断源一般就指定第一个TIM_IT_Update

这样每计数一轮都会触发一次中断。

TIM_Cmd

使能计数器。

使能之后计数器就开始运作了,每次记满一轮之后就会进入一次中断,我们可以从“startup_stm32f10x_md.s”中找到对应的中断函数。

由于可进入这个中断函数的中断源有多个(参考上面中断使能的参数表),因为我们需要查询中断标志位是否是我们所规定的TIM_IT_Update触发的,是的话我们还需要手动把标志位清除(其他中断源也是一样)。

TIM_GetITStatus

查询中断标志位,参数二给的一样的TIM_IT_Update

TIM_ClearITPendingBit

清除中断标志位,参数二给的一样的TIM_IT_Update

上面的函数就是用来计数用的,接下来就是如何输出PWM的了。

把上面计数的流程走一遍,然后把中断相关的都删掉,再加上配置输出比较单元以及初始化GPIO口的函数即可。

TIM_OC1Init

配置通道1的输出比较单元。这里需要注意的是不同定时器资源的不同通道对应的GPIO输出口是不一样的,TIM2的通道1对应的是GPIOA的0号引脚,具体可以查询引脚定义表。并且需要配置为复用推挽输出模式GPIO_Mode_AF_PP

参数一指定定时器资源,参数二传入TIM_OCInitTypeDef类型的参数。

一共有八个成员变量,但是我们只需要用到我圈起来的4个,其余为高级定时器使用的。

TIM_OCMode:设置输出比较的模式,一般我们选择TIM_OCMode_PWM1,在这个模式下,当计数器的值小于阈值时输出设置的极性(下面会设置),反之输出相反的极性。

TIM_OCPolarity:输出比较的极性,这个根据需求来设置,设置为高电平的参数为TIM_OCPolarity_High

TIM_OutputState:设置输出使能,TIM_OutputState_Enable

TIM_Pulse:设置阈值,0~65535。因此我们定时器的自动重装载寄存器的值最好不要超过这个阈值,并且由于容易计算PWM的占空比,一般我会把自动重装载寄存器的值设为10的倍数。

以上就足够我们输出PWM了,如果我们需要实现呼吸灯的效果,那么还需要动态地调整PWM的阈值。

TIM_SetCompare1

设置通道1的输出比较阈值。

参数一指定定时器资源,参数二重新设置阈值大小。 

通用定时器计数1ms代码

#include "stm32f10x.h"                  // Device header
#include "OLED.h"uint32_t count=0;int main(void){OLED_Init();RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     //打开TIM2的外设时钟TIM_InternalClockConfig(TIM2);                          //选择内部时钟(72MHz)作为时钟源TIM_TimeBaseInitTypeDef itd;itd.TIM_ClockDivision=TIM_CKD_DIV1;                     //时钟1分频itd.TIM_CounterMode=TIM_CounterMode_Up;                 //向上计数模式itd.TIM_Period=1000-1;                                  //设置自动重装器的值itd.TIM_Prescaler=72-1;                                 //设置预分频器的值//TIM2的计数器溢出频率(每秒中断次数)为//(72MHz/1(1分频)/(1000-1+1)(自动重装器的值+1)/(72-1+1)(预分频器的值+1))=1000(ms级,即1ms溢出一次)itd.TIM_RepetitionCounter=0;                            //重复计数器的值,但是仅高级定时器有效TIM_TimeBaseInit(TIM2,&itd);TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                //开启定时器中断,TIM为中断源//配置中断优先级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         //抢占优先级和响应优先级各占两位NVIC_InitTypeDef itd1;itd1.NVIC_IRQChannel=TIM2_IRQn;                         //指定TIM2的中断通道itd1.NVIC_IRQChannelCmd=ENABLE;itd1.NVIC_IRQChannelPreemptionPriority=2;               //抢占优先级为2itd1.NVIC_IRQChannelSubPriority=2;                      //响应优先级为2NVIC_Init(&itd1);TIM_Cmd(TIM2,ENABLE);                                   //使能定时器while(1){OLED_ShowNum(2,1,count,6);}
}void TIM2_IRQHandler(void){if(TIM_GetITStatus(TIM2,TIM_FLAG_Update)){          //判断是否是TIM中断源引发的中断++count;    TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);    //清除标志位}
}

效果

 通用定时器使用PWM实现LED呼吸灯

#include "stm32f10x.h"                  // Device header
#include "Delay.h"int main(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     //打开TIM2的外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef gitd;gitd.GPIO_Mode=GPIO_Mode_AF_PP;                         //配置为复用推挽输出gitd.GPIO_Pin=GPIO_Pin_0;gitd.GPIO_Speed=GPIO_Speed_2MHz;GPIO_Init(GPIOA,&gitd);TIM_InternalClockConfig(TIM2);                          //选择内部时钟(72MHz)作为时钟源TIM_TimeBaseInitTypeDef itd;itd.TIM_ClockDivision=TIM_CKD_DIV1;                     //时钟1分频itd.TIM_CounterMode=TIM_CounterMode_Up;                 //向上计数模式itd.TIM_Period=100-1;                                   //设置自动重装器的值itd.TIM_Prescaler=72-1;                                 //设置预分频器的值itd.TIM_RepetitionCounter=0;                            //重复计数器的值,但是仅高级定时器有效TIM_TimeBaseInit(TIM2,&itd);TIM_OCInitTypeDef itd1;itd1.TIM_OCMode = TIM_OCMode_PWM1;                      //比较输出模式为PWM1itd1.TIM_OCPolarity = TIM_OCPolarity_High;              //输出极性为高电平itd1.TIM_OutputState=TIM_OutputState_Enable;            //使能itd1.TIM_Pulse=0;                                       //初始化输出比较的阈值          TIM_OC1Init(TIM2,&itd1);TIM_Cmd(TIM2,ENABLE);                                   //使能定时器while(1){for(int i=0;i<=100;++i){ TIM_SetCompare1(TIM2,i);Delay_ms(10);}for(int i=100;i>=0;--i){TIM_SetCompare1(TIM2,i);Delay_ms(10);}}
}

效果

参考

《STM32F10xxx参考手册(中文)》

《STM32F103xx固件函数库用户手册》

b站江科大自化协

《STM32库开发实战指南(基于STM32F103)》

《ARM Cortex-M3嵌入式原理及应用(基于STM32F103微控制器)》

相关文章:

【STM32F103】TIM定时器PWM

定时器分类 STM32F1中除了互联型产品&#xff08;STM32F103C8T6为64KB Flash 中容量产品&#xff09;&#xff0c;其余有8个定时器。 可以8个定时器分为高级&#xff0c;通用&#xff0c;基本三种。 高级定时器有两个&#xff0c;分别是TIM1和TIM8。 通用定时器有四个&…...

图论及其应用的一些论断---选择题

在任意一个网络N=(X,Y,I,A,c)中,最大流的值等于最小割的容量。在任意6个人的集会上,要么有3个人互相认识,要么有3个人互不认识。若G为无向简单图,则图G的边数ε,点数v之间有: ε < = ( v 2 ) ε<=\binom{v}{2} ε<=...

腾讯云轻量应用服务器镜像操作系统如何选择?

腾讯云轻量应用服务器镜像怎么选择&#xff1f;镜像是指轻量服务器的操作系统&#xff0c;可以选择宝塔Linux面板8.0.4腾讯云专享版&#xff0c;如果需要Win系统建议选择Windows Server 2012 R2 中文版&#xff0c;腾讯云服务器网txyfwq.com分享腾讯云轻量应用服务器镜像操作系…...

鸿蒙原生应用/元服务开发-发布基础类型通知类型与接口

基础类型通知主要应用于发送短信息、提示信息、广告推送等&#xff0c;支持普通文本类型、长文本类型、多行文本类型和图片类型。 表 基础类型通知中的内容分类 目前系统仅通知栏订阅了通知&#xff0c;将通知显示在通知栏里。基础类型通知呈现效果示意图如下所示。 图1基础类…...

Apisix常见问题

1.通过接口操作路由时X-API-KEY cd /usr/local/apisix/conf vim config-default.yaml注释掉这一部分 #allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow# - 0.0.0.0/24 # If we dont set any IP list, then a…...

Docker 安装Mysql

目录 Docker Mysql安装 ✨安装和配置mysql ✨远程连接mysql远程连接 MySQL 是世界上最流行的开源数据库。根据 DB-Engines的调查数据&#xff0c;MySQL 是第二受欢迎的数据库&#xff0c;仅次于 Oracle 数据库。MySQL在过去由于性能高、成本低、可靠性好&#xff0c;已经成…...

Pillow图像处理(PIL.Image类的详细使用)

文章目录 Opencv、Matplotlib(plt)、Pillow(PIL)、Pytorch读取数据的通道顺序Python图像处理库&#xff08;PIL、Pillow、Scikit-image、Opencv&#xff09;Pillow 官方文档&#xff08;超详细&#xff0c;超推荐&#xff09;一、PIL库与Pillow库的区别二、Pillow库&#xff08…...

嵌入式开发——ADC开发

学习目标 了解ADC开发流程掌握采样方式能够使用ADC进行芯片内部通道进行采样能够使用ADC对外部电路进行采样学习内容 GD32F4的ADC 特点: 16个外部模拟输入通道;1个内部温度传感通道(VSENSE);1个内部参考电压输入通道(VREFINT);1个外部监测电池VBAT供电引脚输入通道。ADC开…...

FreeSWITCH t38测试

主叫 192.168.100.205 被叫 192.168.100.121 主叫侧发送multipage.tif 被叫侧接收传真&#xff0c;保存为recv.tif 主叫侧: originate [fax_enable_t381][fax_verbose1][fax_disable_v170][fax_ident77777777][fax_enable_t38_request1]sofia/internal/1234192.168.100.121:…...

跑腿配送系统技术探析

概述 跑腿配送系统是一种基于现代科技的服务平台&#xff0c;通过智能化的技术手段&#xff0c;实现用户需求的快速响应和高效配送。本文将探讨该系统的核心技术原理&#xff0c;以及在实际开发中的一些代码示例。 技术原理 1. 用户请求与任务分配 跑腿配送系统的第一步是…...

【数据不完整?用EM算法填补缺失】期望值最大化 EM 算法:睹始知终

期望值最大化算法 EM&#xff1a;睹始知终 算法思想算法推导算法流程E步骤&#xff1a;期望M步骤&#xff1a;最大化陷入局部最优的原因 算法应用高斯混合模型&#xff08;Gaussian Mixture Model, GMM&#xff09;问题描述输入输出Python代码实现 算法思想 期望值最大化方法&a…...

PMP证书可以挂靠吗?

PMP证书不是国内的证书&#xff0c;挂靠不了呀&#xff0c;想挂靠&#xff0c;可以考软考/一建等&#xff0c;里面也有项目管理相关的证书。 PMP证书虽然不能挂靠&#xff0c;但是用处还是很大的&#xff0c;例如提升个人能力、薪资待遇&#xff0c;还有持证可享一些城市的福利…...

HTML语义化的理解

HTML语义化是指在编写HTML代码时&#xff0c;合理地选择适当的标签和属性来描述页面的结构和内容&#xff0c;使得代码更具有可读性、可维护性和可访问性。 可读性&#xff1a;通过使用语义化的标签&#xff0c;可以清晰地表达页面的结构和内容&#xff0c;使得代码更易于阅读和…...

(Java企业 / 公司项目)注册,配置中心Nacos的怎么使用?(含相关面试题)(一)

在企业项目中使用Nacos实现的功能操作&#xff0c;以及如何在自己的环境中搭建Nacos环境&#xff0c;包含demo 一. 官网介绍&#xff1a;home (nacos.io) 文档地址&#xff1a;Nacos 快速开始 二. 准备Nacos环境 在公司里面很多的服务以及环境都是自己搭建的所以我在这里就从…...

计算机网络---知识点

ARPANET----NFSNET—ANSNET—Internet发展及协议 移动互联网 物联网 无线自组网、无线传感器网络、无线个域网 ISO/OSI网络体系结构 TCP/IP网络体系结构 对等通信、PDU 电路交换、报文交换、分组报文交换 虚电路、数据报 信道复用技术 网络性能的主要指标&#xff08…...

力扣42. 接雨水

双指针法 思路&#xff1a; 将数组前后设置为 left、right 指针&#xff0c;相互靠近&#xff1b;在逼近的过程中记录两端最大的值 leftMax、rightMax&#xff0c;作为容器的左右边界&#xff1b;更新指针规则&#xff1a; 如果数组左边的值比右边的小&#xff0c;则更新 left…...

SpringSecurity-2.7中跨域问题

SpringSecurity-2.7中跨域问题 访问测试 起因 写这篇的起因是会了解到 SSM(CrosOrigin)解决跨域,但是会在加入SpringSecurity配置后,这个跨域解决方案就失效了,而/login这个请求上是无法添加这个注解或者通过配置(WebMvcConfig)去解决跨域,所以只能使用SpringSecurity提供的.c…...

Java解决字典序最小回文串

Java解决字典序最小回文串 01 题目 给你一个由 小写英文字母 组成的字符串 s &#xff0c;你可以对其执行一些操作。在一步操作中&#xff0c;你可以用其他小写英文字母 替换 s 中的一个字符。 请你执行 尽可能少的操作 &#xff0c;使 s 变成一个 回文串 。如果执行 最少 操…...

【力扣100】207.课程表

添加链接描述 class Solution:def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:# 思路是计算每一个课的入度&#xff0c;然后使用队列进行入度为0的元素的进出# 数组&#xff1a;下标是课程号&#xff0c;array[下标]是这个课程的入度# 哈希…...

2024年生成式AI支出将翻倍,到2027年将超1500亿美元

据国际数据公司&#xff08;IDC&#xff09;的预测&#xff0c;2023年全球企业在生成式人工智能(GenAI)解决方案上的投资已达194亿美元&#xff0c;预计在2024年将翻番。该预测还指出&#xff0c;包括GenAI软件、相关硬件和服务在内的支出将在2027年达到1511亿美元&#xff0c;…...

COMSOL中固态锂离子电池的电-热-力耦合仿真:考虑扩散诱导应力、热应力及外部挤压应力的影响

COMSOL 固态锂离子电池仿真 固态锂离子电池电-热-力耦合仿真&#xff0c;考虑了扩散诱导应力&#xff0c;热应力以及外部挤压应力。固态电池鼓包变形的时候&#xff0c;工程师老张盯着屏幕上的应力云图直挠头。这玩意儿明明充满电就膨胀&#xff0c;放完电又缩回去&#xff0c;…...

Fast-GitHub:突破网络瓶颈的开发效率工具解决方案

Fast-GitHub&#xff1a;突破网络瓶颈的开发效率工具解决方案 【免费下载链接】Fast-GitHub 国内Github下载很慢&#xff0c;用上了这个插件后&#xff0c;下载速度嗖嗖嗖的~&#xff01; 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 1 痛点直击&#xff…...

工业相机+Python视觉系统崩溃频发?(产线停机损失超¥8600/小时的5个隐藏代码陷阱)

第一章&#xff1a;工业相机视觉系统崩溃的根源诊断工业相机视觉系统在产线部署中一旦突发崩溃&#xff0c;往往表现为图像丢失、帧率归零、设备离线或软件进程异常终止。此类故障表面随机&#xff0c;实则多由底层软硬件协同失配引发&#xff0c;需从驱动层、通信协议、资源调…...

基于MATLAB的数字图像处理系统:预处理、特征提取与语义分割全流程实现

数字图像处理系统&#xff08;基于matlab&#xff09; 此系统包括预处理&#xff0c;特征提取&#xff0c;语义分割 使用机器学习算法knn和svm 预处理包括线性灰度级变化&#xff0c;指数灰度级变化&#xff0c;直方图均衡化&#xff0c;高斯滤波&#xff0c;中值滤波&#xff…...

Debugging torch.distributed.DistBackendError: NCCL Communicator Setup and ncclUniqueId Retrieval Iss

1. 理解NCCL通信错误的核心问题 当你看到torch.distributed.DistBackendError: [2] is setting up NCCL communicator and retrieving ncclUniqueId这个错误时&#xff0c;本质上是在说GPU之间的"对讲机"无法正常建立连接。想象一下你正在组织一场多房间的线上会议&…...

别再死记硬背了!用HuggingFace Diffusers库5分钟搞懂Stable Diffusion的VAE、U-Net和CLIP怎么协同工作

5分钟透视Stable Diffusion核心组件&#xff1a;用HuggingFace Diffusers实战VAE/U-Net/CLIP协同机制 当你在HuggingFace Diffusers库中第一次调用StableDiffusionPipeline时&#xff0c;是否好奇过那段简短的文本提示如何变成精美图像&#xff1f;这背后是VAE、U-Net和CLIP三…...

Mermaid在线编辑器:技术图表制作的高效解决方案

Mermaid在线编辑器&#xff1a;技术图表制作的高效解决方案 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-live-editor …...

零基础入门esp32开发:用快马平台生成第一个led控制程序详解

最近在学ESP32开发&#xff0c;发现对于新手来说&#xff0c;从零开始写代码还是挺有挑战的。不过我发现了一个超好用的工具——InsCode(快马)平台&#xff0c;它可以根据你的需求直接生成可运行的代码&#xff0c;特别适合像我这样的初学者。 项目需求分析 我想实现一个简单的…...

避开Codesys电子凸轮Cam表设置的3个常见坑:SMC_CAMXYVA结构体赋值与MC_CAM_REF实例化详解

Codesys电子凸轮Cam表实战避坑指南&#xff1a;从结构体赋值到功能块调优 在工业自动化领域&#xff0c;电子凸轮技术正在逐步取代传统的机械凸轮系统。作为Codesys平台下的核心运动控制功能&#xff0c;Cam表的正确配置直接关系到设备运行的精度和稳定性。本文将深入剖析手动编…...

ArduPilot电机控制逻辑与PWM输出机制剖析

1. ArduPilot电机控制基础概念 当你第一次接触无人机飞控时&#xff0c;最让人困惑的莫过于电机控制逻辑了。想象一下&#xff0c;你手里拿着遥控器&#xff0c;轻轻推动摇杆&#xff0c;无人机就能平稳地上升、下降或者转向。这背后到底发生了什么&#xff1f;让我用最直白的…...