主题 : MINI2440(S3C2440)串口接收中断只能进去一次,求教 复制链接 | 浏览器收藏 | 打印
面朝大海,春暖花开
级别: 新手上路
UID: 128049
精华: 0
发帖: 1
金钱: 5 两
威望: 1 点
贡献值: 0 点
综合积分: 2 分
注册时间: 2016-09-17
最后登录: 2016-09-17
楼主  发表于: 2016-09-17 14:51

 MINI2440(S3C2440)串口接收中断只能进去一次,求教

/*
各位大神,小弟初学ARM9嵌入式编程,想从逻辑程序开始,目前正在学习串口通讯编码。新建了一个工程,
想让PC机与开发板进行串口通讯,用的是UART0,采用非FIFO+中断模式,按照教材和实例初始化了各中断
寄存器、编写了中断服务函数。板子上电后等待PC机发送数据帧,收到后进行响应。运行结果是接收中断
只能响应一次,发送中断正常。各部分代码如下:
//*/
// 1、串口初始化函数:
// 注:
//(1)注释掉的那些寄存器配置不知道是不是一定要加上?
//(2)用的是非FIFO模式,希望通过中断来发送和接收
void Uart_RegInit(void)
{
    // configuration GPHCON to UART
    //rGPHCON = 0x00faaa;
    rGPHCON = rGPHCON & (~(0xf<<4));
    //rGPHUP = 0x7ff
    rGPHCON = rGPHCON | (0x0a<<4);

    // configuration UART0 communication register
    // 8-bits,1 stop bit, no parity
    rULCON0 = 0x03;
    rUCON0 = 0x05;

    // configuration UART baudrate
    rUBRDIV0 = (int)(PCLK/9600/16) -1;

    // clean interrupt bit
    rSUBSRCPND = rSUBSRCPND | (0x03);// 0x03:发送和接收 0x02:只能发送 0x01:只能接收
    rSRCPND = rSRCPND | (0x01<<28);
    rINTPND = rINTPND | (0x01<<28);
    // rINTMOD = rINTMOD & (~(0x01<<28));
    // rEINTPEND = rEINTPEND | (0x01<<28);
    // rEINTMASK = rEINTMASK & (~(0x01<<28)); // 0x03:发送和接收 0x02:只能发送 0x01:只能接收
    rINTSUBMSK = rINTSUBMSK & (~(0x03));// UART0总中断
    rINTMSK = rINTMSK & (~(0x01<<28));
}

// 2、串口中断函数:
// 注:
//(1)RunMode为在main.c中声明的全局变量,用于控制程序执行逻辑
//(2)我将接收中断和发送中断分开处理了
//(3)接收和发送我都用一个LED灯闪烁了一下
void __irq UART0_interrupt(void)
{
    // clean interrupt bit
    if(rSUBSRCPND & 0x01)// 接收中断
    {
        RunMode = 1; // 此处置为1,在main中将程序引导至接收函数Uart_Recv_Byte()
        LedModule_TurnOnLed03();
        MainModule_Delay(5);
        LedModule_TurnOffLed03();
        // 0x03:发送和接收  0x02:只能发送  0x01:只能接收
        rSUBSRCPND = rSUBSRCPND | (0x01);
        // 0x03:发送和接收  0x02:只能发送  0x01:只能接收
        rINTSUBMSK = rINTSUBMSK & (~(0x01));
}
    else if(rSUBSRCPND & 0x02)// 发送中断
    {
        LedModule_TurnOnLed04();
        MainModule_Delay(5);
        LedModule_TurnOffLed04();
        // 0x03:发送和接收  0x02:只能发送  0x01:只能接收
        rSUBSRCPND = rSUBSRCPND | (0x02);
        // 0x03:发送和接收  0x02:只能发送  0x01:只能接收
        rINTSUBMSK = rINTSUBMSK & (~(0x02));
    }
    else
    {
        // 0x03:发送和接收  0x02:只能发送  0x01:只能接收
        RunMode = 1; rSUBSRCPND = rSUBSRCPND | (0x03);
        // 0x03:发送和接收  0x02:只能发送  0x01:只能接收
        rINTSUBMSK = rINTSUBMSK & (~(0x03));
    }
    rSRCPND = rSRCPND | (0x01<<28);
    rINTPND = rINTPND | (0x01<<28);
    //rINTMOD = rINTMOD & (~(0x01<<28));
    //rEINTPEND = rEINTPEND | (0x01<<28);
    //rEINTMASK = rEINTMASK & (~(0x01<<28));
    rINTMSK = rINTMSK & (~(0x01<<28));
}

// 3、main.c中的初始化函数:
void MainModule_Init(void)
{
    MMU_Init();
    MainModule_SetCpuClk();
    MainModule_SetBusClk();
    Uart_RegInit();
    LedModule_LedXXInit();
    MainModule_Timer4Init();
    // 串口通讯中断入口
    pISR_UART0 = (U32)UART0_interrupt;
    // 定时器4中断入口
    pISR_TIMER4 = (U32)Timer4_interrupt;
}

// 4、main函数:
void Main(void)
{
    int i=0;
    int cnt=0;// 用来限制发送中断执行次数
    MainModule_Init();
    while(1)
    {
        // 此处应该使用switch,因为功能比较少,懒得编,就先用if凑合着用
        // 接收中断发生后,程序会执行到此处,Uart_recv_Byte()用于将数据保存下来
        if (RunMode == 1)
        {
            Uart_Recv_Byte();
            RunMode = 2;
        }
        else if (RunMode == 2)// 数据保存完毕后,原封不动的又发送给pc机
        {
            Uart_Send_Byte(cnt);
            Uart_Send_Byte(0xFF);
            for (i=0; i<RxBufPtr; i++)
                Uart_Send_Byte(RxDataBuf);
            cnt++;
            if (cnt<10)// 限制发送10次,不要一直发一直发
                RunMode = 2;
            else
                RunMode = 0;
        }
        else
            ;
        // 在没有接收和发送时,led01一直闪烁,模拟主程序一直在运行其他功能
        LedModule_TurnOnLed01();
        MainModule_Delay(1000);
        LedModule_TurnOffLed01();
        MainModule_Delay(1000);
    }
}

// 运行现象总结:

//(1)最初,我将Uart_Recv_Byte()放在中断函数UART0_interrupt()中,也没有区分接收和发送,并且在
// Uart_Recv_Byte()中直接调用Uart_Send_Byte(),意思就是收到PC机发来的数据帧以后立马就响应回去。
// 运行结果是板子上电,led01一直闪烁,led02(使用Timer4中断控制)一直闪烁,此时,板子运行正常。
// 当我从PC机上向开发板发送一帧数据帧后,开发板立刻进行了响应,返回了我刚发下去的数据,但是,此
// 时,问题来了,led01和led02都不再闪烁了,此后PC机和开发板还是可以继续通讯,没有问题,但是led01
// 和led02就永远也没有闪烁了。在网上找了好多帖子,可能是进入UART0_interrupt()后就一直没有恢复现
// 场,所以
//     LedModule_TurnOnLed01();
//     MainModule_Delay(1000);
//     LedModule_TurnOffLed01();
//     MainModule_Delay(1000);
// 这段代码和Timer4_interrupt()也都没有再执行。是不是这个原因我也无法确定。

// (2)后来,将Uart_Send_Byte()从Uart_Recv_Byte()中取出来,并且将Uart_Recv_Byte()从
// UART0_interrupt()中取出来,就是上面代码的样子,并且在main_init中将RunMode直接置为2,板子一上
// 电就开始按照设计发送10次数据,然后停止,led01和led02也都正常闪烁。我觉得这个可以说明发送中断
// 确实产生了,而且成功恢复了现场,发送完成后,main中该干啥继续干啥。

// (3)第三阶段,将RunMode置
// 为0,Main函数中就只驱动Led01,Timer04驱动led02,两个灯一直闪烁,没有问题。然后我让PC发送一帧
// 数据,led03闪烁了一下,说明进入了接收中断,然后按照程序设计转到RunMode=2,发送10次数据,此时
// led04也闪烁了,都是正常的,10次发送完成后,led01和led02继续闪烁,没有问题,可是再从PC发送一帧
// 数据下来,接收中断就再也没进去过,main中该干嘛还是继续干嘛,代码就是上面贴出来的样子。

// 反复运行了很多次,并在网上查了很多网友发的帖子,我觉得我的寄存器配置应该没有错,心里一直在思
// 考是不是串口中断属于外部中断,所以还有其他的寄存器没有清,否则为什么只能进一次接收中断呢?其
// 实实现串口发送/接收只是第一步,下一步我想使用Timer4进行接收完成判断。请问各位大神,为什么接收
// 中断就只进去了一次呢?我的代码还有哪里不对?