ZYNQ UltraScale MPSOC,使用PL端AXI_UART16550IP核,且在PS端控制下实现RS485通信,接收不同帧长报文数据-----中断方式

目录

硬件环境:Xilinx ZynqMP XCZU15eg-ffvb1156-2-i

软件环境:Vivado2018.3

一:新建工程

二:芯片配置

 三:添加IP核

 四:引脚绑定,并生成bitstream

 五:导出硬件平台信息,然后在SDK里新建一个helloworld工程;

六:将板子的A1和B1 以及A2,B2分别与外部串口通信工具连接,也即用485转USB连接电脑。

七:PS端代码:废话少说直接上代码:

 八:结果总结

硬件环境:Xilinx ZynqMP XCZU15eg-ffvb1156-2-i

软件环境:Vivado2018.3

一:新建工程

        打开Vivado,建立一个工程,选择芯片xczu15eg-ffvb-2-i,建立完毕后建立blockDesign,添加芯片进去。

二:芯片配置

  1. 首先配置bank电压,分别为LVCMOS18,LVCMOS18,LVCMOS18,LVCMOS33
  2. 配置低速IO,包括QSPI,SD,UART等
  3. 配置DDR
  4. 打开PLtoPS的中断;具体配置如下图所示:

 

 

 

 三:添加IP核

先来一张总的设计图:

  1.  添加 AXI GPIO模块,并配置为输出,位宽为1,用于第一路 RS485的 DE 控制
  2. 添加UART16550模块,用于第一路RS485的数据接口
  3. 自动连接
  4. 删除UART引脚,并展开UART接口
  5. 添加constant模块,并设置位宽为1,值为1;
  6. 连接ctsn,rin信号
  7. 再添加一个constant模块,值设置为0;
  8. 连接freeze,dcdn,dsrn信号
  9. 将sin和sout引脚导出,修改引脚名字为RS485_0_RXD和RS485_0_TXD;
  10. 并将GPIO的引脚名字修改为RS485_0_DE;至此第一路配置结束。
  11. 同样的方法开始配置第二路RS485接口;
  12. 添加concat模块,连接两路中断到pl_ps_irq0;
  13. 自动连接并修改第二路的引脚名称;

 四:引脚绑定,并生成bitstream

引脚绑定主要为两路RS485的DE,以及TXD和RXD,根据硬件原理图绑定相应引脚,也即添加.xdc文件,然后create HDL Wrapper以及Generate Output Products,最后编译并生成bitstream

 五:导出硬件平台信息,然后在SDK里新建一个helloworld工程;

六:将板子的A1和B1 以及A2,B2分别与外部串口通信工具连接,也即用485转USB连接电脑。

七:PS端代码:废话少说直接上代码:

//主程序
#include "xil_exception.h"
#include "xil_printf.h"
#include"sleep.h"
#include <string.h>
#include "RS485_Intr_Recv.h"
/************************** Constant Definitions ******************************/

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */

#define UART_DEVICE_ID		XPAR_UARTNS550_0_DEVICE_ID
#define UART_IRPT_INTR		XPAR_FABRIC_AXI_UART16550_0_IP2INTC_IRPT_INTR
#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
#define TEST_BUFFER_SIZE	200
/************************** Variable Definitions ******************************/

XUartNs550 UartNs550Instance;				/* Instance of the UART Device */
INTC IntcInstance;							/* Instance of the Interrupt Controller */

u8 SendBuffer[TEST_BUFFER_SIZE];			/* Buffer for Transmitting Data */
u8 RecvBuffer[TEST_BUFFER_SIZE];			/* Buffer for Receiving Data */
u8 *RecvBufferPtr;
volatile u32 TotalRecvCnt;
static volatile int TotalSentCount;
static volatile int TotalErrorCount;
unsigned int flag = 0;



int main(void)
{
	RecvBufferPtr = RecvBuffer;
	UartNs550Init(UART_DEVICE_ID, &UartNs550Instance);

	XUartNs550_Recv(&UartNs550Instance, RecvBuffer, 108);
	while(1)
	{
		usleep(1000000);

		if(TotalRecvCnt > 0)
		{
			XUartNs550_Recv(&UartNs550Instance, RecvBuffer, 200);
			TotalRecvCnt = 0;
			flag = 1;
		}
		if(flag == 1)
		{
			for(int i =0;i<108;i++)
			{
				xil_printf("%c",RecvBuffer[i]);
			}
			flag=0;
			memset(RecvBuffer,0,200);
		}

	}

}

int UartNs550Init(u16 DeviceId, XUartNs550 *UartNs550)
{
	u16 Options;
	/*Initialize the UART driver so that it's ready to use.*/
	XUartNs550_Initialize(UartNs550, DeviceId);

	/*Perform a self-test to ensure that the hardware was built correctly.*/
	XUartNs550_SelfTest(UartNs550);

	/** Connect the UART to the interrupt subsystem such that interrupts can
	 * occur. This function is application specific.
	 */
	UartNs550SetupIntrSystem(&IntcInstance, UartNs550, UART_IRPT_INTR);

	/** Setup the handlers for the UART that will be called from the
	 *  interrupt context when data has been sent and received, specify a
	  * pointer to the UART driver instance as the callback reference so
	  * the handlers are able to access the instance data.
	*/
	XUartNs550_SetHandler(UartNs550, UartNs550IntrHandler, UartNs550);

//	XUartNs550_SetRecvTimeout(UartNs550, 8);
	XUartNs550_SetFifoThreshold(UartNs550, XUN_FIFO_TRIGGER_08);

	Options = XUN_OPTION_DATA_INTR | XUN_OPTION_FIFOS_ENABLE |XUN_OPTION_RESET_TX_FIFO;
	XUartNs550_SetOptions(UartNs550, Options);
	/* Set uart mode Baud Rate 115200, 8bits, no parity, 1 stop bit */
	XUartNs550_SetDataFormat(UartNs550, &UartNs550Format);

}
/*****************************************************************************/
/**
*
* This function is the handler which performs processing to handle data events
* from the UartNs550.  It is called from an interrupt context such that the
* amount of processing performed should be minimized.
*
* This handler provides an example of how to handle data for the UART and
* is application specific.
*
* @param	CallBackRef contains a callback reference from the driver,
*		in thiscase it is the instance pointer for the UART driver.
* @param	Event contains the specific kind of event that has occurred.
* @param	EventData contains the number of bytes sent or received for sent
*		and receive events.
*
* @return	None.
*
* @note		None.
*
*******************************************************************************/
void UartNs550IntrHandler(void *CallBackRef, u32 Event, unsigned int EventData)
{
	u8 Errors;
	XUartNs550 *UartNs550Ptr = (XUartNs550 *)CallBackRef;

	 static unsigned int ReceivedCount = 0;

	/*
	 * All of the data has been sent.
	 */
	if (Event == XUN_EVENT_SENT_DATA) {
		TotalSentCount = EventData;
	}
	if (Event == XUN_EVENT_RECV_DATA)
	{
		TotalRecvCnt = EventData;
	}

	/*Data was received, but not the expected number of bytes, a
	 * timeout just indicates the data stopped for 4 character times.
	 */
	if (Event == XUN_EVENT_RECV_TIMEOUT)
	{
		TotalRecvCnt = EventData;
	}

	if (Event == XUN_EVENT_RECV_ERROR) {
		TotalRecvCnt = EventData;
		TotalErrorCount++;
		Errors = XUartNs550_GetLastErrors(UartNs550Ptr);
	}

}

/******************************************************************************/
/**
*
* This function setups the interrupt system such that interrupts can occur
* for the UART.  This function is application specific since the actual
* system may or may not have an interrupt controller.  The UART could be
* directly connected to a processor without an interrupt controller.  The
* user should modify this function to fit the application.
*
* @param	IntcInstancePtr is a pointer to the instance of the Interrupt
*		Controller.
* @param	UartInstancePtr is a pointer to the instance of the UART.
* @param	UartIntrId is the interrupt Id and is typically
*		XPAR_<INTC_instance>_<UARTNS550_instance>_VEC_ID value from
*		xparameters.h.
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note		None.
*
*******************************************************************************/
static int UartNs550SetupIntrSystem(INTC *IntcInstancePtr,
					XUartNs550 *UartInstancePtr,
					u16 UartIntrId)
{
	int Status;
	XScuGic_Config *IntcConfig;

	/*Initialize the interrupt controller driver so that it is ready to use.*/
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, UartIntrId,
					0xA0, 0x3);

	/*
	 * Connect the interrupt handler that will be called when an
	 * interrupt occurs for the device.
	 */
	Status = XScuGic_Connect(IntcInstancePtr, UartIntrId,
				 (Xil_ExceptionHandler)XUartNs550_InterruptHandler,
				 UartInstancePtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	/*Enable the interrupt for the Timer device.*/
	XScuGic_Enable(IntcInstancePtr, UartIntrId);

	/*Initialize the exception table. */
	Xil_ExceptionInit();

	/*Register the interrupt controller handler with the exception table.*/
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			 (Xil_ExceptionHandler)INTC_HANDLER,
			 IntcInstancePtr);

	/* Enable exceptions.*/
	Xil_ExceptionEnable();


	return XST_SUCCESS;
}


/*****************************************************************************/
/**
*
* This function disables the interrupts that occur for the UartNs550 device.
*
* @param	IntcInstancePtr is the pointer to the instance of the Interrupt
*		Controller.
* @param	UartIntrId is the interrupt Id and is typically
*		XPAR_<INTC_instance>_<UARTNS550_instance>_VEC_ID
*		value from xparameters.h.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void UartNs550DisableIntrSystem(INTC *IntcInstancePtr, u16 UartIntrId)
{
	/*Disconnect and disable the interrupt for the UartNs550 device.*/
	XScuGic_Disable(IntcInstancePtr, UartIntrId);
	XScuGic_Disconnect(IntcInstancePtr, UartIntrId);
}

//头文件如下
* RS485_Intr_Recv.h
 *
 *  Created on: 2022年6月23日
 *      Author: tan804
 */

#ifndef SRC_RS485_INTR_RECV_H_
#define SRC_RS485_INTR_RECV_H_

#include "xscugic.h"
#include "xparameters.h"
#include "xuartns550.h"



#define INTC			XScuGic
#define INTC_HANDLER	XScuGic_InterruptHandler

XUartNs550Format UartNs550Format =
{
		115200,
		XUN_FORMAT_8_BITS,
		XUN_FORMAT_NO_PARITY,
		XUN_FORMAT_1_STOP_BIT
};
/************************** Function Prototypes *******************************/

int UartNs550IntrExample(INTC *IntcInstancePtr,
			XUartNs550 *UartInstancePtr,
			u16 UartDeviceId,
			u16 UartIntrId);
void UartNs550IntrHandler(void *CallBackRef, u32 Event, unsigned int EventData);
static int UartNs550SetupIntrSystem(INTC *IntcInstancePtr,
				XUartNs550 *UartInstancePtr,
				u16 UartIntrId);
static void UartNs550DisableIntrSystem(INTC *IntcInstancePtr, u16 UartIntrId);
int UartNs550Init(u16 DeviceId, XUartNs550 *UartNs550);

#endif /* SRC_RS485_INTR_RECV_H_ */

 八:结果总结

在串口助手中利用一个串口485发送数据,可以看到另一个串口PS端UART会打印出数据。

在本次实验中利用开发板PL端的1个RS485接口实现了PS端的中断控制通信,在代码设置一个RS485口为数据输入。

 此外:RS485通信等价于RS422通信的单路,也即RS485设置为输出时,其引脚A,B等同于RS422的T+和T-。设置为输入是,其引脚A,B等同于RS422的R+和R-。因此根据工程需要可以和RS422引脚直用杜邦线连接通信,两路RS485等于一路RS422。这样就不用把RS485频繁切换输入输出方向了。

  • 2
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值