总体概述
在MCU开发中,我们经常需要对外部信号的上升沿或下降沿进行检测,并据此触发中断。但在实际项目中,你可能会遇到这样的问题:
某些引脚(例如MCXC444的PortE)并不支持GPIO中断功能。
这时候,如果再调整硬件已经来不及,该怎么办?
一个非常实用的思路是:借助FlexIO来“模拟中断”。
FlexIO本质上是一个高度可编程的外设,不仅可以模拟UART、SPI、I²C,还能灵活实现:
波形捕捉
边沿检测
自定义时序逻辑
本文就带你一步步实现:利用FlexIO Timer,在FLEXIO_D4(PTE20)引脚上捕捉上升沿并触发中断~
一、设计思路
FlexIO Timer的核心机制如下:
PinSelect → 选择输入引脚(FLEXIO_D4 PTE20)
TimerDecrement → 由引脚电平驱动计数
TimerReset → 在上升沿复位计数器
TimerCompare → 计数达到比较值时置位中断标志
这样就能实现:每检测到一次上升沿,就触发一次中断
二、实现步骤
2.1 时钟配置
为FlexIO模块开启时钟。
/* Set FLEXIO clock source. */ CLOCK_SetFlexio0Clock(SIM_FLEXIO_CLK_SEL_IRC48M_CLK);
2.2 配置引脚
PTE20 → 复用为 FLEXIO0_D4 输入
PTE30 → GPIO 输出(用于产生测试波形)
/* PORTE20 (pin 9) is configured as FXIO0_D4 */ PORT_SetPinMux(PORTE, 20U, kPORT_MuxAlt6); /* PORTE30 (pin 18) is configured as PTE30 */ PORT_SetPinMux(PORTE, 30U, kPORT_MuxAsGpio);
2.3 配置 FlexIO Timer
flexio_config_t flexioConfig; flexio_timer_config_t timerConfig; /* 3. 初始化 FlexIO 模块 */ FLEXIO_GetDefaultConfig(&flexioConfig); FLEXIO_Init(BOARD_FLEXIO_BASE, &flexioConfig); memset(&timerConfig, 0, sizeof(timerConfig)); timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled; timerConfig.pinSelect = 4; timerConfig.pinPolarity = kFLEXIO_PinActiveHigh; timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(FLEXIO_PIN); timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh; // rising edge timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceExternal; timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh; timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit; timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset; timerConfig.timerDecrement= kFLEXIO_TimerDecSrcOnPinInputShiftPinInput; timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinRisingEdge; timerConfig.timerDisable = kFLEXIO_TimerDisableNever; timerConfig.timerEnable = kFLEXIO_TimerEnabledAlways; timerConfig.timerCompare = 0x0001; FLEXIO_SetTimerConfig(BOARD_FLEXIO_BASE, 0, &timerConfig); FLEXIO_EnableTimerStatusInterrupts(BOARD_FLEXIO_BASE, 1U << 0); EnableIRQ(UART2_FLEXIO_IRQn); NVIC_SetPriority(UART2_FLEXIO_IRQn, 2);
关键点说明:
triggerSelect
FLEXIO_TIMER_TRIGGER_SEL_PININPUT(FLEXIO_PIN);
引脚输入作为触发源
timerReset
kFLEXIO_TimerResetOnTimerPinRisingEdge,确保每次上升沿都会触发
timerDecrement
kFLEXIO_TimerResetOnTimerPinRisingEdge, 由外部引脚驱动计数
pinConfig/pinSelect
指定输入引脚为FlexIO_D4
timerMode
单次计数模式,适合捕捉事件
timerCompare = 0x01, 确保每次边沿都会立刻触发中断。值太大会导致需要多次脉冲才触发
每次边沿立即产生中断(非常关键!)
注意:
MCXC444没有单独的 FLEXIO_IRQn, 而是复用在:UART2_FLEXIO_IRQn
2.4 中断服务函数
void UART2_FLEXIO_IRQHandler(void)
{
uint32_t flags = FLEXIO_GetTimerStatusFlags(BOARD_FLEXIO_BASE);
if (flags & (1U << FLEXIO_TIMER))
{
FLEXIO_ClearTimerStatusFlags(BOARD_FLEXIO_BASE, 1U << FLEXIO_TIMER);
PRINTF("FlexIO: Rising edge detected!
");
}
};
三、实验结果
当外部信号接入PTE20(FLEXIO0_D4)并产生上升沿时:
FlexIO Timer 成功捕获
中断被触发
串口打印提示信息
实验证明:
FlexIO完全可以作为“软件定义的外部中断模块”使用
四、重点优化
很多人认为:
没有GPIO中断=无法检测外部事件
但实际上,通过FlexIO,你可以:
自定义触发条件
灵活绑定任意引脚
实现比传统 GPIO 更复杂的逻辑
本质上,FlexIO提供的是一种“更高级的硬件编程能力”。当GPIO中断受限时,FlexIO就是你的“外挂神器”——不仅能替代,还能做得更强。
TIC: Harry Zhang
全部0条评论
快来发表一下你的评论吧 !