This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
工具与软件:
您好!
我正在尝试在 GPIO 端口 M Pin0...上实现按钮中断 我在示波器上看到、当按下开关时、开关确实变为低电平、但通过 UART 端口没有显示任何内容。 我是否遗漏了针对中断初始化引脚的步骤? 我在开关上连接了一个硬件去抖电路。
下面是我的代码:
您好!
抱歉、我目前正在度假一整周。 当我回来的时候,我会回复你。 请预计我的回复会有延迟。
你(们)好
[报价 userid="617391" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1451550/sw-ek-tm4c1294xl-ek-tm4c1294xl-eval-board-trying-to-set-portm-pin0-for-a-push-button-interrupt "]下面是我的代码:
您的代码对我来说没有问题。 我看到唯一缺失的是下面一行。
IntEnable (INT_GPIIOM);
我在 Init 函数的末尾添加了 IntEnable (INT_GPIIOM)、但现在按下按钮后、UART 显示屏将锁定、不会发出任何东西。
如果不添加线条、则表明按钮正在被按下、但仅当我在按下按钮的同时转动光学编码器旋钮时才会如此。
如果我只按下按钮、不会出现任何情况。
我将开关输出连接至 PM0的引脚41
您好!
您应该尽量不要在 PortM ISR 中使用 UARTprintf()。 UARTprintf 会占用周期来传输 ASCII 消息。 在传输消息时、可能检测到 GPIO 上的另一个边沿、从而错过了该消息。
我在 ISR 中对 UARTPrintf 语句进行了注释。 当我使用添加的 IntEnable (INT_GPIIOM)代码按下按钮时、它仍然锁定。
您好!
您能解释一下锁定是什么意思吗? 如果你在 IntHandlerPortM 中放置一个断点、它会在其中停止吗? 一旦输入、如果您在 ISR 中单步执行代码、它最终会退出吗? 我想在你的 main ()中,你有某种类型的 while ()循环,只是旋转。 如果您还在 while 循环中放置了一个断点、它会在该循环中停止吗? 换言之、它是以替代方式在任一断点停止?
是的、我在 IntHandlerPortM、IntEnable (INT_GPIIOM)和 while 循环中设置断点。 它会命中除 ISR 断点之外的所有内容。 我按下光学编码器上的按钮后、UART 显示器就会停止并锁住。 我必须复位电路板/调试才能使其重新启动并运行。 ISR 中的断点不会被命中。
您好!
您是如何实现去抖的? 您是否确定去抖未完全滤除输入?
这是您的定制 PCB 还是 LaunchPad? 我之所以提出这个问题、是因为如果您在 LaunchPad 上运行、LaunchPad 不会使用 PM0作为开关、而是使用 PJ0和 PJ1作为开关。 为何不修改代码来尝试 PJ0 (SW1)或 PJ1 (SW2)、并确保其在 LaunchPad 上正常工作。 如果 PM0是您在定制电路板上实现的代码、则可与您的现有代码进行比较。
我使用的是 LaunchPad。 我最初设置为使用 PJ0和 PJ1上的开关、但它适用于评估板本身上的按钮开关。 但光学编码器开关没有中断、因此我认为当按下编码器开关时、LaunchPad 开关可能会覆盖 ISR、因此我将编码器开关切换为 PM0。 除了使用 GPIOM 而不是 GPIOJ 之外、代码是相同的。
当您说它锁定了时、处理器卡在哪里? 您还可以从 Register Browser 显示整个端口 M 的寄存器转储吗?
当我停止调试时、它似乎位于默认 ISR 指令处。 此外、在我的"Registers"窗口中、我只能看到 GPIO_PORT (A 到 F)、无法确定为何未显示其他寄存器。 我尝试在表达式浏览器中手动输入 GPIO 名称、但该浏览器找不到 GPIO_PORTM
当我停止调试时、似乎是默认 ISR 指令
这意味着不会进行中断矢量的动态分配。 当我再次仔细查看你的代码时,你用 GPIOIntRegisterPin ()来插入你的 ISR。 不能将其用于 PortM。 您需要使用 GPIOIntRegister (),因为 PortM 不会为每个单独的引脚分配 ISR 矢量。 只有 PortP 和 PortQ 可以为每个引脚具有单独的 ISR。 请参阅 下面 GPIOIntRegisterPin 与 GPIOIntRegister 之间的差异。
请参阅下面的矢量表。 端口 M 中的所有引脚都映射到一个 ISR、而对于 PP 和 PQ、可以具有单独的引脚及其自己的 ISR。
我最初确实将 PortQ 作为我的中断寄存器、但我对总结中断引脚0感到困惑、所以我切换到了 PortM。 但由于我不使用它作为摘要中断、我使用 Pin1将其切换回端口 Q、但仍然没有注册该中断。 此板需要在按钮后复位、以显示 UART 之外的任何内容。 在调试中、按下按钮后仍会进入 IntDefaultHandler。
您好、Erwin:
在调试中、按下该按钮后仍将转至 IntDefaultHandler。[/QUOT]如果您正在 IntDefaultHandler 上暂停、则表示由于某种原因未注册 PQ1的向量。 就 GPIO 而言、它会生成中断。 只是处理器跳转到默认矢量、该矢量除了旋转而不是跳转到 IntHandlerPortQ。
您能否尝试以静态方式代替使用 GPIOIntRegisterPin 来为 PQ1插入 ISR ? 请参阅以下示例。
1.注释掉您下面的行。
GPIOIntRegisterPin (GPIO_PORTQ_BASE、GPIO_PIN_1、IntHandlerPortQ);
2.在启动文件中添加以下行。
extern void IntHandlerPortQ (void);
3.将 PQ1矢量替换为以下内容。
进行了上述更改并且仍然保持不变。 转到默认中断处理程序
这很奇怪。 为什么不试试下面的代码呢? 这对我来说很有用。 我没有实现任何去抖。 每次将 PQ1拉至低电平时、我都会看到 LED 以更快的速率闪烁。 首先在 LaunchPad 上尝试它。 稍后您可以为您的应用修改它。
BTW、您可以插入如下代码。 您无需截取代码的屏幕截图。
#include <stdbool.h> #include <stdint.h> #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/sysctl.h" #include "driverlib/timer.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" #define USER_LED1 GPIO_PIN_0 #define USER_LED2 GPIO_PIN_1 uint32_t ui32SysClock; //***************************************************************************** // // Counter to count the number of interrupts that have been called. // //***************************************************************************** static volatile uint32_t g_ui32Counter = 0; //***************************************************************************** // // The interrupt handler for the Timer0 interrupt. // //***************************************************************************** void Timer0IntHandler(void) { // // Clear the timer interrupt flag. // TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); if ((g_ui32Counter % 2) == 0){ GPIOPinWrite(GPIO_PORTN_BASE, (USER_LED1|USER_LED2), USER_LED1); } else { GPIOPinWrite(GPIO_PORTN_BASE, (USER_LED1|USER_LED2), USER_LED2); } // // Update the periodic interrupt counter. // g_ui32Counter++; } void UserButton2ISR (void) { GPIOIntClear(GPIO_PORTQ_BASE, GPIO_PIN_1); ui32SysClock *= 0.995; TimerLoadSet(TIMER0_BASE, TIMER_A, ui32SysClock / 2); } //***************************************************************************** // // Configure Timer0B as a 16-bit periodic counter with an interrupt // every 1ms. // //***************************************************************************** int main(void) { // // Set the clocking to run directly from the external crystal/oscillator. // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the // crystal on your board. // ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_OSC), 25000000); // // The Timer0 peripheral must be enabled for use. // SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // // Enable and wait for the port to be ready for access // SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPION)) { } // // Configure the GPIO port for the LED operation. // GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, (USER_LED1|USER_LED2)); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOQ)) { } GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_1); GPIOPadConfigSet(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU); GPIOIntTypeSet(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_FALLING_EDGE); // // These interrupts are re-mapped to ISR functions // found within this file. // IntRegister(INT_GPIOQ1, UserButton2ISR); GPIOIntEnable(GPIO_PORTQ_BASE, GPIO_INT_PIN_1); IntEnable(INT_GPIOQ1); IntMasterEnable(); // // Configure Timer0B as a 16-bit periodic timer. // TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC); // // Set the Timer0B load value to 1ms. // TimerLoadSet(TIMER0_BASE, TIMER_A, ui32SysClock / 2); // // Enable processor interrupts. // IntMasterEnable(); // // Configure the Timer0B interrupt for timer timeout. // TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // // Enable the Timer0B interrupt on the processor (NVIC). // IntEnable(INT_TIMER0A); // // Initialize the interrupt counter. // g_ui32Counter = 0; // // Enable Timer0B. // TimerEnable(TIMER0_BASE, TIMER_A); // // Loop forever while the Timer0B runs. // while(1) { } }
好了、使用 main 创建了一个新工程。 编译正常、但在按下按钮时不闪烁 LED。 我确实看到示波器上的信号变为低电平、但 LED 没有闪烁
您要讨论哪个按钮? SW1还是 SW2?
我觉得你错了。 这两个 Launchpad 开关位于 PJ0和 PJ1上。 我使用 PQ1是因为您说 PQ1不能为您效劳。 在本示例中、您不能按 SW1或 SW2、因为我不在使用它们。 您可以使用蓝线在 PQ1和 GND 之间短接。 在 ISR 中放置一个断点。 当它运行时、每次 PQ1对地短路时、都会生成一个中断、并应在 PQ1 ISR 中的断点处停止、 ISR 中有代码用于缩短 LaunchPad 上 LED 的闪烁速率。
我有一个连接到 PQ1的简单按钮开关(主接头上的引脚53)。 我看到信号变为低电平、这样我就知道开关已连接。 但它不会命中断 PQ1 ISR 中的断点、并且没有 LED 闪烁。 我在 UserButton2ISR 中设置了断点、但未被命中。
我尝试使示例尽可能简单。 请参阅以下代码。 没有 LED。 如果生成了 PQ1中断、ISR 将仅增大变量 g_ui32Counter。 你为什么不试试呢? 我不使用任何开关。 我只需使用一根蓝线在 PQ1和接地引脚之间进行触摸即可。 由于我不实现去抖、因此 PQ1输入与 GND 之间的导线触控可以生成很多中断。 我想您是否遇到了硬件问题。 如果您有多个 LaunchPad、请尝试所有这些 LaunchPad。
#include <stdbool.h> #include <stdint.h> #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/sysctl.h" #include "driverlib/timer.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" #define USER_LED1 GPIO_PIN_0 #define USER_LED2 GPIO_PIN_1 uint32_t ui32SysClock; //***************************************************************************** // // Counter to count the number of interrupts that have been called. // //***************************************************************************** static volatile uint32_t g_ui32Counter = 0; //***************************************************************************** // // The interrupt handler for the Timer0 interrupt. // //***************************************************************************** void Timer0IntHandler(void) { } void UserButton2ISR (void) { GPIOIntClear(GPIO_PORTQ_BASE, GPIO_PIN_1); g_ui32Counter++; } //***************************************************************************** // // Configure Timer0B as a 16-bit periodic counter with an interrupt // every 1ms. // //***************************************************************************** int main(void) { // // Set the clocking to run directly from the external crystal/oscillator. // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the // crystal on your board. // ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_OSC), 25000000); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOQ)) { } GPIOPinTypeGPIOInput(GPIO_PORTQ_BASE, GPIO_PIN_1); GPIOPadConfigSet(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU); GPIOIntTypeSet(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_FALLING_EDGE); IntRegister(INT_GPIOQ1, UserButton2ISR); GPIOIntEnable(GPIO_PORTQ_BASE, GPIO_INT_PIN_1); IntEnable(INT_GPIOQ1); IntMasterEnable(); // // Initialize the interrupt counter. // g_ui32Counter = 0; // // Loop forever while the Timer0B runs. // while(1) { } }