在利用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()函数将这些数据回传到串口,这样就可以在终端上看到输入的内容了。