STM32输入捕获相位差测量技术详解(基于TIM1复位模式)

本文将深入解析基于STM32定时器输入捕获功能的方波相位差测量技术,通过复位模式实现高精度相位检测。以下是完整的代码实现与详细原理分析。

一、相位差测量原理

相位差测量基于两个同频方波信号下降沿时间差计算。核心原理:

  1. 复位模式​:将TIM1配置为从模式复位(TIM_SlaveMode_Reset),以参考信号下降沿复位计数器
  2. 双通道捕获​:通道1(PA8)捕获周期值,通道2(PA9)捕获相位时间差
  3. 相位计算​:根据公式 相位差 = (Δt / T) × 360° 转换时间差为角度值

关键优势:​避免计数器溢出处理,简化中断逻辑

二、代码解析与配置细节

1. GPIO与时钟初始化
// 使能TIM1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE);// 配置PA8/PA9为浮空输入
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

关键点​:

  • 浮空输入模式减少外部干扰
  • 50MHz高速响应信号边沿
2. 定时器时基配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = psc;     // 预分频值
TIM_TimeBaseStructure.TIM_Period = arr;         // 自动重装载值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

参数计算​:

  • 定时器频率 = 72MHz / (psc + 1)
  • 最大测量时间 = (arr + 1) × 定时周期
3. 输入捕获通道配置
TIM_ICInitTypeDef TIM1_ICInitStructure;
// 通道1配置(参考信号)
TIM1_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8; // 8分频降中断频率
TIM1_ICInitStructure.TIM_ICFilter = 0x0;                // 无滤波
TIM_ICInit(TIM1, &TIM1_ICInitStructure);// 通道2配置(相位信号,同通道1)
TIM1_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM1, &TIM1_ICInitStructure);

设计要点​:

  • DIV8分频减少高频信号中断负载
  • 双通道相同触发边沿确保测量一致性
4. 复位模式关键配置
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);    // 选择TI1为触发源
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset); // 复位模式

工作原理​:
PA8下降沿 → 复位TIM1计数器 → PA9下降沿触发捕获 → CCR2值即为相位时间差

5. 中断配置与使能
// 使能捕获中断
TIM_ITConfig(TIM1, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);// 配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

三、中断处理与相位计算

1. 中断服务程序
volatile uint32_t Cycle = 0; // 信号周期
volatile uint32_t Phase = 0; // 相位差计数值void TIM1_CC_IRQHandler(void){if(TIM_GetITStatus(TIM1, TIM_IT_CC1) == SET) {Cycle = TIM_GetCapture1(TIM1); // 获取周期值TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);}else if(TIM_GetITStatus(TIM1, TIM_IT_CC2) == SET) {Phase = TIM_GetCapture2(TIM1); // 获取相位差值TIM_ClearITPendingBit(TIM1, TIM_IT_CC2);}
}
2. 相位差智能计算
float getPhase(void) {if(Phase < (Cycle >> 1)) { // 相位差在负半周期return -((float)Phase / Cycle) * 360.0f; } else { // 相位差在正半周期return ((float)(Cycle - Phase) / Cycle) * 360.0f;}
}

算法创新点​:

  • 分段处理​:区分[-180°, 0°]和[0°, 180°]区间
  • 动态补偿​:对超过半周期的相位差自动转换
  • 浮点优化​:提高角度分辨率

四、性能优化与注意事项

  1. 抗干扰设计

    • 增加输入滤波:TIM_ICFilter值设为0x4~0xF
    • 施密特触发器:启用GPIO内部上拉
  2. 精度提升策略

    // 示例:72MHz时钟下配置
    #define psc 71   // 1MHz计数频率(72MHz/72)
    #define arr 9999 // 10ms最大周期(1MHz×0.01s)
    • 测量误差:​< 0.036°​(10kHz信号)
  3. 中断优化技巧

    • 分频器ICPSC动态调整
    • DMA传输捕获值(减少CPU干预)

实测性能:在STM32F103C8T6上可稳定测量0.1°相位差​(10kHz方波)

五、完整源码实现

void TIM1_CH1_Cap_Init(u32 arr,u16 psc)
{NVIC_InitTypeDef NVIC_InitStructure;//TIM1时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE); //使能GPIOA时钟		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); 	GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin 																= GPIO_Pin_8;GPIO_InitStructure.GPIO_Mode 																= GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed 																= GPIO_Speed_50MHz;GPIO_Init(GPIOA , &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin 																= GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode 																= GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed 																= GPIO_Speed_50MHz;GPIO_Init(GPIOA , &GPIO_InitStructure);TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//定时器分频TIM_TimeBaseStructure.TIM_Prescaler 												  		= psc;  						//向上计数模式TIM_TimeBaseStructure.TIM_CounterMode 											  			= TIM_CounterMode_Up; //自动重装载值TIM_TimeBaseStructure.TIM_Period 														  	= arr;   	//时钟分频TIM_TimeBaseStructure.TIM_ClockDivision 										  			= TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1 , &TIM_TimeBaseStructure);//初始化TIM1输入捕获参数//CC1S=01 	选择输入端 IC1映射到TI1上TIM_ICInitTypeDef  TIM1_ICInitStructure;TIM1_ICInitStructure.TIM_Channel													  		= TIM_Channel_1  ; 	//下降沿捕获		TIM1_ICInitStructure.TIM_ICPolarity 												 	    = TIM_ICPolarity_Falling;   			// 下降沿触发//映射到TI1上	TIM1_ICInitStructure.TIM_ICSelection 												  		= TIM_ICSelection_DirectTI; 			// 直连TI1(PA8)//配置输入分频,不分频 TIM1_ICInitStructure.TIM_ICPrescaler 												  		= TIM_ICPSC_DIV8;								  // 8分频捕获(降低中断频率)//IC1F=0000 配置输入滤波器 不滤波	TIM1_ICInitStructure.TIM_ICFilter 															= 0x0;		TIM_ICInit(TIM1 , &TIM1_ICInitStructure);TIM1_ICInitStructure.TIM_Channel 															=	TIM_Channel_2  ; 	//下降沿捕获		TIM1_ICInitStructure.TIM_ICPolarity 														= TIM_ICPolarity_Falling;//映射到TI1上	TIM1_ICInitStructure.TIM_ICSelection 														= TIM_ICSelection_DirectTI; //配置输入分频,不分频 TIM1_ICInitStructure.TIM_ICPrescaler 														= TIM_ICPSC_DIV8;//IC1F=0000 配置输入滤波器 不滤波	TIM1_ICInitStructure.TIM_ICFilter														  	= 0x0;		TIM_ICInit(TIM1 , &TIM1_ICInitStructure);//双通道均设置为下降沿触发,通过分频器(DIV8)减少中断次数//允许CC1 ,允许CC2IE捕获中断	TIM_ITConfig(TIM1 ,  TIM_IT_CC1  | TIM_IT_CC2, ENABLE);//TIM_TS_TI1FP1:表示选择 TIMx_CH1 引脚的滤波后信号(即经过输入滤波器和边沿检测后的信号)作为触发源//输入捕获模式下,用于自动复位计数器(CNT)以实现周期测量//PWMI 模式中,结合通道 2(TI1FP2)同时测量信号的频率和占空比TIM_SelectInputTrigger(TIM1 , TIM_TS_TI1FP1 );  								// 选择TI1(PA8)作为触发源TIM_SelectSlaveMode(TIM1 , TIM_SlaveMode_Reset);								// 从模式:TI1下降沿时计数器复位//PA8的下降沿会复位计数器(TIM_SlaveMode_Reset),为相位差测量提供基准NVIC_InitStructure.NVIC_IRQChannel 													 	 	= TIM1_CC_IRQn ;//抢占优先级2NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 				 				 		= 0;//子优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority 							 			 		= 0;	//IRQ通道使能	NVIC_InitStructure.NVIC_IRQChannelCmd 											 	 		= ENABLE;		//根据指定的参数初始化NVIC寄存器NVIC_Init(&NVIC_InitStructure);	//使能定时器5TIM_Cmd(TIM1 , DISABLE );                                           
}int Cycle = 0; 		//周期 
int Phase = 0; 		//相位
void TIM1_CC_IRQHandler(void)
{if((TIM1->SR & TIM_IT_CC1) != RESET)				// 捕获1发生捕获事件{	Cycle = TIM1->CCR1;								// 保存周期值(计数器复位后的计数值)TIM1->SR = (uint16_t)~TIM_IT_CC1;     		}else if((TIM1->SR & TIM_IT_CC2) != RESET)		    // 捕获2发生捕获事件{	Phase = TIM1->CCR2;								// 保存相位差(两次下降沿间隔)TIM1->SR = (uint16_t)~TIM_IT_CC2;}	}float getPhase()
{float phs = 0.0;if(Phase < (Cycle >> 1))  //进行分段求相位{phs = -((float)(Phase) / (float)Cycle) * 360;  				// -180 ~ 0}else {phs = ((float)(Cycle - Phase) / (float)Cycle) * 360;}return phs;
}

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

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

相关文章

什么是股指期货可转移阿尔法策略?

阿尔法&#xff08;Alpha&#xff09;是投资领域的一个术语&#xff0c;用来衡量投资组合的超额收益。简单来说&#xff0c;阿尔法就是你在市场上赚的比平均水平多出来的那部分钱。比如&#xff0c;市场平均收益率是5%&#xff0c;但你的投资组合收益率是10%&#xff0c;那你的…

AXI GPIO S——ZYNQ学习笔记10

AXI GPIO 同意通道混合输入输出中断控制#KEY set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[0]}] set_property PACKAGE_PIN J13 [get_ports {AXI_GPIO_KEY_tri_io[0]}] set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[1]}] set_pro…

如何通过传感器选型优化,为设备寿命 “续航”?

在当今竞争激烈的工业领域&#xff0c;企业就像在一场没有硝烟的战争中角逐&#xff0c;设备便是企业的“秘密武器”。设备的使用寿命&#xff0c;如同武器的耐用程度&#xff0c;直接决定了企业在生产战场上的“战斗力”。延长设备寿命&#xff0c;已然成为众多企业降低生产成…

WebSocket连接的例子

// 初始化WebSocket连接 const initWebSocket () > {console.log("初始化链接中...")const websocketUrl ws://61.54.84.16:9090/;// WebSocket服务器地址websocket new WebSocket(websocketUrl)//使用真实的webscket// websocket new MockWebSocket(websocket…

c++之指针和引用

一 使用场景 C++ 什么时候使用指针?什么时候使用引用?什么时候应该按值传递?_引用什么时候用比较好-CSDN博客 只使用传递过来的值,而不对值进行修改 需要修改传递过来的值 内置数据类型 按值传递(小型结构) 指针传递 数组 指针传递 指针传递 结构 指针或引用(较大的结构…

pytorch学习笔记-模型训练、利用GPU加速训练(两种方法)、使用模型完成任务

应该算是完结啦~再次感谢土堆老师&#xff01; 模型训练 模型训练基本可以分为以下几个步骤按序执行&#xff1a; 引入数据集-使用dataloader加载数据集-建立模型-设置损失函数-设置优化器-进行训练-训练中计算损失&#xff0c;并使用优化器更新参数-模型测试-模型存储 习惯上会…

深度卷积神经网络AlexNet

在提出LeNet后卷积神经网络在计算机视觉和机器学习领域中报有名气&#xff0c;但是卷积神经网络并没有主导这些领域&#xff0c;因为LeNet在小数据集上取得了很好的效果&#xff0c;在更大&#xff0c;更真实的数据集上训练卷积神经网络的性能 和可行性有待研究&#xff0c;20世…

数据结构-HashSet

在 Java 编程的世界里&#xff0c;集合框架是极为重要的一部分&#xff0c;而 HashSet 作为 Set 接口的典型实现类&#xff0c;在处理不允许重复元素的场景中频繁亮相。今天&#xff0c;我们就一同深入探究 HashSet&#xff0c;梳理它的特点、常用方法&#xff0c;以及和其他相…

心意行药号 · 慈心方的八种用法

心意行药号 慈心方的八种用法慈心方是心意行药号589个珍贵秘方中的一个养生茶方&#xff0c;配伍比例科学严谨&#xff0c;君臣佐使堪称经典&#xff0c;自古就有“小小慈心方&#xff0c;转动大乾坤”之说。自清代光绪年间传承至今&#xff0c;慈心方受益者逾百万计&#xff…

Spring面试宝典:Spring IOC的执行流程解析

在准备Spring框架的面试时&#xff0c;“Spring IOC的工作流程是什么&#xff1f;” 是一个非常经典的问题。虽然网上有很多详细的教程&#xff0c;但它们往往过于复杂&#xff0c;对于没有深入研究过源码的人来说理解起来确实有些困难。今天我们就来简化这个概念&#xff0c;从…

学习日志39 python

1 fromkeys()函数是什么在 Python 中&#xff0c;fromkeys() 是字典&#xff08;dict&#xff09;的一个类方法&#xff0c;用于创建一个新字典。它的作用是&#xff1a;根据指定的可迭代对象&#xff08;如列表、元组等&#xff09;中的元素作为键&#xff08;key&#xff09;…

SpringBoot + MyBatis-Plus 使用 listObjs 报 ClassCastException 的原因与解决办法

在项目中我们经常会遇到这种需求&#xff1a; 根据一组 ID 查询数据库&#xff0c;并返回指定字段列表。 我在写代码的时候&#xff0c;遇到了一个典型的坑&#xff0c;分享出来给大家。一、问题背景我的代码是这样写的&#xff08;查询项目表的负责人信息&#xff09;&#xf…

WT2606B 驱屏语音芯片新增蓝牙功能:功能集成一体化,产品升级自动化,语音交互无线化,场景应用普适化!

小伙伴们&#xff0c;欢迎来到我们的 &#xff03;唯创芯片小讲堂&#xff01;今天我们要为大家介绍一位多才多艺的"芯片全能手"——WT2606B驱屏语音芯片。这颗芯片将在今年8月的I0TE物联网展及ELEXCON 2025深圳国际电子展上大放异彩。在智能设备满天飞的今天&#x…

ORA-16331: container is not open ORA-06512: at “SYS.DBMS_LOGMNR“

使用Flink CDC、Debezium等CDC工具对Oracle进行基于log的实时数据同步时遇到异常ORA-16331: container is not open的解决方案。 1. 异常信息 异常信息通常如下&#xff1a; at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1823) at oracle.jdbc…

「三维共振」:重构实体零售的破局模式

在电商冲击与消费升级的双重浪潮下&#xff0c;传统零售模式正面临前所未有的挑战。wo店首创的 “三维共振” 运营模式&#xff0c;以场景体验为根基、数据驱动为引擎、社群共生为纽带&#xff0c;构建起线上线下深度融合的新型零售生态&#xff0c;至今已实现连续 18 个月客流…

将集合拆分成若干个batch,并将batch存于新的集合

在使用saveAll()等方法时&#xff0c;为了防止集合元素过大&#xff0c;使用splitList将原集合&#xff0c;分割成若干个小集合 import java.util.ArrayList; import java.util.List;public class ListUtils {/*** 将集合拆分成若干个batch,并将batch存于新的集合** param list…

Java主流框架全解析:从企业级开发到云原生

Java作为一门历史悠久且应用广泛的编程语言&#xff0c;其强大的生态系统离不开各种优秀的框架支持。无论是传统的企业级应用开发&#xff0c;还是现代的微服务、云原生架构&#xff0c;Java都提供了丰富的框架选择。本文将全面解析当前主流的Java框架&#xff0c;涵盖Web开发、…

机器学习——网格搜索(GridSearchCV)超参数优化

网格搜索&#xff08;Grid Search&#xff09;详细教学1. 什么是网格搜索&#xff1f;在机器学习模型中&#xff0c;算法的**超参数&#xff08;Hyperparameters&#xff09;**对模型的表现起着决定性作用。比如&#xff1a;KNN 的邻居数量 n_neighborsSVM 的惩罚系数 C 和核函…

【LeetCode】18. 四数之和

文章目录18. 四数之和题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;解题思路算法一&#xff1a;排序 双指针&#xff08;推荐&#xff09;算法二&#xff1a;通用 kSum&#xff08;含 2Sum 双指针&#xff09;复杂度关键细节代码实现要点完整题解代码18. 四数…

Go语言入门(10)-数组

访问数组元素&#xff1a;数组中的每个元素都可以通过“[]”和一个从0开始的索引进行访问数组的长度可由内置函数len来确定。在声明数组时&#xff0c;未被赋值元素的值是对应类型的零值。下面看一个例子package mainfunc main(){var planets [8]stringplanets[0] "Mercu…