UART串口软件接口的设计与分析

在利用UART进行数据操作之前,先来了解UART的操作过程是怎样的。

(1)设置I/O连接到UART。

(2)设置串口波特率。

(3)发送或接收数据。

(4)检查串口状态字或等待串口中断。

关于串口的操作主要由以下几个函数来实现。

1.串口初始化函数UARTInit(uint32_t baudrate)

UARTInit函数根据从主程序传递的参数——波特率对串口进行初始化,包括对数据传输格式的设置,FIFO的设置等。程序源码如下所示:

void UARTInit(uint32_t baudrate)
{
  uint32_t Fdiv;
  uint32_t regVal;

  UARTTxEmpty = 1;
  UARTCount = 0;
 
  NVIC_DisableIRQ(UART_IRQn);          //关闭外部扩展中断

  LPC_IOCON->PIO1_6 &= ~0x07;   
  LPC_IOCON->PIO1_6 |= 0x01;       /* 选择为UART RXD功能 */
  LPC_IOCON->PIO1_7 &= ~0x07; 
  LPC_IOCON->PIO1_7 |= 0x01;       /* 选择为UART TXD功能 */

           /*使能UART的时钟*/
  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
  LPC_SYSCON->UARTCLKDIV = 0x1;      /* divided by 1 */

  LPC_UART->LCR = 0x83;              /* 设置数据格式,8位,无校验,一个停止位 */
  regVal = LPC_SYSCON->UARTCLKDIV;
  Fdiv = ((SystemAHBFrequency/regVal)/16)/baudrate ; 

  LPC_UART->DLM = Fdiv / 256;       
  LPC_UART->DLL = Fdiv % 256;
  LPC_UART->LCR = 0x03;
  LPC_UART->FCR = 0x07;    //清除FIFO中的所有字节 

  /* 通过读操作清除状态*/
  regVal = LPC_UART->LSR;

  /* 确保在开始之前清空寄存器 */
  while (( LPC_UART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );
  while ( LPC_UART->LSR & LSR_RDR )
  {
 regVal = LPC_UART->RBR; /* Dump data from RX FIFO */
  }
 
  /* 使能UART中断*/
  NVIC_EnableIRQ(UART_IRQn);      

#if TX_INTERRUPT
  LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS;
#else
  LPC_UART->IER = IER_RBR | IER_RLS; 
#endif
  return;
}


根据上面的程序来分析,可以得到关于UART的最基本的一个配置流程:

(1)在UART的时钟使能之前需要在IOCONFIG寄存器模块中配置UART的引脚,即UART RXD与UART TXD。

(2)使能UART的时钟。

(3)使能UART外设时钟。

只有当这些都设置好之后,接在UART上面的外设才能进行下一步的操作。在这些设置好之后,在进行数据传输之前,需要对数据的格式进行定义,比如说,在这里定义的被传输的数据格式为:8个数据位、一个停止位、无奇偶校验。然后再进行缓冲区的清空操作,使能中断就可以了。

2.UART中断处理函数UART_IRQHandler(void)

UART_IRQHandle函数用于在发生UART中断时,对不同的中断源进行相应的中断处理。可配置的中断类型为IIR_RDA、IIR_CTI、IIR_THRE等,对应的中断类型奇偶校验错误、传输数据寄存器空、传输完成中断、接收数据准备好、检测到Edle、打断标志、CTS标志等。程序源码如下所示:


void UART_IRQHandler(void)
{
  uint8_t IIRValue, LSRValue;
  uint8_t Dummy = Dummy;

  IIRValue = LPC_UART->IIR;
   
  IIRValue >>= 1;    /* 跳过请求位*/
  IIRValue &= 0x07;    /* 将中断的类型提取出来*/
  if (IIRValue == IIR_RLS)  /* 中断类型是RLS */
  {
    LSRValue = LPC_UART->LSR;
    /* 判断错误的类型 */
    if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI))
    {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      UARTStatus = LSRValue;
      Dummy = LPC_UART->RBR;   /* 读出接收缓冲区的数据*/
      return;
    }
    if (LSRValue & LSR_RDR)   /* 如果中断类型是RDR */   
    {
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* 读出数据并清空中断*/
      UARTBuffer[UARTCount++] = LPC_UART->RBR;
      if (UARTCount >= UART0_RBUF_SIZE)
      {
        UARTCount = 0;    /*缓冲区溢出 */
      } 
    }
  }
  else if (IIRValue == IIR_RDA)  /*如果有数据*/
  {
    UARTBuffer[UARTCount++] = LPC_UART->RBR;
    if (UARTCount >= UART0_RBUF_SIZE)
    {
      UARTCount = 0;     /*数据溢出 */
    }
  }
  else if (IIRValue == IIR_CTI)  /*超时 */
  {
    /* Character Time-out indicator */
    UARTStatus |= 0x100;    /* Bit 9 as the CTI error */
  }
  else if (IIRValue == IIR_THRE)  /*发送保持寄存器为空时*/
  {
    /* THRE interrupt */
    LSRValue = LPC_UART->LSR;   /* 查看THR寄存器中是否合法的数据*/
    if (LSRValue & LSR_THRE)        /*如果为空,则设置相应的变量*/
    {
      UARTTxEmpty = 1;
    }
    else
    {
      UARTTxEmpty = 0;
    }
  }
  return;
}


上面的中断处理函数中,首先将中断ID寄存器中的内容读出来,然后将其右移一位,忽略掉最低位——中断状态位,这样就取得了中断ID号,然后根据ID号对应的不同中断执行不同的操作。例如,当程序中产生了“接收数据可获得”中断的时候,则会通过UARTBuffer[UARTCount++] = LPC_UART->RBR语句将接收缓冲寄存器中的内容存到buffer中。同时,在读取接收缓冲寄存器中的内容时,中断也将会被自动地清除。

3.数据发送函数UARTSend(uint8_t *BufferPtr, uint32_t Length)

UARTSend函数可用来向UART口发送数据。串口发送数据的方式就是当串口准备好发送数据后,直接向发送保持寄存器写数据。下面的程序中直接操作串口的发送保持寄存器进行数据的传输。



void UARTSend(uint8_t *BufferPtr, uint32_t Length)
//参数分别为缓冲区的指针和数据的长度
{
  while ( Length != 0 )
  {
   /*如果有合法的数据*/
#if !TX_INTERRUPT
   while ( !(LPC_UART->LSR & LSR_THRE) );
   LPC_UART->THR = *BufferPtr;  //将数据存到发送保持寄存器中
#else
      while ( !(UARTTxEmpty & 0x01) );
   LPC_UART->THR = *BufferPtr;
      UARTTxEmpty = 0;    //没有发生溢出之前不会为空
#endif
      BufferPtr++;
      Length--;
  }
  return;
}

4.实例源码主程序main()

主程序源码如下所示:


printf("\r\n\r\n-- UART Test --");
  printf("\r\nPlease input a number on the keyboard:\r\n"); //向终端打印语句
  scanf("%d", &i);
  printf("\r\n%d", i);
  printf("\r\n\r\nPlease input any key on the keyboard:\r\n");

  while(1)       //轮询
  { 
if(UARTCount != 0)     //当缓冲区中有数据的时候
 {
   LPC_UART->IER = IER_THRE | IER_RLS; //禁能接收缓冲寄存器
   UARTSend((uint8_t *)UARTBuffer, UARTCount); //将接收到的数据回送到串口之中
   UARTCount = 0;
   LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR;//重新使能
 }
  }
}

利用上面的程序代码可以完成这样的一个功能:

设置好波特率以及帧的格式,打开一个终端之后,终端上首先会打印出“Please input a number on the keyboard”这样的提示信息,每次用户按按键之后,开发板串口会接收到这些信息,然后通过UARTSend()函数将这些数据回传到串口,这样就可以在终端上看到输入的内容了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值