STM32的TIM输入捕获和PWMI详解

系列文章目录

STM32单片机系列专栏

C语言术语和结构总结专栏


文章目录

1. IC输入捕获

2. 频率测量

3. 主模式、从模式、触发源选择

4. 输入捕获基本结构

5. PWMI模式

6. 代码示例

6.1 PWM.c

6.2 PWM.h

6.3 IC.c

6.4 IC.h

6.5 完整工程文件


输出比较可以看下面这篇文章:

STM32定时器的OC比较和PWM

1. IC输入捕获

输入捕获(Input Capture,简称IC)是微控制器中定时器功能之一,主要用于精确地捕获外部事件(如信号的边沿)发生的时刻。在STM32中,IC功能通过定时器来实现,可以对外部输入信号的上升沿或下降沿进行时间的捕获,通过读取捕获时定时器的计数器(CNT)的值,从而知道外部事件发生的确切时刻。并且当前CNT的值将被锁存到CCR中。

输入捕获功能有以下功能:

  • 测量两个事件之间的时间间隔。
  • 测量PWM波形的频率、占空比、脉冲间隔,电平持续时间等。
  • 测量外部信号的脉宽。

每个高级定时器和通用定时器都有4个输入捕获通道。可配置为PWMI模式(PWM输入模式),同时测量频率和占空比,也可以配合主从触发模式,实现硬件全自动测量。这两个模式的组合,可以实现全自动检测,不需要中断也不影响主程序,从而减轻CPU的负担。

注意因为输入捕获和输出比较使用的为同一个寄存器,所以输出捕获和输出比较只能使用一个,不能同时使用。

2. 频率测量

测频法(适合高频信号):在闸门时间T内(通常为1s),对上升沿计次,得到N,则频率

fx = N / T  在单位时间内出现的脉冲数量越多,脉冲的频率就越高。

测周法(适合低频信号):两个上升沿内持续的时间(因为周期的倒数就是频率),使用一个已知的标准频率fc的计次时钟来驱动计数器,从第一个上升沿到下一个上升沿,得到N ,则频率

fx = = fc / N   在给定的周期内,脉冲数量保持不变时,周期越长,每个脉冲的宽度就越宽。

中界频率:测频法与测周法误差相等的频率点

fm = √(fc  / T)   这个指标是用来描述在脉冲调制中,信号的中心频率位置。

3. 主模式、从模式、触发源选择

主模式可以将定时器内部的信号映射到TRGO引脚,用于触发其他的外设。

从模式可以接收其他外设或自身外设的信号,用于控制自身定时器的运行,也就是被其他的信号控制。

触发源选择是选择从模式的触发信号源,选择一个指定的信号,得到TRGI,通过TRGI去触发从模式。从模式可以在列表中选择一项操作来自动执行。例如:如果想让TI1FP1信号自动触发CNT清零,触发源选择TI1FP1,从模式选择Reset,实现硬件全自动。

主模式:

  • 复位 - 主输出TRGO不激活。
  • 使能 - 定时器计数器使能时TRGO被激活。
  • 更新 - 每当定时器更新事件发生时,比如计数器溢出时,TRGO被激活。
  • 比较匹配 - 比如当定时器的比较匹配事件发生时,如CCR1匹配时,TRGO被激活。
  • 比较 - OC1REF的比较匹配事件激活TRGO。
  • 比较 - OC4REF的比较匹配事件激活TRGO。

从模式:

  • 关闭从模式,定时器不受外部信号控制。
  • 编码器模式1,使用内部TRGI(定时器内部触发输入)作为时钟源,通常与编码器的输出相连,用于计数编码器的脉冲。
  • 编码器模式2,同上,但使用两个内部触发输入,允许同时检测方向和速度。
  • 编码器模式3,同上,但使用两个内部触发输入,允许同时检测方向和速度,并且可以检测到位置信息。
  • 复位模式,当TRGI发生时,定时器计数器会被复位。
  • 门控模式,TRGI信号作为启动和停止计数的使能信号。
  • 触发模式,定时器仅在TRGI信号发生时更新其寄存器,并开始计数。
  • 外部时钟模式1,使用TRGI作为定时器的时钟源。

4. 输入捕获基本结构

当配置好时基单元后,启动定时器,此时CNT就会在预分频器之后的时钟驱动下,不断自增。预分频器之后的时钟频率。就是驱动CNT的标准频率fc。

下面的GPIO输入方波信号,经过滤波器和边沿检测,选择TI1FP1为上升沿触发,之后输出选择直连的通道,分频器选择不分频。当TI1FP1出现上升沿之后,CNT(最大65535)的当前计数值会进入CCR1中。同时触发源选择。选择TI1FP1为触发信号,从模式选择复位模式,从而清零CNT。

5. PWMI模式

这部分前面和输入捕获一样,但后面使用了两个通道,可以同时测量周期和占空比,TI1FP2为下降沿触发。这样CCR1就是一整个周期的计数值,CCR2是高电平之间的计数值。此时用CCR2除以CCR1 就是占空比。

6. 代码示例

第一步:开始RCC时钟,打开将要使用的TIM外设时钟和GPIO外设时钟。

第二步:GPIO初始化,把GPIO配置为输入模式,一般为上拉输入或浮空输入模式。

第三步:配置时基单元,让CNT计数器在内部时钟的驱动下自增运行,PSC预分频器、CNT计数器和ARR自动重装载,也包括包括时钟源选择。

第四步:配置输入捕获单元,包括滤波器、极性、直连通道/交叉通道、分频器。

第五步:选择从模式的触发源(TI1FP1)

第六步:选择触发后执行的操作,这里执行Reset操作。

第七步:调用TIM_Cmd函数,开启定时器。

下面的代码实现功能为: 通过PWMI得到时钟频率和占空比。

6.1 PWM.c

要使用的库函数文件依然为:stm32f10x_tim.h,拖到最下面,在这里可以找到定时器TIM需要使用到的函数。

#include "stm32f10x.h" 

//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模式1
	TIM_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
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}

//PWM设置PSC
void PWM_SetPrescaler(uint16_t Prescaler)
{
	TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);		//设置PSC的值
}

RCC_APB1PeriphClockCmd

  • TIM2 代表定时器2,它是STM32的一个基础硬件定时器。在STM32的某些系列中,TIM2连接到的是APB1总线。
  • ENABLE 是一个宏定义,用来开启某项功能,这里用来开启TIM2的时钟。如果传递 DISABLE 则会关闭外设的时钟。
  • 简单来说,RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 这行代码的作用是开启连接到APB1总线的定时器2(TIM2)的时钟。只有开启了时钟,程序中关于TIM2的其他功能(如计时、计数、PWM发生等)才能正常工作。

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  • GPIO的初始化中,选择AF_PP复用推挽输出,因为对于普通的开漏推挽输出,引脚的控制权是来自于输出数据寄存器的,如果想用定时器来控制引脚,就需要使用复用开漏/推挽输出模式。

 

6.2 PWM.h

接着是PWM.h文件,这部分引用声明一下即可

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
void PWM_SetPrescaler(uint16_t Prescaler);

#endif

6.3 IC.c

在这段代码中,我们设置了一个STM32的定时器TIM3以输入捕获(IC)模式运行。代码的主要目的是初始化TIM3以捕获来自外部信号(从PWM波)的频率和占空比。

#include "stm32f10x.h"

//输入捕获初始化
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);							//将PA6引脚初始化为上拉输入
	
	//配置时钟源
	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_TimeBaseInit,配置TIM3的时基单元
	
	//PWMI模式初始化
	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
	TIM_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_PWMIConfig(TIM3, &TIM_ICInitStructure);						//将结构体变量交给TIM_PWMIConfig,配置TIM3的输入捕获通道
																	//此函数同时会把另一个通道配置为相反的配置,实现PWMI模式

	//选择触发源及从模式
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);					//触发源选择TI1FP1
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);					//从模式选择复位
																	//即TI1产生上升沿时,会触发CNT归零
	
	//TIM使能
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
}

//获取输入捕获的频率
uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);		//测周法得到频率fx = fc / N,这里不执行+1的操作也可以
}

//获取输入捕获的占空比
uint32_t IC_GetDuty(void)
{
	return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);	//占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可以
}

6.4 IC.h

同样这部分引用声明一下即可

#ifndef __IC_H
#define __IC_H

void IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);

#endif

6.5 完整工程文件

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ORAN C平面优化

使用section扩展6的C平面优化 在时域和频域中,都可以使用section扩展6进行非连续PRB分配。Section扩展6有两个位掩码:symbolMask和rbgMask。使用symbolMask可以选择一个slot内任意的symbol子集。使用rbgMask可以选择startPrbc和(startPrbc …

Android版本依赖Version catalog

曾经我们使用config.gradle文件进行版本依赖配置,然后在project的build.gradle.kts中使用如下方式引入: apply(from "./config.gradle") 缺点:在project的module中引用无任何提示,无法跳转到指定引用 一、创建versio…

Go-变量

可以理解为一个昵称 以后这个昵称就代指这些信息 var sg string "czy" 声明赋值 package mainimport "fmt"func main() {var sg string "陈政洋"fmt.Println(sg)var age int 73fmt.Println(age)var flag bool truefmt.Println(flag) } …

服务网关GateWay原理

文章目录 自动装配核心类GatewayAutoConfigurationDispatcherHandler请求处理阶段apply方法httpHandler#handle方法WebHandler#handle方法DispatchHanlder#handle方法第一步 getHandler获取请求映射第二步 invokeHandler 请求适配第三步 handleResult请求处理总结 上一篇博文我…

【刷题篇】回溯算法floodfill(七)

文章目录 1、太平洋大西洋水流问题2、扫雷游戏3、衣橱整理 1、太平洋大西洋水流问题 有一个 m n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。 这个岛被分割成一个由若干方形…

Python 全栈体系【四阶】(三十九)

第五章 深度学习 八、目标检测 3. 目标检测模型 3.2 YOLO 系列 3.2.4 YOLOv4(2020 年 4 月) YOLOv4 将最近几年 CV 界大量的研究成果集中在一套模型中,从检测速度、精度、定位准确率上有了明显改善(相对于 YOLOv3&#xff0c…

基于Springboot的家具网站

基于SpringbootVue的家具网站设计与实现 开发语言:Java数据库:MySQL技术:SpringbootMybatis工具:IDEA、Maven、Navicat 系统展示 用户登录 首页 商家 家具信息 家居资讯 后台管理 后台首页 用户管理 商家管理 家具类型管理 家具…

ASV1000视频监控平台:通过SDK接入海康网络摄像机IPC

目录 一、为何要通过SDK接入海康网络摄像机 (一)海康网络摄像机的SDK的功能 1、视频采集和显示 2、视频存储 3、视频回放 4、报警事件处理 5、PTZ控制 6、自定义设置 7、扩展功能 (二)通过SDK接入的好处(相对…

JavaEE初阶-多线程易忘点总结

文章目录 1.PCBPID文件描述符表内存指针状态上下文优先级记账信息tgid 2.线程与进程的区别3.sleep和interrupt方法的关系变量终止线程interrupt方法终止线程 4.线程状态5.出现线程不安全的原因线程在系统中是随即调度,抢占式执行的。多个线程修改同一个变量线程针对…

Adobe 更新 Firefly Image 3 图像生成模型

一个工具或者模型,对于初次使用的人来说,易用性和超出预期的效果很能吸引使用者,suno和mj在这方面我感觉确实不错,第一次使用感觉很惊艳。 Adobe 更新 Firefly Image 3 图像生成模型,我用了mj的提示词,最后…

列转行(spark 与presto语法)

一、Presto 语法 原始数据: 期望数据: 代码: SELECT info, value FROM ( select 张三 as name,18 as age,男 as gender,清华 as schoolunion allselect 李四 as name,18 as age,男 as gender,清华 as school ) as a CROSS JOIN UNNEST(…

关于YOLO8学习(六)安卓部署ncnn模型--图片检测

前文 关于YOLO8学习(一)环境搭建,官方检测模型部署到手机 关于YOLO8学习(二)数据集收集,处理 关于YOLO8学习(三)训练自定义的数据集 关于YOLO8学习(四)模型转换为ncnn 关于YOLO8学习(五)安卓部署ncnn模型–视频检测 简介 前文第五章,讲述了部署自定义模型后,进…

Java--方法的使用

1.1什么是方法 方法顾名思义就是解决问题的办法,在程序员写代码的时候,会遇到很多逻辑结构一样,解决相同问题时,每次都写一样的代码,这会使代码看起来比较绒余,代码量也比较多,为了解决这个问题…

分拣机器人也卷的飞起来了

导语 大家好,我是智能仓储物流技术研习社的社长,老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 智能制造-话题精读 1、西门子、ABB、汇川:2024中国工业数字化自动化50强 2、完整拆解:智能…

foobar2000 for Mac:卓越音乐播放器

当您在寻找一款音质卓越、功能丰富的音频播放器时,foobar2000 for Mac无疑是您的首选。它拥有简洁明了的界面设计,易于上手,同时支持多种音频格式,让您无需担心兼容性问题。 foobar2000 for Mac v2.6.4免激活版下载 foobar2000 fo…

匹配网络(Matching Networks)和原型网络(Prototypical Networks):区别详解

匹配网络(Matching Networks)和原型网络(Prototypical Networks) 匹配网络与原型网络:区别详解匹配网络(Matching Networks)核心特点:应用场景: 原型网络(Pro…

威尔科克森秩和检验 (Wilcoxon rank-sum test)-- 代码实现

⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计3077字,阅读大概需要3分钟 🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号&#xf…

设计模式之业务代表模式

在编程江湖的风雨中漂泊多年,每当我遇到那些错综复杂的业务逻辑和系统交互,总有一个模式像一位忠诚的骑士,默默守护着我的代码城堡,那就是——业务代表模式(Business Delegate Pattern)。它不是最耀眼的明星…

一键实现在VS Code中绘制流程图

VS Code是一款常用的IDE,受到许多用户的欢迎和喜爱。而其较为出众的一点,就是较好的可拓展性,即丰富的插件应用,这些应用可以极大地提高生产效率,并优化日常使用。 流程图是一种直观的图示方法,可以用简明…

家庭用水安全新举措:保障自来水管和储水设施卫生

随着公众对家庭用水安全意识的提高,如何确保自来水管和楼顶储水罐的安全性和卫生已成为家庭生活中的重要议题。近期,专家针对此问题提出了一系列实用的注意事项和建议。 注意事项: 定期检查:专家强调,家庭应每季度至…
最新文章