• ZYNQ UltraScale MPSOC,使用PL端AXI_UART16550IP核,且在PS端控制下实现RS485通信-----轮询方式


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

    软件环境:Vivado2018.3

    目录

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

    软件环境:Vivado2018.3

    一:新建工程

    二:芯片配置

     三:添加IP核

     四:引脚绑定,并生成bitstream

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

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

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

     八:结果总结

    九:下一篇讲述使用UART16550的中断模式接收多种帧长的报文数据,也即接收不定长数据。


    一:新建工程

            打开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端代码:废话少说直接上代码:

    1. #include <stdio.h>
    2. #include "xil_printf.h"
    3. #include "xgpio.h"
    4. #include "xuartns550.h"
    5. #include "sleep.h"
    6. #include "RS485_process.h"
    7. XUartNs550Format UartNs550Format =
    8. {
    9. 115200,
    10. XUN_FORMAT_8_BITS,
    11. XUN_FORMAT_NO_PARITY,
    12. XUN_FORMAT_1_STOP_BIT
    13. };
    14. #define DE0_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
    15. #define DE1_DEVICE_ID XPAR_GPIO_1_DEVICE_ID
    16. XGpio rs485_0_de ;
    17. XGpio rs485_1_de ;
    18. XUartNs550 UartNs550_0;
    19. XUartNs550 UartNs550_1;
    20. /*
    21. * For UART16550 module,The following constant controls the length of the buffers to be sent
    22. * and received with the UART, this constant must be 16 bytes or less since
    23. * this is a single threaded non-interrupt driven example such that the
    24. * entire buffer will fit into the transmit and receive FIFOs of the UART
    25. */
    26. #define TEST_BUFFER_SIZE 200
    27. u8 SendBuffer[TEST_BUFFER_SIZE]; /* Buffer for Transmitting Data */
    28. u8 RecvBuffer[TEST_BUFFER_SIZE]; /* Buffer for Receiving Data */
    29. u8 *RecvBufferPtr;
    30. volatile u32 TotalRecvCnt;
    31. char RS485_Recv_flag = 0;
    32. int main()
    33. {
    34. int Status;
    35. RecvBufferPtr = RecvBuffer;
    36. Status = RS485_Init();
    37. /* wait 1ms */
    38. usleep(1000) ;
    39. memset(RecvBuffer, 0, TEST_BUFFER_SIZE) ;
    40. while(1)
    41. {
    42. RS485_Recv_Data();
    43. RS485_Send_Out(char *Send_data,int n);
    44. }
    45. return 0;
    46. }
    47. int RS485_Send_Out(char *Send_data,int n)
    48. {
    49. /* RS485_1 TX */
    50. XGpio_DiscreteWrite(&rs485_1_de, 1, 1);
    51. if(RS485_Recv_flag == 1){
    52. for(int j = 0;j<n;j++)
    53. {
    54. XUartNs550_SendByte(UartNs550_1.BaseAddress, Send_data[j]);
    55. }
    56. RS485_Recv_flag = 0;
    57. }
    58. return 0;
    59. }
    60. void RS485_Recv_Data()
    61. {
    62. u32 ReceivedCount = 0;
    63. u8 flag = 0;
    64. /* RS485_0 RX FROM*/
    65. XGpio_DiscreteWrite(&rs485_0_de, 1, 0);
    66. if(XUartNs550_IsReceiveData(UartNs550_0.BaseAddress))
    67. {
    68. ReceivedCount = XUartNs550_Recv(&UartNs550_0, RecvBufferPtr, 1); //接收一下
    69. TotalRecvCnt += ReceivedCount ;
    70. RecvBufferPtr += ReceivedCount ;
    71. }
    72. if (TotalRecvCnt== TEST_BUFFER_SIZE) {
    73. RecvBufferPtr = RecvBuffer;
    74. TotalRecvCnt = 0;
    75. ReceivedCount = 0;
    76. flag =1;
    77. }
    78. if(flag ==1){
    79. for(int j = 0; j<TEST_BUFFER_SIZE;j++)
    80. {
    81. SendBuffer[j] = RecvBuffer[j];
    82. }
    83. flag = 0;
    84. RS485_Recv_flag = 1;
    85. }
    86. }
    87. int RS485_Init()
    88. {
    89. int Status;
    90. /* Initial RS485_0 DE */
    91. PLGpioInitial(&rs485_0_de, DE0_DEVICE_ID) ;
    92. /* Initial RS485_1 DE */
    93. PLGpioInitial(&rs485_1_de, DE1_DEVICE_ID) ;
    94. xil_printf("Start UART485 Send Test!\r\n");
    95. /* Initial UART16550 which connected to RS485_0 */
    96. Status = UartNs550Initial(XPAR_AXI_UART16550_0_DEVICE_ID, &UartNs550_0) ;
    97. if (Status != XST_SUCCESS) {
    98. xil_printf("RS485_0 Initial Failed!\r\n");
    99. return XST_FAILURE;
    100. }
    101. /* Initial UART16550 which connected to RS485_1 */
    102. Status = UartNs550Initial(XPAR_AXI_UART16550_1_DEVICE_ID, &UartNs550_1) ;
    103. if (Status != XST_SUCCESS) {
    104. xil_printf("RS485_1 Initial Failed!\r\n");
    105. return XST_FAILURE;
    106. }
    107. /*Set rs485_1 to tx*/
    108. XGpio_DiscreteWrite(&rs485_1_de, 1, 1);
    109. /* Set rs485_0 to rx*/
    110. XGpio_DiscreteWrite(&rs485_0_de, 1, 0);
    111. return 0;
    112. }
    113. int PLGpioInitial(XGpio *GpioInstPtr, u16 DeviceId)
    114. {
    115. int Status ;
    116. /* initial gpio */
    117. Status = XGpio_Initialize(GpioInstPtr, DeviceId) ;
    118. if (Status != XST_SUCCESS)
    119. return XST_FAILURE ;
    120. /* set gpio as output */
    121. XGpio_SetDataDirection(GpioInstPtr, 1, 0x0);
    122. return XST_SUCCESS ;
    123. }
    124. int UartNs550Initial(u16 DeviceId, XUartNs550 *UartNs550)
    125. {
    126. int Status;
    127. u16 Options;
    128. /*
    129. * Initialize the UART Lite driver so that it's ready to use,
    130. * specify the device ID that is generated in xparameters.h
    131. */
    132. Status = XUartNs550_Initialize(UartNs550, DeviceId);
    133. if (Status != XST_SUCCESS) {
    134. return XST_FAILURE;
    135. }
    136. /*
    137. * Perform a self-test to ensure that the hardware was built correctly
    138. */
    139. Status = XUartNs550_SelfTest(UartNs550);
    140. if (Status != XST_SUCCESS) {
    141. return XST_FAILURE;
    142. }
    143. /*
    144. * Enable the local loopback so data that is sent will be received,
    145. * and keep the FIFOs enabled
    146. */
    147. Options = XUN_OPTION_FIFOS_ENABLE;
    148. XUartNs550_SetOptions(UartNs550, Options);
    149. /* Set uart mode Baud Rate 115200, 8bits, no parity, 1 stop bit */
    150. XUartNs550_SetDataFormat(UartNs550, &UartNs550Format);
    151. return XST_SUCCESS;
    152. }

     八:结果总结

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

    在本次实验中利用开发板PL端的两个RS485接口实现了PS端的控制通信,在代码设置一个RS485口为输出,一个RS485口为数据输入。这样就不用切换使用一个RS485口了。

    因为RS485是半双工通信,完全可以利用一个RS485就可以实现数据的输入和输出,只是要翻转一下DE控制引脚,因此本实验只需修改为只使用RS485_0也可,代码里增加每次接收数据设置为接收方向,输出时设置为输出方向,并注意核对串口输出地址为同一个串口下(因为本实验有两个会错乱)。

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

    九:下一篇讲述使用UART16550的中断模式接收多种帧长的报文数据,也即接收不定长数据。

  • 相关阅读:
    pandas 怎么样扩展数据,就是把加权数据,转换成个案数据
    【小尘送书-第九期】《Excel数据透视表应用大全for Excel 365 & Excel 2019》
    React教程之 React 中 Render Props 和高阶组件HOC的详细介绍
    Python小练习一
    12款爆款项目管理工具推荐
    快手安全 X 墨菲安全 | 软件供应链安全解决方案完整分享
    Saas.弹性架构设计思考
    el-table如何实现自动缩放,提示隐藏内容
    70. 爬楼梯进阶版
    系统架构设计:14 论软基于架构的软件设计方法(ABSD)的软件开发
  • 原文地址:https://blog.csdn.net/howe1233/article/details/125439090