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

【中微半导体】BAT32G139GK48FA 定时器B输入捕获测速(寄存器TBSR/TBIER/TB/TBGRA/TBGRC)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//步进电机控制输出IO宏定义变量
#define StepA  PORTCbits.RC6   //宏定义输出控制 RC6变量(步进电机驱动A)
#define StepB  PORTCbits.RC7   //宏定义输出控制 RC7变量(步进电机驱动B)
#define StepC  PORTCbits.RC8   //宏定义输出控制 RC8变量(步进电机驱动C)
#define StepD  PORTCbits.RC9   //宏定义输出控制 RC9变量(步进电机驱动D)/*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------*/
#define  Motor_Step_Driver_Freq                             (2)
#define  CM_Engine_Pole_Pairs                               (7)
#define  CM_RPM_BASE_Value                                  (4600)
#define  CM_RPM_BASE                                        (114)  //4600   (4096 / 4600 * 128 = 114)
#define  R_GQ                                               (7)
#define  Protect_Idle_Rpm                                   ((3850L*CM_RPM_BASE)>>R_GQ)   //3720
#define  CM_Engine_Speed_RefMAX                             (( 5600UL * CM_RPM_BASE ) >> R_GQ)	//参考转速最大值限制//   RPM =  (60 * f) / 7极对数
#define ECAP_VALUE_FREQ_LIMIT_UP                            (26666)//300hz   2571RPM     8M  1/8us      
#define ECAP_VALUE_FREQ_LIMIT_DOWN                          (10428)  // 	700Hz时的周期数       6000rpm      
/*-----------------------------------------------------------------------------*/

/*************************************************
Description: TMB_InputCapture_Init
Input      : 
Return     : 
Others     : 用于发电机转速信号捕获
*************************************************/
void TMB_InputCapture_Init(void)
{/*(1)设置TMB_InputCapture的时钟*/CGC->PER1 |= CGC_PER1_TMBEN_Msk;     /* enables input clock supply */TMB->TBMR &= (uint8_t)~_80_TMB_COUNT_START;TMB->TBCR = _00_TMB_CLEAR_DISABLEED  | _00_TMB_COUNT_RISING | _03_TMB_fCLK_8_SELECTED;  //时钟8分频,上升沿计数  64M/8 = 8MTMB->TBMR = _00_TMB_SIGNALB_SELECTED | //选择外部输入信号1/数字滤波器通过信号1。_00_TMB_INCREMENT_MODE   |  //递增计数_00_TMB_TBIOA_FILTER_UNUSED| //	TBIO0引脚的数字滤波器功能的选择_10_TMB_fCLK_8_SELECTED  | //数字滤波器功能所用时钟的选择_00_TMB_TIMER_MODE;        //定时器模式  /*(2)设置TMB_InputCapture捕获配置模式*/
//    TMB->TBIOR |= _80_TMB_TBGRB_REGISTER_USED | _40_TMB_TBGRB_INPUT_CAPTURE ;  //TBGRB配置为输入捕捉功能  ,使用缓冲寄存器,TBIO1的上升沿TMB->TBIOR = _08_TMB_TBGRA_REGISTER_USED | _04_TMB_TBGRA_INPUT_CAPTURE; //TBGRA配置为输入捕捉功能  ,使用缓冲寄存器,TBIO0的上升沿/*(4)设置TMB_InputCapture捕获中断*/	INTC_DisableIRQ(TMB_IRQn);/* disable INTTMB interrupt */INTC_ClearPendingIRQ(TMB_IRQn);/* clear INTTMB interrupt flag */TMB->TBIER = _08_TMB_INTERRUPT_TBOVF_ENABLE  | _01_TMB_INTERRUPT_TBIMFA_ENABLE;//配置中断允许寄存器	/*(5)设置TMB_InputCapture中断优先级*/	NVIC_SetPriority(TMB_IRQn,3);/*(6)配置输入源IO端口模式*/	/* Set TBIO0 pin */PORT->PM5 |= 0x01U; // P50   输入模式//		/* Set TBIO1 pin */
//		PORT->PM5 |= 0x02U; // P51   输入模式/*(7)开启TMB_InputCapture模块*/	TMB0_Start();	 	 		 
}

/*************************************************
Description: tmb0_interrupt
Input      : 
Return     : 
Others     : IC2捕获中断:获取发电机转速
*************************************************/
static void tmb0_interrupt(void)
{uint32_t Temp_AA;uint32_t Temp_BB;uint8_t tbsr_temp,tbier_temp; INTC_ClearPendingIRQ(TMB_IRQn); /* clear INTTMB interrupt flag */tbsr_temp = TMB->TBSR;tbier_temp = TMB->TBIER;TMB->TBIER = 0x00U; // 关闭中断  TBIER 允许寄存器// TBSR 定时器B状态寄存器// 当定时器B计数器(TB)上溢发生时,TBSR 寄存器的 TBOVF 位置1if ((TMB->TBSR & _08_TMB_REGISTER_OVERFLOW) == _08_TMB_REGISTER_OVERFLOW) // 溢出处理 TBOVF 是 TBSR 的溢出标志{TMB->TBSR = tbsr_temp & (uint8_t)~_08_TMB_REGISTER_OVERFLOW;g_tmb_overflow_count_a += 1UL;}#if 1if ((TMB->TBSR & _01_TMB_INTERRUPT_TBIMFA_ENABLE) == _01_TMB_INTERRUPT_TBIMFA_ENABLE) // TBIMFA 是 TBIO0 (测速)引脚的输入边沿 P50 引脚{TMB->TBSR = tbsr_temp & ~_01_TMB_INTERRUPT_TBIMFA_ENABLE;g_tmb_intTaken_a++;if (g_tmb_overflow_count_a == 0UL){g_tmb_active_width_a = (TMB->TBGRA - TMB->TBGRC);		// TBGRC 是 TBGRA的缓冲寄存器, 			}else{g_tmb_active_width_a = (TMB->TBGRA - TMB->TBGRC) + (0x10000UL * g_tmb_overflow_count_a);//TMB->TBGRC为上一下的值g_tmb_overflow_count_a = 0UL;					}}s32_GeneratorcapvalCal     = g_tmb_active_width_a;//捕获As32_GeneratorcapvalCaltemp = s32_GeneratorcapvalCal;if ( s32_GeneratorcapvalCal >   ECAP_VALUE_FREQ_LIMIT_UP )  s32_GeneratorcapvalCal  = ECAP_VALUE_FREQ_LIMIT_UP;if ( s32_GeneratorcapvalCal < ECAP_VALUE_FREQ_LIMIT_DOWN )  s32_GeneratorcapvalCal  = s32_GeneratorcapvalCal_OLd;s32_GeneratorcapvalCal_OLd  = s32_GeneratorcapvalCal;Temp_AA = ( ( 480000000L/CM_Engine_Pole_Pairs )) >> R_GQ;	//   (8MHz)*60=360 000 000       例:5000RPM * 114 >> 7  5000RPM * CM_RPM_BASE >> R_GQTemp_BB = ( Temp_AA	* CM_RPM_BASE );// >> R_GQ;Temp_AA = s32_GeneratorcapvalCal ;   s16_GeneratorfreVal = ( Temp_BB / Temp_AA );if(s16_GeneratorfreVal_Old > 2862)//不等于最低转速时启用{ if((s16_GeneratorfreVal - s16_GeneratorfreVal_Old > 350 ||s16_GeneratorfreVal - s16_GeneratorfreVal_Old < -350) && ADSample_Info.Bus_Vol_Filiter_AD > 2730)s16_GeneratorfreVal = s16_GeneratorfreVal_Old;}s16_GeneratorfreVal_Old = s16_GeneratorfreVal;GeneratorfreFilter.half.hWord = (((uint32_t)GeneratorfreFilter.half.hWord * 1093)  + ((uint32_t)s16_GeneratorfreVal * 3003) ) >> 12;//采集的转速一阶低通滤波    if(count_flag >= SpeedSampleCount)    count_flag = 0;s16_GeneratorfreVal_Array[count_flag] = GeneratorfreFilter.half.hWord;count_flag ++;	#endifTMB->TBIER = tbier_temp;}

初始化 + 中断采集 + 宏定义全部串起来,做一份“从硬件到公式到变量流”的完整解析。看完你就能对TMB 定时器如何采集转速数据怎么流转每一步算法在做什么心里有数。


一、硬件与时序基础

  • 计数时钟TMB->TBCR 配成 fCLK/8。你注释写明主时钟 64 MHz,因此 计数频率 = 8 MHz计数分辨率 = 1/8 µs = 0.125 µs = 125 ns/计数
  • 捕获通道TMB->TBIOR 使用 TBGRA 做输入捕获,TBIO0(P50) 上升沿触发。
  • 测量量:连续两次上升沿之间的计数差(含溢出补偿)= 输入信号的电角周期
  • 寄存器与位宽:捕获寄存器是 16 位(你用 0x10000UL * 溢出次数 补偿),所以需要溢出记数。

二、初始化做了什么(TMB_InputCapture_Init)

  1. 开时钟/停计数
    CGC->PER1 |= TMBEN 使能模块 → TMB->TBMR 清计数开始位,先停止定时器再配。

  2. 计数模式
    TMB->TBCR = 上升沿计数 + fCLK/8TMB->TBMR = 递增计数 + (未用TBIOA滤波)

  3. 捕获选择
    TMB->TBIOR = TBGRA 作为输入捕获(TBIO0 上升沿),带缓冲(降低丢样风险)。

  4. 中断
    溢出中断(TBOVF)+ 捕获 A 中断(TBIMFA),设置 NVIC 优先级。

  5. 引脚
    P50 输入模式(TBIO0)。

  6. 启动
    TMB0_Start(),开始计数、等待外部脉冲。


三、中断里怎么“量周期”(tmb0_interrupt)

  1. 关中断、拍快照、清挂起
    防重入 → 读取 TBSR/TBIER 暂存 → TBIER=0 关所有 TMB 中断。

  2. 溢出处理

if (TBSR & OVERFLOW) {清标志;g_tmb_overflow_count_a++;
}
  • 脉冲周期很长(低速)时,16 位计数会绕回,用溢出计数补偿
  1. 捕获事件(上升沿到来)
清 TBIMFA 标志;
if (g_tmb_overflow_count_a == 0)g_tmb_active_width_a = TBGRA - TBGRC;
elseg_tmb_active_width_a = (TBGRA - TBGRC) + 0x10000 * g_tmb_overflow_count_a;
g_tmb_overflow_count_a = 0;
  • TBGRA=本次时间戳,TBGRC=上次时间戳(硬件缓冲/影子寄存器)。
  • 差值 + 溢出补偿 = 本周期计数值(capture_counts)
  1. 原始周期到工作周期(限幅/防抖)
s32_GeneratorcapvalCal = g_tmb_active_width_a;if (capval > ECAP_VALUE_FREQ_LIMIT_UP)    capval = ECAP_VALUE_FREQ_LIMIT_UP;   // 下限转速饱和
if (capval < ECAP_VALUE_FREQ_LIMIT_DOWN)  capval = capval_old;                 // 过高转速丢弃
capval_old = capval;
  • 你设置了有效频率窗

    • ECAP_VALUE_FREQ_LIMIT_UP = 26666 → 对应 300 Hz≈2571 rpm
    • ECAP_VALUE_FREQ_LIMIT_DOWN = 10428 → 你注释写“700 Hz=6000 rpm”。按 8 MHz,700 Hz 的周期应是 11429 计数,10428 对应 ≈ 767 Hz(≈ 6571 rpm)。这儿建议你核对一下常量或注释是否笔误。
  • 逻辑意图:低速(<≈2571 rpm)直接饱和到下限;高速(>≈6000 rpm)则忽略本次更新(保持旧值)。

    区间锁定可保证控制算法处于有效速度窗内运行,避免极低/极高转速对后级环节造成干扰。


四、从“周期计数”算到“转速值”

核心代码:

Temp_AA = ((480000000L / CM_Engine_Pole_Pairs)) >> R_GQ;  // 480e6 = 60 * 8e6
Temp_BB = (Temp_AA * CM_RPM_BASE);
s16_GeneratorfreVal = Temp_BB / capval;                   // capval=本周期计数

把它化简成数学式(全部是整数定点运算):

  • 已知:

    • 计数时钟 f_cnt = 8 MHz
    • 电频率 f_elec = f_cnt / capval
    • 机械转速(RPM):RPM=60⋅felecPolePairs\text{RPM} = \dfrac{60 \cdot f_{elec}}{\text{PolePairs}}RPM=PolePairs60felec
  • 你的定标/量化

    • R_GQ = 7 → 右移 7,相当于除以 27=1282^7=12827=128
    • CM_RPM_BASE = 114(来自 4096/4600×128≈1144096 / 4600 \times 128 \approx 1144096/4600×128114
  • 组合得到:

s16_GeneratorfreVal=(60⋅fcntPolePairs)⋅CM_RPM_BASE/2R_GQcapval=Kcapval, \begin{aligned} s16\_GeneratorfreVal &= \frac{\left(\frac{60 \cdot f_{cnt}}{\text{PolePairs}} \right) \cdot CM\_RPM\_BASE / 2^{R\_GQ}}{capval} \\ &= \frac{K}{capval}, \end{aligned} s16_GeneratorfreVal=capval(PolePairs60fcnt)CM_RPM_BASE/2R_GQ=capvalK,

其中

K=⌊60⋅8,000,000PolePairs⌋≫7×CM_RPM_BASE K = \left\lfloor \frac{60 \cdot 8{,}000{,}000}{\text{PolePairs}} \right\rfloor \gg 7 \times CM\_RPM\_BASE K=PolePairs608,000,0007×CM_RPM_BASE

把你的参数代入(PolePairs=7,R_GQ=7,CM_RPM_BASE=114):

  • (480 000 000/7)≫7=535 714(480\,000\,000 / 7) \gg 7 = 535\,714(480000000/7)7=535714
  • K=535 714×114=61 071 396K = 535\,714 \times 114 = 61\,071\,396K=535714×114=61071396

所以:

s16_GeneratorfreVal≈⌊61,071,396capval⌋ \boxed{s16\_GeneratorfreVal \approx \left\lfloor \frac{61{,}071{,}396}{capval} \right\rfloor} s16_GeneratorfreValcapval61,071,396

这是定标后的转速值,不是“真 RPM”。它与真值的线性换算关系见下。


五、定标量纲与“真 RPM”换算

你把 RPM 做了定点缩放:

s16≈RPM×CM_RPM_BASE2R_GQ=RPM×114128=RPM×0.890625 s16 \approx \text{RPM} \times \frac{CM\_RPM\_BASE}{2^{R\_GQ}} = \text{RPM} \times \frac{114}{128} = \text{RPM} \times 0.890625 s16RPM×2R_GQCM_RPM_BASE=RPM×128114=RPM×0.890625

所以:

  • 由 s16 得 RPM RPM≈s16×128114≈s16×1.1228\ \text{RPM} \approx s16 \times \frac{128}{114} \approx s16 \times 1.1228 RPMs16×114128s16×1.1228
  • 由 RPM 得 s16 s16≈RPM×0.890625\ s16 \approx \text{RPM} \times 0.890625 s16RPM×0.890625

例子(用上面的 K 值计算):

场景周期计数 capvals16 计算换算真 RPM
300 Hz(≈2571 rpm)2666661071396 / 26666 = 22902290×128/114 ≈ 2571 rpm
约 4000 rpm1714361071396 / 17143 = 35623562×128/114 ≈ 3999 rpm
你宏里 104281042858565856×128/114 ≈ 6575 rpm(对应≈767 Hz)

再次提示:如果你要把“上限”严格卡在 6000 rpm(700 Hz @ 7 极对数),ECAP_VALUE_FREQ_LIMIT_DOWN 应为 11429 左右,而不是 10428


六、瞬态抑制(跳变过滤)与一阶低通

  1. 跳变抑制(只在一定速度以上才启用):
if (s16_old > 2862) { // 约 3213 rpm(=2862×128/114)if (|s16 - s16_old| > 350  且  母线电压AD > 2730) s16 = s16_old;  // 认为是毛刺/异常,丢弃
}
s16_old = s16;
  • 350 的阈值在真 RPM 中 ≈ 350×128/114≈393 rpm350 \times 128 / 114 \approx 393\ \text{rpm}350×128/114393 rpm
  • 带上母线电压判据(AD>2730)进一步减少误判。
  1. 一阶 IIR 低通(平滑噪声/抖动):
y = (y_prev*1093 + x*3003) >> 12; // 1093+3003 = 4096
  • 归一化后:y=0.267 y−1+0.733 xy = 0.267\,y_{-1} + 0.733\,xy=0.267y1+0.733x(较快响应、适中平滑)。
  1. 环形缓冲
    滤波后的 s16 值存进 s16_GeneratorfreVal_Array[10],10 点窗口(SpeedSampleCount=10)可用于后续均值/统计。

七、宏参数的作用与“速度窗”

#define CM_Engine_Pole_Pairs   (7)          // 极对数,决定电频/机频换算
#define R_GQ                    (7)          // 定点右移位数(Q 格式)
#define CM_RPM_BASE             (114)        // 定点比例子
#define Protect_Idle_Rpm        ((3850*114)>>7)  // ≈3428(真RPM≈3850)—保护/怠速门槛
#define CM_Engine_Speed_RefMAX  ((5600*114)>>7)  // ≈4988(真RPM≈5600)—参考速度上限
#define ECAP_VALUE_FREQ_LIMIT_UP   (26666)   // 300 Hz(≈2571 rpm)以下饱和到此
#define ECAP_VALUE_FREQ_LIMIT_DOWN (10428)   // 建议核对,应为 ~11429 对应 700 Hz/6000 rpm
  • 速度窗(有效采样区间)2571–6000 rpm

    • 低于下限:直接压到 2571 rpm 等效值(通过把周期 capval 压到 26666)。
    • 高于上限:忽略本次更新(保持上一次值)。
  • 控制环配合:上游测速限幅 + 下游 PI/表格(P_table/Q_table)通常会期望速度处于这个窗内,便于稳定控制。


八、变量数据如何流动(要点对照表)

变量/寄存器含义
TBGRA / TBGRC本次/上次捕获时间戳(16 位)
g_tmb_overflow_count_a期间发生的 16 位溢出次数
g_tmb_active_width_a本周期计数 = (TBGRA - TBGRC) + 0x10000×溢出
s32_GeneratorcapvalCal经过限幅/防抖后的有效周期计数
s16_GeneratorfreVal定标后的转速值(≈ RPM×114/128)
s16_GeneratorfreVal_Old上一次定标转速,用于跳变抑制
GeneratorfreFilter.half.hWord一阶低通滤波输出(仍是定标转速)
s16_GeneratorfreVal_Array[10]最近 10 个滤波后的定标转速样本
ADSample_Info.Bus_Vol_Filiter_AD母线电压判断门槛(>2730 才启用跳变抑制)

九、整体流程图

flowchart TD
A[中断入口: tmb0_interrupt] --> B[读 TBSR/TBIER 快照, 关闭 TMB 中断]
B --> C{TBSR 溢出标志?}
C -- 是 --> C1[清溢出标志; g_overflow++ ] --> D
C -- 否 --> D[检查捕获标志(TBIMFA)]
D -- 发生 --> E[清捕获标志; g_intTaken_a++]
E --> F{g_overflow == 0?}
F -- 是 --> G[cap = TBGRA - TBGRC]
F -- 否 --> H[cap = (TBGRA - TBGRC) + 0x10000 * g_overflow; g_overflow=0]
G --> I[capval = cap]
H --> I[capval = cap]
I --> J{capval > ECAP_UP(26666)?}
J -- 是 --> J1[capval = 26666(≈2571rpm)]
J -- 否 --> K{capval < ECAP_DOWN?}
K -- 是 --> K1[capval = capval_old(忽略本次)]
K -- 否 --> L[capval_old = capval]
J1 --> L
K1 --> L
L --> M[s16 = floor(K / capval), K=61071396]
M --> N{s16_old > 2862(≈3213rpm)?}
N -- 是 --> O{|s16-s16_old|>350 且 母线AD>2730?}
O -- 是 --> O1[s16 = s16_old]
O -- 否 --> P[保持 s16]
N -- 否 --> P
O1 --> Q
P --> Q[ s16_old = s16 ]
Q --> R[LPF: y = (y*1093 + s16*3003)>>12 ]
R --> S[写入环形缓冲数组]
S --> T[恢复 TBIER, 退出中断]

十、校核与建议

  1. 上限常量核对:如需严格卡 6000 rpm,ECAP_VALUE_FREQ_LIMIT_DOWN 应按 8e6/700 ≈ 11429 设置;你现在的 10428 对应 ≈ 6575 rpm。

  2. 定点精度:目前先除后移再乘,已尽量避免溢出;如要更精确可用 64 位:

    uint64_t K = ( (uint64_t)60 * 8000000 * CM_RPM_BASE ) >> R_GQ;
    K /= CM_Engine_Pole_Pairs;
    s16 = (uint16_t)(K / capval);
    
  3. 低速可测范围:低于 ≈2571 rpm 被强制饱和,如需更低速测量,要调大 ECAP_VALUE_FREQ_LIMIT_UP(对应更长周期)。

  4. 输入去抖/数字滤波:现在 TBIOA 滤波未开,若前端传感器有毛刺,可适度开启数字滤波以改善 |Δs16|>350 的毛刺触发概率。

  5. 单位转换:需要真 RPM 时,用 rpm ≈ s16 * 128 / 114,并注意整数四舍五入。


也可以把这套公式做成可直接拷进工程的注释+调参建议表(比如如何把速度窗改到 1500–7000 rpm、LPF 系数如何改快/改稳等),或者把上面的 Mermaid 进一步拆成“初始化/中断/计算”三张图,便于写文档。

http://www.dtcms.com/a/332436.html

相关文章:

  • Struts文件泄露漏洞分析与修复方案
  • 企业级Spring事务管理:从单体应用到微服务分布式事务完整方案
  • Baumer高防护相机如何通过YoloV8深度学习模型实现驾驶员疲劳的检测识别(C#代码UI界面版)
  • MySQL 主键详解:作用与使用方法
  • 搭建前端开发环境 安装nvm nodejs pnpm 配置环境变量
  • MySQL、PolarDB、PolarDB-X、TableStore、MongoDB、TiDB、ClickHouse选型
  • 融合开源AI智能名片与链动2+1模式的微商新零售转型研究——基于S2B2C商城小程序的实践探索
  • 戴永红×数图:重构零售空间价值,让陈列创造效益!
  • HTML5新增属性
  • 鸿蒙任务调度机制深度解析:优先级、时间片、多核与分布式的流畅秘密
  • 什么是国产化防爆平板?有哪些功能特点?应用在什么场景?
  • 【iOS】多线程原理
  • AI生成内容版权争议:当算法创作撞上法律边界
  • Python入门第2课:变量、数据类型与输入输出
  • Java Maven更换国内源
  • 企业网盘、NAS、移动硬盘、同步盘都是什么意思?
  • 个人博客系统测试文档
  • Python复杂元素排序:从基础到高阶
  • 以太网转换器实现:S7-300通过MPI转以太网连接多类工业设备
  • Java锁机制深度解析:从synchronized到StampedLock
  • Linux网络基础(一)
  • 嵌入式开发学习———Linux环境下网络编程学习(二)
  • 开始回溯的学习
  • OpenSCA开源社区每日安全漏洞及投毒情报资讯|14th Aug. , 2025
  • hex文件结构速查
  • Flutter 以模块化方案 适配 HarmonyOS 的实现方法
  • 3分钟解锁网页“硬盘“能力:离线运行VSCode的新一代Web存储技术
  • 二叉树(1):二叉树的前、中、后和层次遍历
  • 《R for Data Science (2e)》免费中文翻译 (第4章) --- Workflow: code style
  • STM32L051 RTC闹钟配置详解