【问题标题】:How do you exit an interrupt routine and go back to main?如何退出中断程序并返回主程序?
【发布时间】:2018-10-25 04:02:20
【问题描述】:

我正在使用带有 Keil uVision IDE 的 Tiva C 系列开发板。我基本上是在尝试使用中断执行以下操作:

如果未按下开关 1 和开关 2:红色 LED 闪烁。 如果按下开关 1,则进入中断程序并闪烁绿色 LED。

一旦释放开关 1,重新进入主电源以继续闪烁红色 LED。

在下降沿触发时进入中断服务程序。我知道我需要在上升沿触发时以某种方式返回 main,但是我不确定如何执行此操作。

我试图尽我所能发表评论,所以这是我到目前为止的评论:

#include <stdint.h>
#include <stdbool.h>
#include "Final Project.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"

#include "inc/tm4c123gh6pm.h"       // manually added by the programmer
#include "driverlib/interrupt.h"    // manually added by the programmer


// Interrupt handler
void GPIOPortF_Handler(void)
    {
        // acknowledge flag for PF0
        GPIO_PORTF_ICR_R |= 0x01;   

        // Switch 1 is pressed
        if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4)==0x00)
        {
            // turn off red LED
            GPIO_PORTF_DATA_R &= ~0x02;
            // turn off blue LED
            GPIO_PORTF_DATA_R &= ~0x04;

            // while switch 1 is pressed
            while(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4)==0x00)
            {
                // Turn on green LED
                GPIO_PORTF_DATA_R |= 0x08;
                // Delay
                SysCtlDelay(16000000/3/2);
                // Turn off green LED
                GPIO_PORTF_DATA_R &= ~0x08;
                // Delay
                SysCtlDelay(16000000/3/2);
            }
        }
    }

    void Interrupt_Init(void)
{
    NVIC_EN0_R |= 0x40000000;           // enable interrupt 30 in NVIC (GPIOF)
    NVIC_PRI7_R &= ~0x00E00000;     // configure GPIOF interru  
    GPIO_PORTF_IM_R |= 0x01;            // arm interrupt on PF0
    GPIO_PORTF_IS_R &= ~0x01;           // PF0 is edge-sensitive
    GPIO_PORTF_IBE_R |= 0x01;           // PF0 both edges trigger
    //GPIO_PORTF_IEV_R &= ~0x01;    // PF0 falling edge event
    //IntGlobalEnable();                    // Globally enable interrupt (without PinMux)
    IntMasterEnable();                      // Globally enable interrupt (with PinMux)
}


void
PortFunctionInit(void)
{
    // Enable Peripheral Clocks 
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    // Enable pin PD1 for GPIOInput
    GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_1);

    // Enable pin PD0 for GPIOOutput
    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0);

    // Enable pin PF2 for GPIOOutput
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);

    // Enable pin PF3 for GPIOOutput
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);

    // Enable pin PF0 for GPIOInput
        GPIO_PORTF_PUR_R |= 0x01; 

    // Enable pin PF4 for GPIOInput
        GPIO_PORTF_PUR_R |= 0x10; 

    //First open the lock and select the bits we want to modify in the GPIO commit register.
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0x1;

    //Now modify the configuration of the pins that we unlocked.
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_0);

    // Enable pin PF1 for GPIOOutput
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);

    // Enable pin PF4 for GPIOInput
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
}


int main(void)
{

        // Iinitialize the GPIO ports   
        PortFunctionInit();
        // Configure the GPIOF interrupt
        Interrupt_Init();


    // Loop forever.
    while(1)
    {
            // Turn on red lED
            GPIO_PORTF_DATA_R |= 0x02;
            // Delay
            SysCtlDelay(16000000/3/2);
            // Turn off red lED
            GPIO_PORTF_DATA_R &= ~0x02;
            // Delay
            SysCtlDelay(16000000/3/2);
    }

}

【问题讨论】:

    标签: c


    【解决方案1】:
    1. 在中断处理程序GPIOPortF_Handler 中有一个延迟函数是一个非常糟糕的主意。

    2. 此外,您在中断处理程序中有一个 while 循环等待用户输入。

    上面的问题是中断有一段时间不会退出。一个好的设计可以确保中断上下文只运行很短的时间并退出。这允许注册其他中断。

    我建议你在中断处理程序中设置一个 volatile 标志并检查main 中的标志。根据此标志,您可以采取适当的措施。

    下面是一个简单的例子。

    void GPIOPortF_Handler(void)
    {
        GPIO_PORTF_ICR_R |= 0x01;   
        flags = 1;
    } 
    

    在主函数中,

    int main(void) 
    {
        while(1) 
        {   
            if(flags==1)
            { 
                GPIO_PORTF_DATA_R |= 0x02; 
                SysCtlDelay(16000000/4); 
                GPIO_PORTF_DATA_R &= ~0x02; 
                SysCtlDelay(16000000/4); 
            } 
            else
            { 
                // Turn on red lED
                GPIO_PORTF_DATA_R |= 0x02;
                // Delay
                SysCtlDelay(16000000/4);
                // Turn off red lED
                GPIO_PORTF_DATA_R &= ~0x02;
                // Delay
                SysCtlDelay(16000000/4);
            }
    
            /* Check status of switch */
            if ( /* enter switch port here */ == 0)
            {
                GPIO_PORTF_DATA_R &= ~0x02; /* make green LED OFF */
                flags = 0;
            }
        }
    }
    

    请注意,此示例确实有一些缺点,并且需要一些时间来检测密钥。根据SysCtlDelay 的时间,它可能是可以接受的。

    【讨论】:

    • 谢谢。当按下开关 1 时,在我的中断处理程序中,flags = 1。在 main 中,我有 if(flags==1){flash green LED}。我可以进入中断处理程序,但我仍然不确定如何返回主函数。你建议我如何进行?
    • 您应该在主函数中完成所有处理。中断处理程序应该运行很短的时间(大约 10 或 100 微秒)。您永远不会知道中断何时发生,但在主循环中,您会看到标志为 1。
    • 这是有道理的。我将如何让中断处理程序运行很短的时间?我知道设置 flags = 1 将使中断处理程序在程序期间保持打开状态,但我不确定使中断处理程序运行更短时间的不同方法。对于我缺乏编程技能,我深表歉意。
    • 如原始答案中所述,从 IRQ 处理程序中删除延迟函数和阻塞循环。然后处理程序将退出。通过阻塞循环,我的意思是循环等待用户输入。所有这些都应该移到 main 函数中。
    • 抱歉不清楚。我做了以下事情: void GPIOPortF_Handler(void){GPIO_PORTF_ICR_R |= 0x01; flags = 1;} 然后在主函数中我有以下内容: int main(void) {while(1) { if(flags==1){ GPIO_PORTF_DATA_R |= 0x02; SysCtlDelay(16000000/3/2); GPIO_PORTF_DATA_R &= ~0x02; SysCtlDelay(16000000/3/2); } if(flags!=1){ GPIO_PORTF_DATA_R &= ~0x02; } 抱歉格式化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 1970-01-01
    • 2022-01-12
    • 2018-06-18
    • 1970-01-01
    相关资源
    最近更新 更多