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

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.dtcms.com/a/343304.html

相关文章:

  • Nacos 深度指南:从入门到高可用集群部署
  • ES6 面试题及详细答案 80题 (01-05)-- 基础语法与变量声明
  • C++宏的高级用法与元编程技巧
  • 数据结构青铜到王者第一话---数据结构基本常识(2)
  • 指数续创新高,期权的几种应对之策
  • 在线《相关性分析》
  • rs-fMRI_一篇文章中分析方法的梳理(翻译)
  • 职星学院企业培训系统:私有化部署赋能企业知识安全
  • 【鸿蒙开发】ArkTS 装饰器全解析:从 @Entry 到 @Observed 的全面指南
  • 资源对象深度解析:Pod生命周期与容器探针、Deployment滚动更新与回滚、StatefulSet有状态应用管理
  • 《MLB美职棒》美国国球是橄榄球还是棒球·棒球5号位
  • DAY44打卡
  • LCR 018. 验证回文串
  • VUE实现多个弹窗优先级变化实现思路
  • 技术框架搭建:支撑竞拍全流程
  • Spring Cloud系列—SkyWalking链路追踪
  • IPSec 安全基础
  • Matplotlib数据可视化实战:Matplotlib高级使用技巧与性能优化
  • GitHub Push 认证失败 fatal Authentication failed
  • 数据治理——解读56页 数据治理整体规划汇报【附全文阅读】
  • java-ArrayList的使用
  • 短波红外科研相机:开启科研新视野的利器​
  • LCR 019. 验证回文串 II
  • SpringCloudConfig配置文件本地化部署
  • 第5.1节:awk内置变量
  • MySQL诊断系列(5/6):表结构与元数据查询——快速掌握数据库“DNA”
  • 在pycharmIDE中如何快速掌握一个新模块的使用方法
  • 前端视频流处理从 0 到 “能跑”:可复制 Demo+WebGL/Worker 优化,覆盖会议 / 直播 / 监控场景
  • js来比较两个对象内容有误差异
  • 从源码中学习Java面向对象的多态