打印
[NUC120]

NUC140 (cortex M0)中断是怎样执行的?原理是什么?

[复制链接]
7818|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
shudaixiongabc|  楼主 | 2011-12-1 22:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 缥缈九哥 于 2012-9-14 12:20 编辑

菜鸟学习NUC140。买了块开发板,其中一个例程如下:
#include <stdio.h>
#include "NUC1xx.h"
#include "DrvGPIO.h"
#include "DrvUART.h"
#include "DrvSYS.h"

void GPABCallback(uint32_t u32GpaStatus, uint32_t u32GpbStatus)
{
    printf("GPAB Interrupt! GPA:0x%04x  GPB:0x%04x\n", u32GpaStatus, u32GpbStatus);
    /* Toggle LED */
    outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->;PIN) ^ (1 << 7));
}
void GPCDECallback(uint32_t u32GpcStatus, uint32_t u32GpdStatus, uint32_t u32GpeStatus)
{
    printf("GPCDE Interrupt! GPC:0x%04x  GPD:0x%04x  GPE:0x%04x\n", u32GpcStatus, u32GpdStatus, u32GpeStatus);

    /* Toggle LED (GPA7) */
    outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->;PIN) ^ (1 << 7));
}
void EINT0Callback(void)
{
    printf("EINT0 Interrupt!\n");
   
    /* Toggle LED (GPA7) */
    outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->;PIN) ^ (1 << 7));
}
void EINT1Callback(void)
{
    printf("EINT1 Interrupt!\n");
   
    /* Toggle LED (GPA7) */
    outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->;PIN) ^ (1 << 7));
}
void Delay1ms(int delay1msdata)
{
int i,j,k;
for(i=0;i<delay1msdata;i++)
  for(j=0;j<75;j++)
   for(k=0;k<10;k++)
    ;
}
/*---------------------------------------------------------------------------------------------------------*/
/* MAIN function                                                                                          */
/*---------------------------------------------------------------------------------------------------------*/   
int main (void)
{
STR_UART_T param;
UNLOCKREG();
    SYSCLK->;PWRCON.XTL12M_EN = 1;
    /* Waiting for 12M Xtal stalble */
    DrvSYS_Delay(5000);
DrvGPIO_InitFunction(FUNC_UART0);

    param.u32BaudRate        = 115200;
    param.u8cDataBits        = DRVUART_DATABITS_8;//8位数据位
    param.u8cStopBits        = DRVUART_STOPBITS_1;//1位停止位
    param.u8cParity          = DRVUART_PARITY_NONE; //校验位
    param.u8cRxTriggerLevel  = DRVUART_FIFO_1BYTES;// FIFO存储深度 1 字节
    param.u8TimeOut          = 0; //   FIFO超时设定
    DrvUART_Open(UART_PORT0, ¶m);  // The function is used to initialize UART. It consists of baud-rate, parity, data-bits,     */
              // stop-bits, rx-trigger-level and timeout interval settings.
   
printf("\n\n");
    printf("+-------------------------------------------------------------------+\n");
    printf("|                      GPIO Driver Sample Code                      |\n");
    printf("+-------------------------------------------------------------------+\n");
/*---------------------------------------------------------------------------------------------------------*/
/* GPIO Interrupt Test                                                                                     */
/*---------------------------------------------------------------------------------------------------------*/   
   
    printf("\n  GPB13, GPC0, GPB14 and GPB15 are used to test key interrupt\n  and control LED (GPA7)\n");   
    /* Configure GPA7 for LED control */
    DrvGPIO_Open(GPA, 7, IO_OUTPUT);
    /* Configure general GPIO interrupt */
    DrvGPIO_Open(GPB, 13, IO_INPUT);

    /* The Quasi-bidirection mode could be used as input with pull up enable */
    DrvGPIO_Open(GPC, 0, IO_QUASI);
    DrvGPIO_SetIntCallback(GPABCallback, GPCDECallback);
    DrvGPIO_EnableInt(GPB, 13, IO_RISING, MODE_EDGE);     /* IO_FALLING means low level trigger if it is in level trigger mode */
    DrvGPIO_EnableInt(GPC, 0, IO_FALLING, MODE_LEVEL);

    DrvGPIO_SetDebounceTime(3, DBCLKSRC_HCLK); .   
    DrvGPIO_EnableDebounce(GPB, 13);  
    DrvGPIO_EnableDebounce(GPC, 0);
   
    /* Configure external interrupt */
    DrvGPIO_EnableEINT0(IO_FALLING, MODE_EDGE, EINT0Callback);        
    DrvGPIO_EnableEINT1(IO_BOTH_EDGE, MODE_EDGE, EINT1Callback);
    /* Waiting for interrupts */
    printf("  GPIO Input/Output test ................................ ");
DrvGPIO_Open(GPA,1, IO_OUTPUT);
DrvGPIO_Open(GPA,2, IO_OUTPUT);
DrvGPIO_Open(GPA,3, IO_OUTPUT);
    while(1)
{
  DrvGPIO_SetBit(GPA,1);
  DrvGPIO_SetBit(GPA,2);
  DrvGPIO_SetBit(GPA,3);
  Delay1ms(2000);
  DrvGPIO_ClrBit(GPA,1);
  DrvGPIO_ClrBit(GPA,2);
  DrvGPIO_ClrBit(GPA,3);
  Delay1ms(2000);
}
}



原理图是GPA1 GPA2 GPA3 分别接的3个led, GPB15接一个按键。GPA7什么都没接,没有什么LED灯,(估计是另外板子的例程)GPB13 和GPC0也什么都没接。见附件电路图。

现在程序运行时,结果如下:
+-------------------------------------------------------------------+
|                      GPIO Driver Sample Code                      |
+-------------------------------------------------------------------+
  GPB13, GPC0, GPB14 and GPB15 are used to test key interrupt
  and control LED (GPA7)
EINT1 Interrupt!EINT1 Interrupt!EINT1 Interrupt!EINT1 Interrupt!EINT1 Interrupt!(程序已开始运行就不停输出EINT1 Interrupt!EINT1 Interrupt!
EINT1 Interrupt!

第一次按键时,屏幕上的EINT1 Interrupt!停住,
3个LED灯闪烁,并出现“GPIO Input/Output test ................................ ”)
GPIO Input/Output test ................................

当放手后LED灯不再闪烁,继续出现EINT1 Interrupt!EINT1 Interrupt!EINT1 Interrupt!
以后每次按键或弹起的时候EINT1 Interrupt!又停止了,灯又开始闪烁,但不会出现GPIO Input/Output test ................................ 这句话。偶尔极少数时候按键或弹起的时候又会出现GPAB Interrupt! GPA:0x0000  GPB:0x2000这句话。为什么会是这个结果呀?

   其中 DrvGPIO_SetIntCallback函数定义如下:
void DrvGPIO_SetIntCallback(GPIO_GPAB_CALLBACK pfGPABCallback, GPIO_GPCDE_CALLBACK pfGPCDECallback)
{
    _pfGPABCallback  = (void (*)(uint32_t, uint32_t))pfGPABCallback;
    _pfGPCDECallback = (void (*)(uint32_t, uint32_t, uint32_t))pfGPCDECallback;   
}

现在有如下几个问题:
1.DrvGPIO_SetIntCallback 函数还有GPABCallback函数到底是干嘛用的呢?
按照我读程序的理解,程序从main函数开始执行。在执行了DrvGPIO_SetIntCallback(GPABCallback, GPCDECallback);这句话之后就应该去执行void GPABCallback和void GPDCECallback这两个回调函数,就应该在屏幕上输出GPAB Interrupt! GPA:0x%04x  GPB:0x%04x\n  然后输出GPCDE Interrupt! GPC:0x%04x  GPD:0x%04x  GPE:0x%04x\n。可是为什么程序中都没有输出呢?这个DrvGPIO_SetIntCallback 函数还有GPABCallback函数到底是干嘛用的呢?
2.然后执行到DrvGPIO_EnableEINT1(IO_BOTH_EDGE, MODE_EDGE, EINT1Callback);这句话时,使能了EINT1的中断。之后程序就停在那里了吗?为什么不继续往下执行printf("  GPIO Input/Output test ................................ "); 这句以及后面的while(1)中的灯闪烁的程序呢
3.按照我的理解使能EINT1的中断后,要按键触发才会执行中断程序EINT1Callback输出EINT1 Interrupt呀?为什么没按键的时候程序一运行就一直不停输出EINT1 Interrupt呢?
4.灯闪烁这个程序不是应该写在EINT1Callback这个中断程序中吗?当进入中断的时候灯才闪烁,执行完中断程序后又继续执行原来的程序,然后灯停止闪烁。不是应该这样吗?

这些问题困扰我好多天了,一直没搞懂,希望高手帮忙。说说程序执行的过程。解答下以上几个问题。不甚感激。

Mini-NUC140-V2.0.pdf

51.46 KB

相关帖子

板凳
hotpower| | 2011-12-2 08:40 | 只看该作者
不断中断应该是在中断中未清除标志导致不断中断。

使用特权

评论回复
地板
hotpower| | 2011-12-2 08:58 | 只看该作者
回调函数说穿了就是在中断服务程序例程isr里放置一个用户函数指针。isr里测试这个函数指针,非空就运行,空就不运行。
为何要如此?拿村里的一句俗话就是:“脱裤子放屁,多此一举”,是吗?
非也,是也。
在mcu编程中,我们一般都是在中断向量表中填写isr地址,在isr内添加用户中断服务程序。
故一般都要动启动代码文件,而这些大都是汇编文件。
如此这般每个用户程序的启动代码都不会相同。当然你可以用系统默认的isr名称,这样就不会动启动代码。
为了省略这些,引入了回调函数,系统事先编写好通用的isr,用于只要设置即安装回调函数即可,而且可以动态卸载,即将回调函数指针清空。
这样就增加了灵活性和通用性,用户就不需要明白中断向量号等有关涉及硬件的知识了。
用户做的只是安装或卸载回调即可。
把精力放在如何写好回调函数即自己的普通函数即可。

使用特权

评论回复
5
缥缈九哥| | 2011-12-2 21:46 | 只看该作者
顶起再说

使用特权

评论回复
6
fallalee| | 2013-8-6 12:22 | 只看该作者
本帖最后由 fallalee 于 2013-8-6 14:16 编辑

关于第1个问题:DrvGPIO_SetIntCallback函数还有GPABCallback函数到底是干嘛用
的呢?

我的认为是:
1.DrvGPIO_SetIntCallback(GPABCallback, GPCDECallback)函数是用来设定当有一般的GPIO(包含PA,PB,PC,PD,PE)中断发生时,需要去执行的中断副(回调)程序;只是PA,PB的中断会执行GPABCallback副程序;PC ,PD,PE的中断会执行GPCDECallback副程序.

2. 可能没加上NVIC_ClearPendingIRQ函数;所以当离开中断服务程序时,按键可能还没有松开,会再次进入中断服务程序。到松开为止,可能会产生多次的中断。

刚在学习,不知道这样讲对不对...

使用特权

评论回复
7
ceflsh| | 2013-8-15 20:14 | 只看该作者
学习了,顶一下。

使用特权

评论回复
8
RF-7| | 2013-8-15 22:58 | 只看该作者
没关注过这个厂家的,不懂。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

8

帖子

1

粉丝