LPC1100系列微控制器UART LPC1100系列Cortex-M0微控制器具有一个符合16C550工业标准的异步串行口(UART)。此口同时增加了调制解调器(Modem)接口,DSR、DCD和RI Modem信号是只用于LQFP48和PLCC44封装的管脚配置。
特性
16字节收发FIFO;
寄存器位置符合16C550工业标准;
接收器FIFO触发点可为1、4、8和14字节;
内置波特率发生器;
用于精确控制波特率的小数分频器,并拥有赖以实现软件流控制的自动波特率检测能力和机制;
支持软件或硬件流控制执行;
包含标准Modem接口信号(CTS、DCD、DTS、DTR、RI、RTS);
支持RS-458/EIA-485的9位模式和输出使能。
【实验步骤】:
先看一下板子上UART的原理图
PL-2303HX是一款UART-USB芯片,这里先不管其原理,我们只学习如何将数据从CPU发送到这个TXD RXD处。
一、LPC11C14 UART 寄存器描述
这里只贴出部分
具体寄存器分析,这里不再阐述,先看一下在头文件中我们这样定义
/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/ /** @addtogroup LPC11xx_UART LPC11xx Universal Asynchronous Receiver/Transmitter @{ */ typedef struct { union { __I uint32_t RBR; /*!< Offset: 0x000 Receiver Buffer Register (R/ ) */ __O uint32_t THR; /*!< Offset: 0x000 Transmit Holding Register ( /W) */ __IO uint32_t DLL; /*!< Offset: 0x000 Divisor Latch LSB (R/W) */ }; union { __IO uint32_t DLM; /*!< Offset: 0x004 Divisor Latch MSB (R/W) */ __IO uint32_t IER; /*!< Offset: 0x000 Interrupt Enable Register (R/W) */ }; union { __I uint32_t IIR; /*!< Offset: 0x008 Interrupt ID Register (R/ ) */ __O uint32_t FCR; /*!< Offset: 0x008 FIFO Control Register ( /W) */ }; __IO uint32_t LCR; /*!< Offset: 0x00C Line Control Register (R/W) */ __IO uint32_t MCR; /*!< Offset: 0x010 Modem control Register (R/W) */ __I uint32_t LSR; /*!< Offset: 0x014 Line Status Register (R/ ) */ __I uint32_t MSR; /*!< Offset: 0x018 Modem status Register (R/ ) */ __IO uint32_t SCR; /*!< Offset: 0x01C Scratch Pad Register (R/W) */ __IO uint32_t ACR; /*!< Offset: 0x020 Auto-baud Control Register (R/W) */ uint32_t RESERVED0; __IO uint32_t FDR; /*!< Offset: 0x028 Fractional Divider Register (R/W) */ uint32_t RESERVED1; __IO uint32_t TER; /*!< Offset: 0x030 Transmit Enable Register (R/W) */ uint32_t RESERVED2[6]; __IO uint32_t RS485CTRL; /*!< Offset: 0x04C RS-485/EIA-485 Control Register (R/W) */ __IO uint32_t ADRMATCH; /*!< Offset: 0x050 RS-485/EIA-485 address match Register (R/W) */ __IO uint32_t RS485DLY; /*!< Offset: 0x054 RS-485/EIA-485 direction control delay Register (R/W) */ __I uint32_t FIFOLVL; /*!< Offset: 0x058 FIFO Level Register (R) */ } LPC_UART_TypeDef; /*@}*/ /* end of group LPC11xx_UART */
相关宏定义(部分)
****************************************************************************/ #ifndef __UART_H #define __UART_H #define RS485_ENABLED 0 #define TX_INTERRUPT 0 /* 0 if TX uses polling, 1 interrupt driven. */ #define MODEM_TEST 0 #define IER_RBR (0x01<<0) #define IER_THRE (0x01<<1) #define IER_RLS (0x01<<2) #define IIR_PEND 0x01 #define IIR_RLS 0x03 #define IIR_RDA 0x02 #define IIR_CTI 0x06 #define IIR_THRE 0x01 #define LSR_RDR (0x01<<0) #define LSR_OE (0x01<<1) #define LSR_PE (0x01<<2) #define LSR_FE (0x01<<3) #define LSR_BI (0x01<<4) #define LSR_THRE (0x01<<5) #define LSR_TEMT (0x01<<6) #define LSR_RXFE (0x01<<7) #define UART0_RBUF_SIZE 64
二、UART的初始化
/***************************************************************************** ** Function name: UARTInit ** ** Descriptions: Initialize UART0 port, setup pin select, ** clock, parity, stop bits, FIFO, etc. ** ** parameters: UART baudrate ** Returned value: None ** *****************************************************************************/ void UARTInit(uint32_t baudrate) { uint32_t Fdiv; uint32_t regVal; UARTTxEmpty = 1; UARTCount = 0; NVIC_DisableIRQ(UART_IRQn); LPC_IOCON->PIO1_6 &= ~0x07; /* UART I/O config */ LPC_IOCON->PIO1_6 |= 0x01; /* UART RXD */ LPC_IOCON->PIO1_7 &= ~0x07; LPC_IOCON->PIO1_7 |= 0x01; /* UART TXD */ /* Enable UART clock */ LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); LPC_SYSCON->UARTCLKDIV = 0x1; /* divided by 1 */ LPC_UART->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ regVal = LPC_SYSCON->UARTCLKDIV; Fdiv = ((SystemAHBFrequency/regVal)/16)/baudrate ; /*baud rate */ LPC_UART->DLM = Fdiv / 256; LPC_UART->DLL = Fdiv % 256; LPC_UART->LCR = 0x03; /* DLAB = 0 */ LPC_UART->FCR = 0x07; /* Enable and reset TX and RX FIFO. */ /* Read to clear the line status. */ regVal = LPC_UART->LSR; /* Ensure a clean start, no data in either TX or RX FIFO. */ 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 */ } /* Enable the UART Interrupt */ NVIC_EnableIRQ(UART_IRQn); #if TX_INTERRUPT LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART interrupt */ #else LPC_UART->IER = IER_RBR | IER_RLS; /* Enable UART interrupt */ #endif return; }
1、对IO口进行设置
以PIO1_7寄存器为例
可以看到低3位用于配置管脚功能 001为TXD,PIO1_6配置也相同
LPC_IOCON->PIO1_6 &= ~0x07; /* UART I/O config */ LPC_IOCON->PIO1_6 |= 0x01; /* UART RXD */ LPC_IOCON->PIO1_7 &= ~0x07; LPC_IOCON->PIO1_7 |= 0x01; /* UART TXD */
2、时钟设置
/* Enable UART clock */ LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); LPC_SYSCON->UARTCLKDIV = 0x1; /* divided by 1 */
3、设置波特率、数据位
LPC_UART->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ regVal = LPC_SYSCON->UARTCLKDIV; Fdiv = ((SystemAHBFrequency/regVal)/16)/baudrate ; /*baud rate */
4、UART相应配置
LPC_UART->DLM = Fdiv / 256; LPC_UART->DLL = Fdiv % 256; LPC_UART->LCR = 0x03; /* DLAB = 0 */ LPC_UART->FCR = 0x07; /* Enable and reset TX and RX FIFO. */第4行 FCR为 FIFO控制寄存器。控制UART FIFO的使用和模式
5、使能中断等操作
/* Read to clear the line status. */ regVal = LPC_UART->LSR; /* Ensure a clean start, no data in either TX or RX FIFO. */ 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 */ } /* Enable the UART Interrupt */ NVIC_EnableIRQ(UART_IRQn); #if TX_INTERRUPT LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART interrupt */ #else LPC_UART->IER = IER_RBR | IER_RLS; /* Enable UART interrupt */ #endifLCR寄存器作用
三、发送数据
/***************************************************************************** ** Function name: UARTSend ** ** Descriptions: Send a block of data to the UART 0 port based ** on the data length ** ** parameters: buffer pointer, and data length ** Returned value: None ** *****************************************************************************/ void UARTSend(uint8_t *BufferPtr, uint32_t Length) { while ( Length != 0 ) { /* THRE status, contain valid data */ #if !TX_INTERRUPT while ( !(LPC_UART->LSR & LSR_THRE) ); LPC_UART->THR = *BufferPtr; #else /* Below flag is set inside the interrupt handler when THRE occurs. */ while ( !(UARTTxEmpty & 0x01) ); LPC_UART->THR = *BufferPtr; UARTTxEmpty = 0; /* not empty in the THR until it shifts out */ #endif BufferPtr++; Length--; } return; }
四、接收数据
这里利用中断
/***************************************************************************** ** Function name: UART_IRQHandler ** ** Descriptions: UART interrupt handler ** ** parameters: None ** Returned value: None ** *****************************************************************************/ void UART_IRQHandler(void) { uint8_t IIRValue, LSRValue; uint8_t Dummy = Dummy; IIRValue = LPC_UART->IIR; IIRValue >>= 1; /* skip pending bit in IIR */ IIRValue &= 0x07; /* check bit 1~3, interrupt identification */ if (IIRValue == IIR_RLS) /* Receive Line Status */ { LSRValue = LPC_UART->LSR; /* Receive Line Status */ 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; /* Dummy read on RX to clear interrupt, then bail out */ return; } if (LSRValue & LSR_RDR) /* Receive Data Ready */ { /* If no error on RLS, normal ready, save into the data buffer. */ /* Note: read RBR will clear the interrupt */ UARTBuffer[UARTCount++] = LPC_UART->RBR; if (UARTCount >= UART0_RBUF_SIZE) { UARTCount = 0; /* buffer overflow */ } } } else if (IIRValue == IIR_RDA) /* Receive Data Available */ { /* Receive Data Available */ UARTBuffer[UARTCount++] = LPC_UART->RBR; if (UARTCount >= UART0_RBUF_SIZE) { UARTCount = 0; /* buffer overflow */ } } else if (IIRValue == IIR_CTI) /* Character timeout indicator */ { /* Character Time-out indicator */ UARTStatus |= 0x100; /* Bit 9 as the CTI error */ } else if (IIRValue == IIR_THRE) /* THRE, transmit holding register empty */ { /* THRE interrupt */ LSRValue = LPC_UART->LSR; /* Check status in the LSR to see if valid data in U0THR or not */ if (LSRValue & LSR_THRE) { UARTTxEmpty = 1; } else { UARTTxEmpty = 0; } } return; }
下面学习一下UART中断
对于UART接口来说,有两种情况可以触发UART接收中断:接收字节数达到接收FIFO的触发点(RDA)、接收超时(CTI)。
(1) 接收字节数达到接收FIFO中的触发点(RDA)
LPC1100系列Cortex-M0微控制器UART接口具有16字节的接收FIFO,接收触发点可以设置为1、4、8、14字节,当接收到的字节数达到接收触发点时,便会触发中断。
通过UART FIFO控制寄存器U0FCR,将接收触发点设置为“8字节触发”。那么当UART接收8个字节时,便会触发RDA中断(注:在接收中断使能的前提下)。
下面看一下IIR
五、其他操作补充
/******************************************************************************* * Function Name : UART0_PutChar * Description : Send a char to uart0 channel. * Input : c * Output : None * Return : None *******************************************************************************/ void UART0_PutChar(char ch) { while(!(LPC_UART->LSR & LSR_THRE)); LPC_UART->THR = ch; } /******************************************************************************* * Function Name : uart0_sendstring * Description : Send string to uart0 channel. * Input : pString -- string * Output : None * Return : None *******************************************************************************/ void UART0_PutString(char *pString) { while(*pString) { UART0_PutChar(*pString++); } } /******************************************************************************* * Function Name : UART0_printf * Description : print format string. * Input : fmt * Output : None * Return : None *******************************************************************************/ void UART0_printf(char *fmt, ...) { char uart0_pString[101]; va_list uart0_ap; va_start(uart0_ap, fmt); vsnprintf(uart0_pString, 100, fmt, uart0_ap); UART0_PutString(uart0_pString); va_end(uart0_ap); } /******************************************************************************* * Function Name : UART0_GetChar * Description : print format string. * Input : fmt * Output : None * Return : None *******************************************************************************/ uint8_t UART0_GetChar(uint8_t *ch) { if(UART_op != UARTCount) { *ch = UARTBuffer[UART_op]; UART_op ++; if(UART_op >= UART0_RBUF_SIZE) UART_op = 0; return 1; } return 0; }