上文对Zynq中的UART控制器做了简单介绍。从本文开始将以实例的方式详细讲述UART的各种使用方法。本文是UART最基础的使用方法,每秒发送一个“hello world”,实现的功能与printf或xil_printf相同。但后面介绍UART更复杂特性的文章,都是在本文设计的基础上进行改动。
Vivado中配置Zynq时启用开发板提供的UART接口。SDK中user_uart.h文件代码如下:
#ifndef SRC_USER_UART_H_
#define SRC_USER_UART_H_
#include "xparameters.h"
#include "xuartps.h"
#include "xil_printf.h"
#include "sleep.h"
#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID
int Uart_Send(XUartPs* Uart_Ps, u8 *sendbuf, int length);
int Uart_Init(XUartPs* Uart_Ps, u16 DeviceId);
#endif /* SRC_USER_UART_H_ */
user_uart.c文件的代码如下:
#include "user_uart.h"
// UART格式
XUartPsFormat uart_format =
{
9600,
//XUARTPS_DFT_BAUDRATE, //默认波特率 115200
XUARTPS_FORMAT_8_BITS,
XUARTPS_FORMAT_NO_PARITY,
XUARTPS_FORMAT_1_STOP_BIT,
};
//--------------------------------------------------------------
// UART初始化函数
//--------------------------------------------------------------
int Uart_Init(XUartPs* Uart_Ps, u16 DeviceId)
{
int Status;
XUartPs_Config *Config;
/* 初始化UART设备 */
Config = XUartPs_LookupConfig(DeviceId);
if (NULL == Config) {
return XST_FAILURE;
}
Status = XUartPs_CfgInitialize(Uart_Ps, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* UART设备自检 */
Status = XUartPs_SelfTest(Uart_Ps);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* 设置UART模式与参数 */
XUartPs_SetOperMode(Uart_Ps, XUARTPS_OPER_MODE_NORMAL); //正常模式
XUartPs_SetDataFormat(Uart_Ps, &uart_format); //设置UART格式
return XST_SUCCESS;
}
//--------------------------------------------------------------
// UART数据发送函数
//--------------------------------------------------------------
int Uart_Send(XUartPs* Uart_Ps, u8 *sendbuf, int length)
{
int SentCount = 0;
while (SentCount < length) {
SentCount += XUartPs_Send(Uart_Ps, &sendbuf[SentCount], 1);
}
return SentCount;
}
main.c文件的代码如下:
#include "user_uart.h"
XUartPs Uart_Ps; /* The instance of the UART Driver */
int main(void)
{
int Status;
u8 sendbuf[] = "Hello World!\r\n";
/* 串口初始化 */
Status = Uart_Init(&Uart_Ps, UART_DEVICE_ID);
if (Status == XST_FAILURE) {
xil_printf("Uartps Failed\r\n");
return XST_FAILURE;
}
while (1)
{
sleep(1);
Uart_Send(&Uart_Ps, sendbuf, 14);
}
return Status;
}
SDK Terminal中添加串口,波特率设置为程序制定的9600,运行程序,将看到每隔1s打印一次“Hello World!”。
对UART设备初始化操作和前面GPIO设备、中断设备、定时器设备、XADC设备的初始化过程一样,不再赘述。接着使用XUartPs_SelfTest函数对UART设备自检。
s32 XUartPs_SelfTest(XUartPs *InstancePtr)
这个函数执行一次本地回环,验证可以正常发送和接受数据。返回XST_UART_TEST_FAIL表示测试失败;XST_SUCCESS表示测试成功。我们可以用这个函数检查硬件工作是否正常。
初始化函数中还用XUartPs_SetOperMode函数设置了UART的工作模式。工作模式在xuartps.h文件中宏定义。
void XUartPs_SetOperMode(XUartPs *InstancePtr, u8 OperationMode)
四种工作模式的作用请参考第24篇。下表给出每种模式的宏定义:
宏定义 | 实际值 | 工作模式 |
---|---|---|
XUARTPS_OPER_MODE_NORMAL | 0x00U | 正常模式 |
XUARTPS_OPER_MODE_AUTO_ECHO | 0x01U | 自动echo模式 |
XUARTPS_OPER_MODE_LOCAL_LOOP | 0x02U | 本地回环模式 |
XUARTPS_OPER_MODE_REMOTE_LOOP | 0x03U | 远程回环模式 |
接下来使用XUartPs_SetDataFormat函数设置UART的数据格式,包括波特率、数据位数、停止位数和奇偶校验。调用此函数时应确保UART没有收发数据。
s32 XUartPs_SetDataFormat(XUartPs *InstancePtr, XUartPsFormat * FormatPtr)
如果设置成功则返回XST_SUCCESS;如果该波特率在当前参考时钟频率下无法实现,则返回XST_UART_BAUD_ERROR表示无法设置波特率;函数的任意一个输入参数无效时返回XST_INVALI_PARAM。
我们绝大多数情况下都会使用“8位数据、1位停止、无奇偶校验”,因此如果想进一步提高程序效率,可以仅使用XUartPs_SetBaudRate函数来设置波特率。
s32 XUartPs_SetBaudRate(XUartPs *InstancePtr, u32 BaudRate)
使用该函数也会检查输入的波特率值是否有效。检查的依据是xuartps.c中下面这个宏定义,即最大允许的波特率错误率:
#define XUARTPS_MAX_BAUD_ERROR_RATE 3U /* max % error allowed */
其实质上是波特率生成器产生的实际波特率与设置的波特率之间的差值。如果不满足这个条件,便会返回XST_UART_BAUD_ERROR,保持原有波特率不变。
上面的函数中使用了XuartPsFormat类型的结构体来设置UART格式。该结构体原型如下:
typedef struct {
u32 BaudRate; /**< In bps, ie 1200 */
u32 DataBits; /**< Number of data bits */
u32 Parity; /**< Parity */
u8 StopBits; /**< Number of stop bits */
} XUartPsFormat;
下表总结了与数据格式相关的宏定义,使用时要将其填到结构体变量的对应位置。一般波特率可以写成数字形式,其余三个成员都要用宏定义的形式。
宏定义 | 实际值 | 工作模式 |
---|---|---|
数据位 | ||
XUARTPS_FORMAT_8_BITS | 0U | 8-bits数据位 |
XUARTPS_FORMAT_7_BITS | 2U | 7-bits数据位 |
XUARTPS_FORMAT_6_BITS | 3U | 6-bits数据位 |
奇偶校验 | ||
XUARTPS_FORMAT_NO_PARITY | 4U | 无奇偶校验 |
XUARTPS_FORMAT_MARK_PARITY | 3U | 校验位始终为1 |
XUARTPS_FORMAT_SPACE_PARITY | 2U | 校验位时钟为0 |
XUARTPS_FORMAT_ODD_PARITY | 1U | 奇校验 |
XUARTPS_FORMAT_EVEN_PARITY | 0U | 偶校验 |
停止位 | ||
XUARTPS_FORMAT_2_STOP_BIT | 2U | 2-bits停止位 |
XUARTPS_FORMAT_1_5_STOP_BIT | 1U | 1.5-bits停止位 |
XUARTPS_FORMAT_1_STOP_BIT | 0U | 1-bit停止位 |
波特率 | ||
XUARTPS_MAX_RATE | 921600U | 最大波特率 |
XUARTPS_MIN_RATE | 110U | 最小波特率 |
XUARTPS_DFT_BAUDRATE | 115200U | 默认波特率 |
程序中使用XUartPs_Send函数发送数据。这个函数是非阻塞的,轮询模式和中断驱动模式下都可以使用。它会尽可能地想TxFIFO填充数据,并返回发送的字节数;如果无法填充,会返回0表示发送了0字节,便于用户处理。
中断模式下,该函数会发送指定的缓冲区(Buffer)中的内容,中断处理程序负责将所有数据全部发送完。此时会调用绑定的回调函数,标识发送完成。关于中断的用法在后面文章中专门介绍。
u32 XUartPs_Send(XUartPs *InstancePtr, u8 *BufferPtr, u32 NumBytes)
第二个参数是指向要发送的数据缓冲区的指针;第三个参数是发送的字节数;返回值标识实际发送的字节数。本例程序中就是利用返回值确保所有数据都依次发送(虽然本例的数量不大,但要学习这个用法)。
这个函数还有个特殊用法,如果将第三个参数设为0,则会停止正在进行的发送操作,并将已经在TxFIFO中的所有数据都发送出去。可以用这个用法实现某些特殊功能。
本文了解UART的基本使用方法,为后文打基础。