前面章节中我们打印的测试结果都是通过JTAG返回控制台的,这章我们将在MB系统中添加一个串口,利用此串口可进行相关的调试,并完成一个串口的中断实验。 ◎紧接第六章工程,打开XPS系统,在工程中添加AXI UART(Lite)IP,在弹出对话框中选择yes。
◎点击该ip,打开配置程序,选择默认。波特率9600bps,8位,无奇偶校验位。
◎单击axi_uart_lite,将名称命名为RS232。可以看到RS232挂到了MB系统的AXI4Lite0总线上。
◎在Ports中,打开RS232的下拉菜单,将RS232中断连接到中断控制器上。
◎可以看到,加上前两章,此时已有3个中断系统挂在中断控制intc0下了。
◎在ExternalPorts中可以看到,RS232的两个接口已接到外面了。
◎在mis603_soc.mhs文件中,已经可以看到串口的两个PORT了。
◎打开mis603_soc.ucf文件,为RS232的两个引脚配置约束。
◎保存后,在Hardware下运行Generate NetList,产生网表。 ◎打开SDK文件,在SDK中新建个工程,工程命名为Uart_Interrupt,以helloworld为模板。
◎将helloworld.c文件命名为uart_intr.c文件。 ◎先写个程序来测试下,RS232是否能正常通信。我们从上位机中发送数据,当接收到数据后,立即发送至上位机,做一个环路测试。 /* * uart_intr.c * * Created on: 2016-1-14 * Author: Milinker Xu */ #include <stdio.h> #include "xparameters.h" #include "xuartlite_l.h" #include "xuartlite.h" #include "platform.h" int main() { unsigned char rx_data; //8 bit接收数据 unsigned char i; init_platform(); while(1) { //check receiver buffer is empty or not if(!XUartLite_IsReceiveEmpty(XPAR_UARTLITE_1_BASEADDR)) { //delay for (i=100;i>0;i--); //receive one byte rx_data = XUartLite_RecvByte(XPAR_UARTLITE_1_BASEADDR); //delay for (i=100;i>0;i--); //send one byte XUartLite_SendByte(XPAR_UARTLITE_1_BASEADDR,rx_data); //delay for (i=100;i>0;i--); } } return 0; } |
◎将ISE生成的bit文件下载后,在运行UART_INTR工程,在run configuration新建一个UART_INTR Debug,中默认即可。
◎将J5连接到PC机的串口,安装好驱动程序。打开串口调试助手,设置好波特率。
◎在发送串口输入发送数据,选择自动发送模式,再打开串口。这样串口调试助手中就能收到发送端的数据,证明发送与接收通信正常。
◎在发送串口输入发送数据,选择自动发送模式,再打开串口。这样串口调试助手中就能收到发送端的数据,证明发送与接收通信正常。 ◎同前几节一样,新建几个文件:1.uart中断设置文件,uart_intr_initial_set.c;2.串口中断处理函数文件uart_intr_handler.c;3.串口中断头文件。 ◎在uart_intr_initial_set.c文件主要包括两方面:中断控制器初始化和串口初始化。中断控制器初始化包括:初始化中断、使能中断、外部中断初始化、外部中断处理子函数和启动中断。串口初始化包括:串口控制器初始化、串口中断与中断控制器直接映射、以及使能串口中断程序。代码如下所示。 /* * uart_intr_initial.c * * Created on: 2016-1-14 * Author: Milinker XU */ #include "uart_intr.h" void Uart_Init(XIntc* IntcInstancePtr,XUartLite* UartInstancePtr,u16 DeviceId,u16 IntrId) { XUartLite_Initialize(UartInstancePtr, DeviceId); XIntc_Connect(IntcInstancePtr, IntrId,(XInterruptHandler)uart_intr_handler,(void*)UartInstancePtr); XUartLite_EnableInterrupt(UartInstancePtr); } void intr_set(void) //设置中断 { intr_init(&Intc, XPAR_INTC_0_DEVICE_ID);//初始化中断 Uart_Init(&Intc,&Uart,XPAR_UARTLITE_1_DEVICE_ID,XPAR_INTC_0_UARTLITE_1_VEC_ID);//初始化GPIO中断 } void intr_init(XIntc *IntcInstancePtr, u16 DeviceId) { XIntc_Initialize(IntcInstancePtr, DeviceId);//初始化中断 XIntc_Enable(&Intc, XPAR_INTC_0_UARTLITE_1_VEC_ID);//使能中断 Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XIntc_InterruptHandler,IntcInstancePtr); Xil_ExceptionEnable(); XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);//启动中断 } |
◎uart_intr_handler.c文件中,主要是串口中断子程序的调用。当串口接收到数据时,通过读取状态寄存器来判断,进入中断,中断子程序将接收到的数据发送回去。 /* * uart_intr_handler.c * Created on: 2016-1-14 * Author: Administrator */ #include "uart_intr.h" void uart_intr_handler(void *CallbackRef)//中断函数 { u8 ReadByte; u32 IsrStatus; XUartLite *InstancePtr= (XUartLite *)CallbackRef; //读取状态寄存器 IsrStatus = XUartLite_ReadReg(InstancePtr->RegBaseAddress,XUL_STATUS_REG_OFFSET); while(IsrStatus & XUL_SR_RX_FIFO_VALID_DATA) { //读取数据 ReadByte=XUartLite_ReadReg(InstancePtr->RegBaseAddress,XUL_RX_FIFO_OFFSET); //发送数据 XUartLite_WriteReg(InstancePtr->RegBaseAddress,XUL_TX_FIFO_OFFSET,ReadByte); //读取状态寄存器 IsrStatus = XUartLite_ReadReg(InstancePtr->RegBaseAddress,XUL_STATUS_REG_OFFSET); } } |
◎这样在主函数中只需要调用中断设置函数intr_set()即可。uart_intr.h文件中依然包含各类头文件和函数声明。
#include "uart_intr.h" int main(void) { Xil_ICacheEnable(); intr_set(); while(1) ; } |
◎将程序下载到板子上,运行该工程,打开串口调试助手,输入发送数据,可以看到接收到一样的数据。
◎或许有人就不理解了,既然结果是一致的,为什么还要用到中断,直接用第一中方法不是一样么。这里需要做下解释,串口中断是指无论程序工作在什么状态,只要串口端接收到数据,就立即跳转到中断函数执行,完成后继续返回原程序进行后续操作。而第一种方法采用查询的方式,不断读取串口标志位,查询是否有数据接收到。程序需要不停地读取状态寄存器,才能够判断是否接收到数据,两者相比,效率明显低下,且占据了程序空间。 ◎UART程序中,有两个重要的头文件。xuartlite.h文件。这两个文件分别包含了串口的初始化,发送,接收,状态寄存器和使能中断控制。Xuartlite_l.h文件包含一些寄存器的偏移地址,在读写数据和状态寄存器时都需用到。至于具体的寄存器操作和API调用,需要慢慢积累。
|