STM32 通用定时器

一、概述

        STM32内部集成了多个定时/计数器,根据型号不同,STM32系列芯片最多包含8个定时/计数器。其中,TIM6、TIM7为基本定时器,TIM2~TIM5为通用定时器,TIM1、TIM8为高级控制定时器。

1.定时器的类型

  • 基本定时器
  • 通用定时器
  • 高级控制定时器
  • 窗口看门狗定时器
  • 独立看门狗定时器
  • 系统滴答定时器

2.计数模式

  • 向上计数模式:计数器从0计数到自动加载值(ARR),并产生向上溢出事件。

  • 向下计数模式:计数器从自动加载值(ARR)向下计数到0,并产生向下溢出事件。 

  • 中央对齐模式:计数器从0开始计数到自动加载值-1,产生向上溢出事件,然后向下计数到1,产生向下溢出事件,最后再从0开始重新计数。

3.主要功能 

  • 基本定时功能
  •  输出比较
  • 输入捕获
  • 编码器接口模式
  • 单脉冲模式
  • 死区控制和刹车功能

        注:本文将介绍前四种常见的功能。 

4.通用定时器的结构

        STM32通用定时器主要包括1个外部触发引脚(TIMx_ETR),4个输入/输出通道(TIMx_CH1、 TIMx_CH2、TIMx_CH3和TIMx_CH4),1个内部时钟1个触发控制器1个时钟单元(由预分频器PSC、自动重装载寄存器ARR和计数器CNT组成)。如图所示:

5.时钟源

        定时/计数器时钟可由下列时钟源(如上图所示)提供: 

  • 内部时钟(CK_INT)
  • 外部时钟模式1(TIMx_CH1~4)
  • 外部时钟模式2(TIMx_ETR)
  • 内部触发输入(ITR,使用一个定时器作为另一个定时器的预分频器)

        当时钟源来自内部时,可实现定时功能;当时钟源来自外部时,可实现计数功能。

6.功能寄存器

        略。

二、基本定时功能

        下面介绍TIM定时器最基础的功能:基本定时功能。这种功能常用于周期性事件的触发。使用流程和步骤如下:

  1. 选择时钟源
  2. 配置时基单元
  3. 配置NVIC
  4. 编写中断服务函数
void Timer_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟TIM_InternalClockConfig(TIM2);		//选择时钟源为内部时钟,若不调用此函数,TIM2默认也为内部时钟/*配置时基单元*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;			TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位,TIM_TimeBaseInit函数末尾,手动产生了更新事件,//若不清除此标志位,则开启中断后,会立刻进入一次中断,//如果不介意此问题,则不清除此标志位也可。TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//设置NVIC分组/*配置NVIC*/NVIC_InitTypeDef NVIC_InitStructure;						NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//设置抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//设置响应优先级为1NVIC_Init(&NVIC_InitStructure);	TIM_Cmd(TIM2, ENABLE);			                            //使能TIM2,运行TIM2
}void TIM2_IRQHandler(void)                                      //定时器中断函数
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){    //此处编写要周期实现的功能TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

 三、输出比较功能

         当定时器的计数器值(CNT)与捕获比较寄存器(CCR)的值相等时,产生比较事件,并根据配置对输出管脚进行相应的操作,如翻转或置位。其应用场景如下:

  • PWM(脉宽调制)信号的产生:输出占空比可调的PWM信号,用于电机控制、LED调光等。
  • 定时脉冲:在特定时间产生一个脉冲信号,用于精确事件触发。
  • DAC触发:精确触发模拟信号输出。

        下面介绍产生PWM波的使用流程:

  1.  配置GPIO,用于输出PWM,根据引脚定义表配置
  2. 选择时钟源
  3. 配置时基单元
  4. 配置输出比较模式
void PWM_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*配置GPIO*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 //复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);								//受外设控制的引脚,均需要配置为复用模式TIM_InternalClockConfig(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 = 36 - 1;               //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);            /*配置输出比较模式*/ 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值,也可以不定为0,直接定为想要的占空比所需的CCR值TIM_OC3Init(TIM2, &TIM_OCInitStructure);                        TIM_Cmd(TIM2, ENABLE);			//使能TIM2,运行TIM2
}TIM_SetCompare3(TIM2, Compare);		            
//设置CCR的值,设置CCR几的值取决于使用哪个引脚,PA2对应的是CCR3
//该行代码用于改变占空比,一般放在主函数或者中断服务函数

 另外,PWM的三项重要数据的计算方法如下:

  1. 占空比:CCR/(ARR+1)
  2. 分辨率:1/(ARR+1)
  3. 频率:CK_PSC/(PSC+1)/(ARR+1),CK_PSC一般为72MHz

四、输入捕获功能 

        输入捕获模式用于测量外部信号的时间特性,例如周期、频率、脉宽等。它通过将外部输入信号的某个边沿(上升沿或下降沿)捕获并保存计数器的值,从而实现时间测量。 

        下面介绍通过输入捕获功能实现频率测量的步骤:

  1.  配置GPIO,用于接收需要测频率的信号,根据引脚定义表配置
  2. 选择时钟源
  3. 配置时基单元
  4. 配置输入捕获功能
  5. 编写频率计算函数
void IC_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*配置GPIO*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;				    //上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);			TIM_InternalClockConfig(TIM3);		//选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟/*配置时基单元*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;               //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);/*配置输入捕获功能*/TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1TIM_ICInitStructure.TIM_ICFilter = 0xF;							//输入滤波器参数,可以过滤信号抖动TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;		//极性,选择为上升沿触发捕获TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;			//捕获预分频,选择不分频,每次信号都触发捕获TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;	//输入信号交叉,选择直通,不交叉TIM_ICInit(TIM3, &TIM_ICInitStructure);	/*选择触发源及从模式*/TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);					//触发源选择TI1FP1TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);					//从模式选择复位,即TI1产生上升沿时,会触发CNT归零TIM_Cmd(TIM3, ENABLE);			//使能TIM3,运行TIM3
}uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1);		//测周法得到频率fx = fc / N,这里不执行+1的操作也可
}

         频率测量方法有两种,一种是适用于测量高频信号的测频法,一种是适用于测量低频信号的测周法。其原理如下图所示:

 五、编码器模式

        编码器接口模式用于解码旋转编码器的信号。它可以直接连接增量型旋转编码器的A相和B相信号,并解码出编码器的旋转方向和位置。 每个高级定时器和通用定时器都拥有1个编码器接口,两个输入引脚借用了输入捕获的通道1和通道2。

        下面介绍使用编码器模式来测量电机转速的步骤,硬件上将带编码器的电机的编码输出连接到STM32的PA6和PA7,具体如下:

  1. 配置GPIO,用于接收正交编码,根据引脚定义表配置
  2. 配置时基单元
  3. 配置输入捕获模式
  4. 配置编码器模式
  5. 配置另一个定时器,编写速度计算函数
void Encoder_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*配置GPIO*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;           //浮空输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;          //配置PA6和PA7引脚GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							/*配置时基单元*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //使用TIM3/*配置输入捕获模式*/TIM_ICInitTypeDef TIM_ICInitStructure;							TIM_ICStructInit(&TIM_ICInitStructure);																																		TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				TIM_ICInitStructure.TIM_ICFilter = 0x10;							//输入滤波器参数,可以过滤信号抖动TIM_ICInit(TIM3, &TIM_ICInitStructure);	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				TIM_ICInitStructure.TIM_ICFilter = 0x10;							//输入滤波器参数,可以过滤信号抖动TIM_ICInit(TIM3, &TIM_ICInitStructure);							TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);//配置编码器模式以及两个输入通道是否反相TIM_ClearFlag(TIM3, TIM_FLAG_Update);TIM_SetCounter(TIM3, 0);TIM_Cmd(TIM3, ENABLE);			                                //使能TIM3
}//使用二、基本定时功能,在中断服务函数中编写计算速度的代码。
//这里需要另外配置一个定时器,相关代码参考第二点,这里不再赘述。
//先计算电机转一圈,STM32收到的n个编码;这取决于电机本身的参数。
//再每隔T时间输出STM32一共接收到的N个编码;则N/n即这段时间T里电机转过的圈数。
//最后用N/n/T即可求出转速。其中:int n=xxx                     //根据电机参数计算int N=TIM_GetCounter(TIM3);   //STM32接收到的编码数TIM_SetCounter(TIM3, 0);      //拿到T时间内的编码数后,计数清零,重新计数float Speed=N/n/T;            //T为定时周期

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

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

相关文章

微信小程序-npm支持-如何使用npm包

文章目录 1、在内建终端中打开2、npm init -y3、Vant Weapp4、通过 npm 安装5、构建 npm 1、在内建终端中打开 Windows PowerShell 版权所有 (C) Microsoft Corporation。保留所有权利。尝试新的跨平台 PowerShell https://aka.ms/pscore6PS C:\Users\dgq\WeChatProjects\minip…

python泵站设备运行预警信息管理系统

目录 功能介绍具体实现截图技术栈和环境说明python语言解决的思路性能/安全/负载方面核心代码部分展示详细视频演示源码获取方式 功能介绍 用户端 注册登录:用户可以注册账号并登录系统。 西电泵站简介:提供泵站的历史、功能和重要性等详细介绍。 泵站…

余承东直播论道智能驾驶:激光雷达不可或缺,华为ADS 3.0引领安全创新

华为余承东:激光雷达,智能驾驶安全性的关键 9月29日,华为消费者业务集团CEO余承东在一场引人注目的直播中,与知名主持人马东就智能驾驶技术的最新进展进行了深入交流。在这场直播中,余承东针对激光雷达在智能驾驶中的必要性问题,发表了明确且深刻的观点,引发了业界和公众…

在Docker中运行微服务注册中心Eureka

1、Docker简介: 作为开发者,经常遇到一个头大的问题:“在我机器上能运行”。而将SpringCloud微服务运行在Docker容器中,避免了因环境差异带来的兼容性问题,能够有效的解决此类问题。 通过Docker,开发者可…

角色动画——RootMotion全解

1. Unity(2022)的应用 由Animtor组件控制 在Animation Clip下可进行详细设置 ​ 官方文档的介绍(Animation选项卡 - Unity 手册) 上述动画类型在Rag选项卡中设置: Rig 选项卡上的设置定义了 Unity 如何将变形体映射到导入模型中的网格,以便能够将其动画化。 对于人…

Linux驱动开发——LED驱动开发

文章目录 1 概述1.1 说明 2 基础知识2.1 地址映射2.1.1 ioremap函数2.1.2 iounmap函数 2.2 I/O内存访问函数2.2.1 读操作函数2.2.2 写操作函数 3 硬件原理图分析4 RK3568 GPIO驱动原理4.1 引脚复用设置4.2 引脚驱动能力配置4.3 GPIO输入输出设置4.4 GPIO引脚高低电平设置 5 实验…

【GeekBand】C++设计模式笔记5_Observer_观察者模式

1. “组件协作”模式 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。典型模式 Template MethodStrategyObserver / Event 2.…

HarmonyOS/OpenHarmony 自定义弹窗页面级层级控制解决方案

关键词:CuntomDialog自定义弹窗、SubWindow子窗口、页面级、弹窗层级控制、鸿蒙、弹窗展示层级异常 问题存在API版本:API10 - API12(该问题已反馈,期望后续官方能增加页面级控制能力) 在正常的鸿蒙app开发过程中&…

aws(学习笔记第二课) AWS SDK(node js)

aws(学习笔记第二课) 使用AWS SDK(node js) 学习内容: 使用AWS SDK(node js) 1. AWS SDK(node js) AWS支持多种SDK开发(除了AWS CLI,还支持其他的SDK) AndroidPythonNode.js(Javas…

约数个数约数之和

好久没发文章了.......不过粉丝还是一个没少...... 今天来看两道超级恶心的数论题目! No.1 约数个数 No.2 约数之和 先来看第一道:约数个数 题目描述 给定 n 个正整数 ai​,请你输出这些数的乘积的约数个数,答案对 10^97 取模 输入格式 第一行包含…

五种IO模型与阻塞IO

一、前言 在网络中通信的本质其实是网络中的两台主机的进程间进行通信,而进程通信的本质就是IO。 IO分为输入(input)和输出(output)站在进程的角度讲,进程出去数据为输出,外部数据进入进程为输…

YOLOv8 基于NCNN的安卓部署

YOLOv8 NCNN安卓部署 前两节我们依次介绍了基于YOLOv8的剪枝和蒸馏 本节将上一节得到的蒸馏模型导出NCNN,并部署到安卓。 NCNN 导出 YOLOv8项目中提供了NCNN导出的接口,但是这个模型放到ncnn-android-yolov8项目中你会发现更换模型后app会闪退。原因…

[ComfyUI]Flux:太强了!任意扩图神器,小红书极致逼真风格出游打卡写实风

随着人工智能技术的不断发展,图像生成与反推技术已经成为了AI领域的一大热点。今天,我们就来为大家详细介绍一款由ComfyUI团队开发的超强图像反推工具——Flux,以及如何使用它实现任意扩图和极致逼真风格出游打卡写实风。 一、Flux&#xff…

【AI大模型】使用Embedding API

一、使用OpenAI API 目前GPT embedding mode有三种,性能如下所示: 模型每美元页数MTEB得分MIRACL得分text-embedding-3-large9,61554.964.6text-embedding-3-small62,50062.344.0text-embedding-ada-00212,50061.031.4 MTEB得分为embedding model分类…

centos7安装配置nginx

先安装依赖 安装依赖之前最好先执行下update yum update yum install gcc gcc-c pcre pcre-devel zlib zlib-devel openssl openssl-devel -y cd /usr/local/nginx wget http://nginx.org/download/nginx-1.18.0.tar.gz tar -zxvf nginx-1.18.0.tar.gz cd /usr/local/ngi…

双非本 985 硕,上岸快手大模型算法岗!

最近已有不少大厂都在秋招宣讲,也有一些已在 Offer 发放阶段了。 节前,我们邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对新手如何入门算法岗、该如何准备面试攻略、面试常考点、大模型技术趋势、算法项目落地经验分享等热门话题进行…

高校校园交友系统小程序的设计

管理员账户功能包括:系统首页,个人中心,管理员管理,用户管理,基础数据管理,论坛管理,公告信息管理,轮播图信息管理 微信端账号功能包括:系统首页,用户&#…

反调试—1

IsDebuggerPresent() CheckRemoteDebuggerPresent() 其内部实际调用NtQueryInformationProcess() bool _stdcall ThreadCall() {while (true){BOOL pbDebuggerPresent FALSE;CheckRemoteDebuggerPresent(GetCurrentProcess(), &pbDebuggerPresent);if (pbDebuggerPres…

fiddler抓包18-2_导出jmeter、postman脚本(带请求头)

课程大纲 1. Fiddler导出请求为curl脚本 选中请求,“文件” - “导出会话” - “选中的会话” - “cURL Script”。 2. 导入jmeter ① 复制curl脚本。 ② 打开jmeter,“工具” - “import from cURL”,粘贴脚本,勾选“Add cooki…

二分查找一>寻找峰值

1.题目&#xff1a; 2.解析&#xff1a; 暴力遍历代码&#xff1a;O(N),由于该题数据很少所以可以通过 暴力遍历&#xff1a;O(N),由于该题数据很少所以可以通过int index 0;for(int i 1; i < nums.length-1; i) {//某段区域内一直递增&#xff0c;更新就indexif(nums[i]…