原创 LPC2103的UART0通信(中断方式)_有很大问题

2010-5-8 01:04 5989 9 9 分类: MCU/ 嵌入式

本以为写过了查询方式,又有ZLG的代码,测试下应该没有什么问题,不过真的是问题多多啊,很多没有弄明白的地方。


还是用KEIL FOR ARM,器件,环境选择如下




 

然后用KEIL给的模板,把ZLG 《深入浅出ARM7-LPC213X...》的程序敲进去,略微改动,

 

#include <LPC21xx.H>              /* LPC21xx definitions                      */

#include "Main.h"      //包含数据类型定义

/*定义串口模式设置数据结构*/
typedef struct UartMode
{
 UINT8 datab;   //字长度,5/6/7/8可选
 UINT8 stopb;   //停止位,1/2可选
 UINT8 parity;   //奇偶校验位,0;无校验;1:奇校验;2:偶校验
}UARTMODE;

UINT8 rcv_buf[8];   // UART0 数据接收缓冲区
volatile UINT8 rcv_new;  // 接受新数据标志


/*********************************************************************************************************
**    函数名称: IRQ_UART0()
**    函数功能: 串口0接受中断服务程序
**    入口参数: 无
**    出口参数: 无
********************************************************************************************************/

void __irq IRQ_UART0(void)
{
 UINT8 i;

 if((U0IIR & 0x0f) == 0x04)
  rcv_new = 1;      //设置接收到新的数据标志

 for(i=0; i<8; i++)      //FIFO使能时设为8字节长度
 {
  rcv_buf = U0RBR;     //读取FIFO的数据,并清除中断
 }
 VICVectAddr = 0x00;      // 中断处理结束
}

/*********************************************************************************************************
**    函数名称: UART0_SendByte()
**    函数功能: 向串口0发送1字节数据
**    入口参数: dat  要发送的数据
**    出口参数: 无
********************************************************************************************************/
 
void UART0_SendByte(UINT8 dat)
{
 U0THR = dat;   //要发送的数据
 


/*********************************************************************************************************
**    函数名称: UART0_SendBuf()
**    函数功能: 向串口0发送8字节数据
**    入口参数: 无
**    出口参数: 无
**********************************************************************************************************/
 
void UART0_SendBuf(void)
{
 UINT8 i;
 
 for(i=0; i<8; i++) 
  UART0_SendByte(rcv_buf);
 while((U0LSR & 0x20) == 0);   //等待数据发送完毕
}

/*********************************************************************************************************
**    函数名称: UART0_Init()
**    函数功能: 串口初始化,设置工作模式和波特率
**    入口参数: baud 波特率
     set  模式设置(UARTMODE 数据结构) 
**    出口参数: 1为初始化成功,0为初始化失败
**********************************************************************************************************/

UINT8 UART0_Init(UINT32 baud, UARTMODE set)
{
 UINT32 bak;
 
 /* 参数过滤 */
 if((baud == 0) || (baud > 115200))
  return 0;
 if((set.datab < 5) || (set.datab > 8))
  return 0;
 if((set.stopb == 0) || (set.stopb > 2))
  return 0;
 if((set.parity > 4))
  return 0;
  
 // 设置串口波特率
 U0LCR = 0x80;      // DLAB = 1 
 bak   = (Fpclk >> 4) / baud;
 U0DLM = bak >> 8;
 U0DLL = bak & 0xFF;    // DLAB = 0
 
 // 设置串口模式     //已在U0LCR中设置 
 bak   = set.datab - 5;    // 设置字长
 if (set.stopb == 2) bak |= 0x04; // 判断是否为2位停止位
 
 if (set.parity != 0)
 {
  set.parity = set.parity - 1;
  bak |= 0x08;
 }
 bak |= set.parity << 4;    // 设置奇偶校验
 
 U0LCR = bak;
 
 return(1);
}

/*********************************************************************************************************
**    函数名称: main()
**    函数功能: 从串口 UART0 接受字符串,并发送回上位机显示
**    调试说明: 需要 PC 串口显示终端软件
**********************************************************************************************************/

 int main (void)
{
 
 UARTMODE set;

 set.datab = 8;
 set.stopb = 1;
 set.parity = 0;
 
 rcv_new = 0;
 
 PINSEL0 = (PINSEL0 & (~0x0f)) | 0x05;  //设置IO为UART0 
 
 UART0_Init(UART_BPS,set);   //串口初始化
 U0FCR = 0x81;     //使能 FIFO,并设置出发点为8字节
 U0IER = 0x01;     //允许 RBR 中断,即接受中断

 IRQEnable();     //使能IRQ 中断,此函数在ZLG的lpc2131模版中

 /*使能 UART0 中断*/
 VICIntSelect = 0x00000000;  //设置所有的通道为 IRQ 中断
 VICVectCntl0 = 0x20 | 0x06;  // UART0 分配到IRQ slot0,即最高优先级
 
 VICVectAddr0 = (UINT32)IRQ_UART0; //设置UART0 向量地址
 VICIntEnable = 1 << 0x06;   //使能UART0 中断
 
 while(1)
 {
  if (rcv_new == 1)   //如果有新数据
  {
   rcv_new = 0;   //清除标志,以接受新数据
   UART0_SendBuf();   
  }

 }
// return 0;
}
/*********************************************************************************************************
**                            End Of File
********************************************************************************************************/

编译时首先发现    //使能IRQ 中断 这里有错误,原来这是ZLG在ADS的LPC2131模板中的一个宏定义,但是KEIL下没有,要自己写。翻书在中断那一章中发现有这么一句话“设置 CPSR 寄存器的I位或者F位,需要在特权模式下,可在启动代码中设置
在startup.s中将
 MSR CPSR_c, # 0xdf;
 LDR SP, =StackUsr
中的 0xdf 改为 0x5f

发现这也是根据ADS中的LPC2100模板说的,KEIL的模板不一样,试图去改也没有成功,把IRQEnable();  注释掉可以编译成功,但是结果是只能收发一个字节的数据,应该是没有开IRQ的中断。

(其实是波特率不对!,不要做下面的更改,误导了,当时以为是正确的)

所以找了ZLG的LPC2131模板,把其中startup.s中的

SoftwareInterrupt   
;        B       SoftwareInterrupt
;//增加开/关中断处理 Chenxibing-2004-02-09                                
        CMP     R0, #4
        LDRLO   PC, [PC, R0, LSL #2]
        MOVS    PC, LR

SwiFunction
        DCD     IRQDisable       ;0
        DCD     IRQEnable        ;1
        DCD  FIQDisable   ;2
        DCD  FIQEnable   ;3

IRQDisable
        ;关IRQ中断
        MRS     R0, SPSR
        ORR     R0, R0, #NoInt
        MSR     SPSR_c, R0
        MOVS    PC, LR

IRQEnable
        ;开IRQ中断
        MRS   R0, SPSR
        BIC   R0, R0, #NoInt
        MSR   SPSR_c, R0
        MOVS    PC, LR
       
FIQDisable
        ;关FIQ中断
        MRS     R0, SPSR
        ORR     R0, R0, #NoFIQ
        MSR     SPSR_c, R0
        MOVS    PC, LR

FIQEnable
        ;开FIQ中断
        MRS   R0, SPSR
        BIC   R0, R0, #NoFIQ
        MSR   SPSR_c, R0
        MOVS    PC, LR
;// Changed 2004-12-09

 

加入到KEIL的startup.s的

; Initialise Interrupt System
;  ...

处,

然后再把ADS模板中target.h中的

__swi(0x00) void SwiHandle1(int Handle);

#define IRQDisable() SwiHandle1(0)
#define IRQEnable() SwiHandle1(1)
#define FIQDisable() SwiHandle1(2)
#define FIQEnable() SwiHandle1(3)

加入到KEIL工程中的头文件中,

 

 

再编译可以,下载到板子上,reset,发 12345678  8个字符的字符串,发了三次用串口助手可以自收发了,如图,红线划得部分.

但是却有一个大大的问题想不通!!!大约过了15秒,没有任何操作,会自动的收到一些码。这之后再发数据就收不到任何数据了。期待解答啊。。。



 

15秒对ARM来说应该是个很漫长的过程啊,为什么这么久才出错?

(这个问题依然未知,但是此程序的PLL频率和波特率都不停变化,可能是原因)
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
9
关闭 站长推荐上一条 /3 下一条