4. UART串口通信
任务目标
在Zynq平台上实现ARM与PC之间的UART通信:PS端通过UART外设发送数据,并采用中断方式接收PC下发的数据,收到后将数据原样回传(回环验证)。通过本案例掌握Zynq UART驱动配置、中断初始化和收发流程。
硬件环境
- Zynq-7000系列开发板(如Zedboard、ZC706)
- USB-UART线缆连接开发板UART接口与PC
- PC端串口终端(如PuTTY、MobaXterm,波特率115200,8N1)
软件环境
- Vivado 2020.1+(含SDK)
- 硬件工程需包含Zynq PS核,并启用UART1(MIO 48/49),SDK中BSP自动生成uartps驱动
核心实现
代码基于Vivado SDK的BSP(standalone),使用XUartPs驱动。主程序完成:UART初始化、设置接收中断、发送提示字符串,随后进入中断等待。中断服务函数将接收到的每个字节立即回传,实现回环。
#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;
// 中断服务函数:接收一个字节并立即回传
void UartRecvHandler(void *CallBackRef, u32 Event, unsigned int Data) {
if (Event == XUARTPS_EVENT_RECV_DATA) {
XUartPs_Send(&UartInst, (u8 *)&Data, 1); // 回传收到的字节
}
}
// UART初始化
int UartInit(u16 DeviceId) {
XUartPs_Config *Config;
int Status;
Config = XUartPs_LookupConfig(DeviceId);
if (Config == NULL) return XST_FAILURE;
Status = XUartPs_CfgInitialize(&UartInst, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) return Status;
// 设置波特率115200,8数据位,无校验,1停止位
XUartPs_SetBaudRate(&UartInst, 115200);
XUartPs_SetDataFormat(&UartInst, XUARTPS_FORMAT_8N1);
return XST_SUCCESS;
}
// 中断控制器初始化并连接UART中断
int IntcInit(u16 DeviceId, u16 UartIntrId) {
XScuGic_Config *IntcConfig;
int Status;
IntcConfig = XScuGic_LookupConfig(DeviceId);
if (IntcConfig == NULL) return XST_FAILURE;
Status = XScuGic_CfgInitialize(&IntcInst, IntcConfig, IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) return Status;
// 连接中断服务函数
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, &IntcInst);
Xil_ExceptionEnable();
Status = XScuGic_Connect(&IntcInst, UartIntrId,
(Xil_InterruptHandler)XUartPs_InterruptHandler, &UartInst);
if (Status != XST_SUCCESS) return Status;
XScuGic_Enable(&IntcInst, UartIntrId);
return XST_SUCCESS;
}
int main() {
int Status;
u8 SendBuf[] = "Zynq UART Ready!\r\n";
Status = UartInit(UART_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("UART init failed!\r\n");
return -1;
}
Status = IntcInit(INTC_DEVICE_ID, UART_IRPT_INTR);
if (Status != XST_SUCCESS) {
xil_printf("Intc init failed!\r\n");
return -1;
}
// 设置接收事件回调
XUartPs_SetHandler(&UartInst, UartRecvHandler, &UartInst);
XUartPs_SetRecvThreshold(&UartInst, 1); // 收到1字节即触发中断
XUartPs_SetInterruptMask(&UartInst, XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXEMPTY);
// 发送就绪提示
XUartPs_Send(&UartInst, SendBuf, sizeof(SendBuf) - 1);
// 主循环空转,等待中断
while (1) {
// 可在此添加低功耗或任务代码
}
return 0;
}
运行与验证
- 在Vivado中创建硬件工程,使能UART1(MIO 48/49),导出硬件并启动SDK。
- 在SDK中新建Application Project,将上述代码替换
helloworld.c,BSP需勾选xil_printf和uartps驱动。 - 连接USB-UART线缆,PC端打开串口终端(115200,8N1)。
- 下载程序到Zynq并运行(Program FPGA → Run)。
- 通过标准:串口终端显示
Zynq UART Ready!;在终端输入任意字符(如ABC123),终端应原样显示相同字符,即回环成功,证明UART发送与中断接收均正常。
常见问题
- 无输出:检查MIO引脚配置是否为UART1,以及串口终端波特率是否匹配。
- 乱码:确认
XUartPs_SetDataFormat设置为8N1,且终端无硬件流控。 - 中断不触发:确认
XScuGic_Connect的中断ID与Vivado中UART1中断号一致(通常为59),并检查BSP中xparameters.h的XPAR_XUARTPS_0_INTR值。