3. UART串口通信
任务目标
在Zynq平台上通过UART实现与PC的双向串口通信:PS端接收PC发送的字符串,并将接收到的数据原样回传(回环验证)。通过本案例掌握UART控制器初始化、中断收发配置及中断服务程序编写方法。
硬件环境
- Zynq-7000系列开发板(如Zedboard、PYNQ-Z2等)
- USB-UART线缆连接开发板UART接口与PC
- PC端串口终端(如PuTTY、MobaXterm,波特率115200,8N1)
实现原理
Zynq PS端UART1控制器通过MIO引脚连接板载USB-UART桥接芯片。本案例使用中断方式接收数据:当RX FIFO接收到字符时触发中断,中断服务程序读取数据并立即写入TX FIFO完成回传。发送方向采用轮询方式,确保数据写入完成后才退出。
关键完整代码
// main.c - UART中断收发回环示例
#include "xparameters.h"
#include "xuartps.h"
#include "xscugic.h"
#include "xil_printf.h"
#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define UART_IRPT_INTR XPAR_XUARTPS_0_INTR
static XUartPs UartInst;
static XScuGic IntcInst;
// 中断服务函数:读取RX数据并回写
void UartRecvHandler(void *CallBackRef, u32 Event, unsigned int ByteCount) {
u8 RecvBuf[8];
u32 ReceivedCount = 0;
if (Event == XUARTPS_EVENT_RECV_DATA) {
ReceivedCount = XUartPs_Recv(&UartInst, RecvBuf, ByteCount);
if (ReceivedCount > 0) {
// 将收到的数据原样发送回PC
XUartPs_Send(&UartInst, RecvBuf, ReceivedCount);
}
}
}
int UartIntrSetup(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 UartIntrId) {
XScuGic_Config *IntcConfig;
int Status;
// 初始化中断控制器
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfig, IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) return XST_FAILURE;
// 连接UART中断
Status = XScuGic_Connect(IntcInstPtr, UartIntrId,
(Xil_InterruptHandler)XUartPs_InterruptHandler,
(void *)UartInstPtr);
if (Status != XST_SUCCESS) return XST_FAILURE;
// 使能UART中断
XScuGic_Enable(IntcInstPtr, UartIntrId);
// 使能异常处理
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
(void *)IntcInstPtr);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
int main(void) {
XUartPs_Config *UartConfig;
int Status;
// 初始化UART
UartConfig = XUartPs_LookupConfig(UART_DEVICE_ID);
Status = XUartPs_CfgInitialize(&UartInst, UartConfig, UartConfig->BaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("UART init failed\r\n");
return XST_FAILURE;
}
// 设置波特率115200,8数据位,无校验,1停止位
XUartPs_SetBaudRate(&UartInst, 115200);
XUartPs_SetDataFormat(&UartInst, XUARTPS_FORMAT_8N1);
// 设置中断触发条件:RX FIFO非空即触发
XUartPs_SetInterruptMask(&UartInst, XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXEMPTY);
// 建立中断连接
Status = UartIntrSetup(&IntcInst, &UartInst, UART_IRPT_INTR);
if (Status != XST_SUCCESS) {
xil_printf("Interrupt setup failed\r\n");
return XST_FAILURE;
}
// 注册UART事件处理函数
XUartPs_SetHandler(&UartInst, UartRecvHandler, &UartInst);
xil_printf("UART Echo Ready. Type characters in terminal...\r\n");
while (1) {
// 主循环空闲,等待中断
}
return 0;
}
运行与验证
- 创建工程:在Vivado中创建基于Zynq的硬件设计,使能UART1(MIO 14/15),导出硬件并启动Xilinx SDK。
- 编译下载:新建Application Project,将上述代码复制到
main.c,编译后将程序下载到开发板运行。 - 连接串口:PC打开串口终端,选择对应COM口,设置波特率115200、8数据位、无校验、1停止位。
- 验证回环:在终端中输入任意字符(如"Hello Zynq"),观察终端是否立即回显相同内容。若每个发送的字符都原样返回,则说明UART中断收发功能正常。
通过条件:终端能实时回显所有发送的字符,无乱码、无丢失,且开发板串口输出提示信息"UART Echo Ready"。
常见问题
- 无回显:检查MIO引脚连接是否正确,确认终端波特率与代码设置一致。
- 乱码:多为波特率不匹配或接地不良,重新确认串口参数。
- 中断不触发:确认
XUartPs_SetInterruptMask中RXEMPTY位设置正确,该位在RX FIFO非空时触发中断。