4. GPIO与基础外设:GPIO模式配置、中断处理、定时器(TPM)基本使用

各位同学,咱们今天聊聊TPMS芯片里最基础、也最绕不开的三个东西:GPIO、中断和定时器。说实话,我刚开始做TPMS驱动那会儿,觉得GPIO不就是个输入输出嘛,有啥好讲的?结果第一次调试就翻车了——芯片死活不响应外部触发,查了两天才发现是GPIO模式没配对。嗯,这种坑,我帮你们先踩过了。

4.1 GPIO模式配置——别小看这玩意儿

NXP的TPMS芯片,GPIO口通常不是单一的。它可能是普通IO,也可能是唤醒源,还可能是SPI接口复用。你想想看,一个引脚要干三份活,配置错了自然就罢工。

我个人习惯,拿到芯片第一件事就是看Port Control Register。以我常用的FXTH87系列为例,GPIO配置主要涉及这几个寄存器:

寄存器 功能 我踩过的坑
PTxDS 数据方向(输入/输出) 默认是输入,忘了改输出就拉不了高电平
PTxPE 上拉/下拉使能 悬空引脚没使能上拉,功耗异常高
PTxPS 上拉/下拉选择 下拉电阻选太大,信号边沿变缓
PTxOD 开漏输出配置 I2C场景必须配开漏,否则总线冲突

配置代码其实很简单,但顺序有讲究。我建议先关中断,再配方向,最后使能。为什么?因为配方向的时候引脚电平会跳变,如果中断开着,可能触发一次虚假中断。我曾经因为这个,在产线上被折腾了一整天。

// 以FXTH87为例,配置PTA0为输出,带上拉
PTA_BASE->PTxDS |= (1 << 0);      // 设为输出
PTA_BASE->PTxPE |= (1 << 0);      // 使能上拉
PTA_BASE->PTxPS |= (1 << 0);      // 选择上拉(非下拉)
// 注意:先配方向,再使能上拉,避免瞬间短路
警告: 千万别在配置完方向之前使能上拉。如果引脚默认是输出且电平为低,上拉电阻会跟输出驱动器打架,轻则功耗飙升,重则烧引脚。我见过一块板子就是这么报废的。

4.2 中断处理——别让中断吃掉你的CPU

TPMS芯片的中断系统,说白了就是用来响应外部事件的。比如轮胎气压突变,传感器会拉一个中断引脚,MCU收到后立刻处理。但这里有个问题:中断服务程序(ISR)里不能做太多事。

我记得有一次,我在ISR里直接调用了SPI读写函数,结果系统卡死了。为什么?因为SPI通信需要等待,而中断里等轮询,等于把CPU锁死在中断里。正确的做法是:ISR里只做标记,具体处理放到主循环

NXP TPMS芯片的中断配置,通常涉及这几个步骤:

  1. 选择触发边沿:上升沿、下降沿、或者双边沿。我个人习惯用下降沿,因为TPMS传感器通常是低电平有效。
  2. 清除中断标志:进ISR第一件事就是清标志,否则会反复进中断。这个顺序千万别搞反。
  3. 设置优先级:TPMS里,气压突变中断优先级最高,定时器中断次之,普通IO中断最低。
// 配置PTA1为下降沿触发中断
PTA_BASE->PTxIE |= (1 << 1);       // 使能中断
PTA_BASE->PTxES |= (1 << 1);       // 下降沿触发
NVIC_EnableIRQ(PTA_IRQn);           // 使能NVIC中断

// ISR示例——只做标记
void PTA_IRQHandler(void) {
    // 第一步:清中断标志
    PTA_BASE->PTxIF |= (1 << 1);
    // 第二步:设一个全局标志
    g_bPressureEvent = 1;
    // 绝对不要在这里做复杂处理!
}
小技巧: 如果你不确定中断是否配置正确,可以在ISR里翻转一个测试GPIO,用示波器看波形。我调试时经常这么干,一眼就能看出中断频率对不对。

4.3 定时器(TPM)基本使用——时间管理的艺术

TPM,全称Timer/PWM Module,是NXP芯片里最常用的定时器外设。TPMS里用它干什么?说白了就两件事:定时唤醒PWM输出

先说说定时唤醒。TPMS芯片为了省电,大部分时间都在休眠。每隔几秒,TPM产生一个中断,把芯片叫醒,测一下气压,然后继续睡。这个周期怎么配?我给你们一个公式:

溢出时间 = (模数值 + 1) × 时钟周期 × 分频系数

举个例子,如果时钟是1MHz,分频系数设为128,模数值设为15624,那么溢出时间就是:

(15624 + 1) × (1 / 1MHz) × 128 = 2秒

嗯,正好两秒唤醒一次。这个参数我在项目里调过无数次,每次都要拿示波器量一下实际时间,因为芯片内部时钟会有偏差。

// 配置TPM0,2秒溢出中断
TPM0_BASE->SC = 0x00;               // 先关定时器
TPM0_BASE->MOD = 15624;             // 模数值
TPM0_BASE->SC = TPM_SC_PS(7) |      // 分频128 (2^7)
                 TPM_SC_TOIE_MASK;   // 使能溢出中断
NVIC_EnableIRQ(TPM0_IRQn);          // 使能中断
TPM0_BASE->SC |= TPM_SC_CMOD(1);    // 启动定时器(内部时钟)
重点: 配置TPM时,一定要先关定时器再改参数,否则寄存器写入可能不同步。我见过有人边跑边改模数值,结果定时器直接跑飞了。

再说说PWM输出。TPMS里PWM用来干嘛?驱动蜂鸣器或者LED指示。比如气压异常时,输出一个1kHz的PWM,驱动蜂鸣器报警。配置PWM其实更简单,设置好周期和占空比就行:

// 配置TPM1通道0输出PWM,频率1kHz,占空比50%
TPM1_BASE->SC = 0x00;               // 先关
TPM1_BASE->MOD = 999;               // 周期 = (999+1)/1MHz = 1ms
TPM1_BASE->C0V = 500;               // 占空比 = 500/1000 = 50%
TPM1_BASE->SC = TPM_SC_PS(0) |      // 不分频
                 TPM_SC_CMOD(1);     // 启动
// 别忘了配置GPIO为TPM复用功能
PTA_BASE->PTxDS |= (1 << 2);       // 输出
PTA_BASE->PTxPS |= (1 << 2);       // 选择TPM功能

这里有个细节:PWM输出频率不能太高。TPMS芯片的GPIO驱动能力有限,超过10kHz波形就开始变形了。我试过20kHz,示波器一看,方波变成了三角波,根本没法用。

4.4 实战中的避坑指南

最后,我把自己这些年踩过的坑总结一下,你们直接拿去用:

  • GPIO初始化顺序:先配方向,再配上拉,最后使能中断。顺序错了,轻则误触发,重则烧引脚。
  • 中断标志清除时机:进ISR第一件事清标志,不是最后。如果最后清,这期间又来了中断,可能会丢失。
  • TPM时钟源选择:低功耗模式下,内部时钟可能不准。如果需要精确计时,建议用外部晶振。我在一个项目里用内部时钟做1秒定时,结果实际是1.2秒,胎压数据全偏了。
  • PWM占空比边界:占空比设为0或100%时,有些芯片会输出恒低或恒高,但有些会直接关闭输出。用之前一定要看数据手册。

好了,这一章的内容就这些。GPIO、中断、定时器,这三个东西是嵌入式开发的基石。你想想看,TPMS芯片里所有功能——气压采集、无线发射、低功耗管理——都离不开它们。把基础打牢,后面学起来就顺了。

下一章咱们聊聊SPI通信,那可是TPMS芯片和传感器对话的桥梁。到时候见。