首先必须清楚什么是UART?
UART的英文全称是:Universal Asynchronous Receiver/Transmitter,通用异步接收/发送装置,UART是一个并行输入成为串行输出的芯片,通常集成在主板上,多数是16550AFN芯片。UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。
我们的LM3S8962控制器带有 2个 UART模块s。 每个 Stellaris?UART 可执行“并-串”和“串-并”转换功能。其功能与16C550 UART类似,但两者的寄存器不兼容。此外,UART外设还包含一个串行红外(SIR)编码器/解码器模块,这里暂时不讨论~~
UART的一个重要结构就是:FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
FIFO的一些重要参数
FIFO的宽度:也就是英文资料里常看到的THE WIDTH,它指的是FIFO一次读写操作的数据位,就像MCU有8位和16位,ARM 32位等等,FIFO的宽度在单片成品IC中是固定的,也有可选择的,如果用FPGA自己实现一个FIFO,其数据位,也就是宽度是可以自己定义的。
FIFO的深度:THE DEEPTH,它指的是FIFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12 ,就可以存储12个8位的数据,FIFO的深度可大可小,个人认为FIFO深度的计算并无一个固定的公式。在FIFO实际工作中,其数据的满/空标志可以控制数据的继续写入或读出。在一个具体的应用中也不可能由一些参数算数精确的所需FIFO深度为多少,这在写速度大于读速度的理想状态下是可行的,但在实际中用到的FIFO深度往往要大于计算值。一般来说根据电路的具体情况,在兼顾系统性能和FIFO成本的情况下估算一个大概的宽度和深度就可以了。而对于写速度慢于读速度的应用,FIFO的深度要根据读出的数据结构和读出数据的由那些具体的要求来确定。
满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针:指向下一个读出地址。读完后自动加1。
写指针:指向下一个要写入的地址的,写完自动加1。 读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。
Lm3s8962的FIFO操作:
UART含2个16位入口的FIFO;一个用于发送,另一个用于接收。两个FIFO都通过UART数据(UARTDR)寄存器 (进行访问。UARTDR的写操作会把8位的数据放入发送FIFO,而UARTDR寄存器的读操作返回的却是一个12位的值,该值由8个数据位和4个错误标志组成。
复位完成后,两个FIFO都被禁能,并充当1字节深的保存(holding)寄存器。通过置位UARTLCRH中的FEN位可以使FIFO使能。
FIFO的状态可以通过 UART标志 (UARTFR)寄存器 )和 UART接收状态(UARTRSR) 寄存器进行监控。而对空、满和溢出条件的监控则是由硬件来完成的。UARTFR 寄存器包含了空和满的标志(TXFE、 TXFF,RXFE和 RXFF 位),而UARTRSR寄存器则通过OE位指示出溢出的状态。促使FIFO产生中断的触发点是通过UART中断的FIFO深度选择 (UARTIFLS) 寄存器 来控制的。可将两个FIFO的中断分别配置为不同的触发深度。可供选择的配置包括1/8、1/4、1/2、3/4和7/8。例如,如果接收FIFO选择1/4,那么UART在接收了4个数据字节之后产生接收中断。在复位完成后,两个FIFO都被配置为以1/2的深度来触发中断。
下面是对例程的解读
//这个函数的作用是向串口发送一个字符串
void
UARTSend(const unsigned char *pucBuffer, unsigned long ulCount)
{
//循环发送字符
while(ulCount--)
{
//向UART写下一个字符
UARTCharPutNonBlocking(UART0_BASE, *pucBuffer++);
}
}
int
main(void)
{
//这个函数设置时钟从晶体输出
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_8MHZ);
//初始化OLED显示屏并向显示频输出一些信息
RIT128x96x4Init(1000000);
RIT128x96x4StringDraw("UART Echo", 36, 0, 15);
RIT128x96x4StringDraw("Port: Uart 0", 12, 16, 15);
RIT128x96x4StringDraw("Baud: 115,200 bps", 12, 24, 15);
RIT128x96x4StringDraw("Data: 8 Bit", 12, 32, 15);
RIT128x96x4StringDraw("Parity: None", 12, 40, 15);
RIT128x96x4StringDraw("Stop: 1 Bit", 12, 48, 15);
//打开两个外设,GPIOA端口,遗迹UART0端口
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//打孔石进程中断
IntMasterEnable();
//设置GPIO的A0,A1为UART引脚
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//配置UART参数 波特率11520 0数据长度8位 1个停止位 无奇偶校验 FIFO禁能无中断
UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));
//打开UART中断
IntEnable(INT_UART0);
UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
//文字提示输入
UARTSend((unsigned char *)" ", 12);
//无限循环等待中断
while(1)
{
}
}
使用串口调试工具可以看到串口输出提示:Enter text:。这时,输入字符串,窗口马上就会显示输出。这里建议大家使用聂小猛的串口调试助手,很好用。
下一步打算深入了解UART的操作对哪些寄存器产生了怎样的影响,老师说,单片机开发就是在合适的时间往合适的寄存器写合适的值~~
顺便弱弱的提一个问,为什么我的操作系统windowsXP里自带的超级终端连接上了,可是发送不了数据,而且还没有响应,发生死机一样的症状?