当前位置: 首页 > 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;…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...