当前位置:   article > 正文

FPGA串口(rs422)调试笔记_fpga rs422

fpga rs422

目录

前言

一、串口到底指的什么?

二、调试记录

1.先通过串口助手实现uart的发送与接收

2.编写top文件,把连续接收的8bit的数据拼接成16bit数据(之后需要的位数)

3.删去原USB程序,把串口程序拼上去

总结


前言

团队项目需求,由于USB通信存在数据被测试环境干扰的问题,且考虑到所需通信速率不高,所以转为串口通信,下面是自己的调试记录,方便自己理解与日后回顾。

一、串口到底指的什么?

了解之前,我也很疑惑,听到大家都在说串口啦,uart啦,rs232啦,rs422啦,rs485啦,说的我一脸懵逼。后来自己了解后,才发现其实类别都不同,不能放在一起说。

串口包含了uart,还包含usb等等,可以说是uart是串口,但串口不一定是uart,我是这样理解的,不知道对不对。串口是物理层次上说的,一般有两种形式的物理接口,DB9和4针的杜邦线插口。

uart包含了rs232,rs422和rs485这些接口标准。可以说这三种接口的物理层不同,输出的电平不同,但通信协议是一样的,也就是说,编程实现是一样的,只是硬件电路电路上不同,当然其传输速率,抗干扰能力等等也自不相同。

二、调试记录

1.先通过串口助手实现uart的发送与接收

从Xilinx嫖的uart接收与发送的例程,改改引脚定义:团队做的pcb用芯片把rs422电平转化为FPGA芯片识别的ttl电平,所以要做的就是得输进去一个rs422电平。

懵逼的我拿了个一头是usb另一头是DB9的线插上去,咦~怎么不管用啊。后来才发现这根线是usb转rs232的线。。。。。我拿了个rs232转rs422的转换器,接上后,咦~~~管用了。

后来加购了个usb直接转rs422电平的线,就可以了。(嘘,我原本以为,usb连接电脑,那边出来的只能是rs232的电平,之后回来再看的时候,不准笑话自己,哈哈哈)

代码如下(by Xilinx):

  1. `timescale 1ns / 1ps
  2. //
  3. //Module name uart_rx
  4. //Description: 16 个 clock 接收一个 bit16 个时钟采样,取中间的采样值
  5. //(by_Xilinx)
  6. //
  7. module uart_rx(
  8.     input                    clk, //采样时钟
  9.     input                    rst_n, //复位信号
  10.     input                    rx, //UART 数据输入
  11.     output   reg[7:0]    dataout, //接收数据输出
  12.     output    reg        rdsig, 
  13.     output    reg        dataerror, //数据出错指示
  14.     output    reg        frameerror//帧出错指示
  15. );
  16. reg [7:0] cnt;
  17. reg          rxbuf, rxfall, receive;
  18. parameter paritymode = 1'b0;
  19. reg         presult;
  20. reg          idle;//线路状态指示,高为线路忙,低为线路空闲
  21. always @(posedge clk) //检测线路的下降沿
  22.     begin
  23.         rxbuf <= rx;
  24.         rxfall <= rxbuf & (~rx);
  25.     end
  26. //启动串口接收程序
  27. always @(posedge clk)
  28.     begin
  29.         if (rxfall && (~idle)) begin//检测到线路的下降沿并且原先线路为空闲,启动接收数据进程
  30.             receive <= 1'b1;
  31.         end
  32.         else if(cnt == 8'd168) begin //接收数据完成
  33.             receive <= 1'b0;
  34.         end
  35.     end
  36. //串口接收程序, 16 个时钟接收一个 bit
  37. always @(posedge clk or negedge rst_n)
  38.     begin
  39.         if (!rst_n) begin
  40.             idle<=1'b0;
  41.             cnt<=8'd0;
  42.             rdsig <= 1'b0;
  43.             frameerror <= 1'b0
  44.             dataerror <= 1'b0; 
  45.             presult<=1'b0;
  46.         end 
  47.         else if(receive == 1'b1) begin
  48.         case (cnt)
  49.             8'd0:begin
  50.                 idle <= 1'b1;
  51.                 cnt <= cnt + 8'd1;
  52.                 rdsig <= 1'b0;
  53.             end
  54.             8'd24:begin //接收第 0 位数据
  55.                 idle <= 1'b1;
  56.                 dataout[0] <= rx;
  57.                 presult <= paritymode^rx;
  58.                 cnt <= cnt + 8'd1;
  59.                 rdsig <= 1'b0;
  60.             end
  61.             8'd40:begin //接收第 1 位数据 
  62.                 idle <= 1'b1;
  63.                 dataout[1] <= rx;
  64.                 presult <= presult^rx;
  65.                 cnt <= cnt + 8'd1;
  66.                 rdsig <= 1'b0;
  67.             end
  68.             8'd56:begin //接收第 2 位数据 
  69.                 idle <= 1'b1;
  70.                 dataout[2] <= rx;
  71.                 presult <= presult^rx;
  72.                 cnt <= cnt + 8'd1;
  73.                 rdsig <= 1'b0;
  74.             end
  75.             8'd72:begin //接收第 3 位数据 
  76.                 idle <= 1'b1;
  77.                 dataout[3] <= rx;
  78.                 presult <= presult^rx;
  79.                 cnt <= cnt + 8'd1;
  80.                 rdsig <= 1'b0;
  81.             end
  82.             8'd88:begin //接收第 4 位数据 
  83.                 idle <= 1'b1;
  84.                 dataout[4] <= rx;
  85.                 presult <= presult^rx;
  86.                 cnt <= cnt + 8'd1;
  87.                 rdsig <= 1'b0;
  88.             end
  89.             8'd104:begin //接收第 5 位数据 
  90.                 idle <= 1'b1;
  91.                 dataout[5] <= rx;
  92.                 presult <= presult^rx;
  93.                 cnt <= cnt + 8'd1;
  94.                 rdsig <= 1'b0;
  95.             end
  96.             8'd120:begin //接收第 6 位数据 
  97.                 idle <= 1'b1;
  98.                 dataout[6] <= rx;
  99.                 presult <= presult^rx;
  100.                 cnt <= cnt + 8'd1;
  101.                 rdsig <= 1'b0;
  102.             end
  103.             8'd136:begin //接收第 7 位数据 
  104.                 idle <= 1'b1;
  105.                 dataout[7] <= rx;
  106.                 presult <= presult^rx;
  107.                 cnt <= cnt + 8'd1;
  108.                 rdsig <= 1'b1;
  109.             end
  110.             8'd152:begin //接收奇偶校验位 
  111.                 idle <= 1'b1;
  112.             if(presult == rx)
  113.                 dataerror <= 1'b0;
  114.             else
  115.                 dataerror <= 1'b1; //如果奇偶校验位不对,表示数据出错
  116.                 cnt <= cnt + 8'd1;
  117.                 rdsig <= 1'b1;
  118.             end
  119.             8'd168:begin
  120.                 idle <= 1'b1;
  121.             if(1'b1 == rx)
  122.                 frameerror <= 1'b0;
  123.             else
  124.                 frameerror <= 1'b1; //如果没有接收到停止位,表示帧出错
  125.                 cnt <= cnt + 8'd1;
  126.                 rdsig <= 1'b1;
  127.             end
  128.             default: begin
  129.                 cnt <= cnt + 8'd1;
  130.             end
  131.         endcase
  132.     end
  133.             else begin
  134.                 cnt <= 8'd0;
  135.                 idle <= 1'b0;
  136.                 rdsig <= 1'b0;
  137.             end
  138.         end
  139. endmodule
  1. `timescale 1ns / 1ps
  2. //
  3. // Module Name: uart_tx
  4. // 说明:16 个 clock 发送一个 bit, 一个起始位,8 个数据位,一个校验位,一个停止位
  5. //
  6. module uart_tx(
  7. input clk, //UART 时钟
  8. input rst_n, //系统复位
  9. input [7:0] datain, //需要发送的数据
  10. input wrsig, //发送命令,上升沿有效
  11. output reg idle, //线路状态指示,高为线路忙,低为线路空闲
  12. output reg tx //发送数据信号
  13. );
  14. reg send;
  15. reg wrsigbuf, wrsigrise;
  16. reg presult;
  17. reg[7:0] cnt; //计数器
  18. parameter paritymode = 1'b0;
  19. //检测发送命令 wrsig 的上升沿
  20. always @(posedge clk)
  21. begin
  22. wrsigbuf <= wrsig;
  23. wrsigrise <= (~wrsigbuf) & wrsig;
  24. end
  25. //启动串口发送程序
  26. always @(posedge clk)
  27. begin
  28. if (wrsigrise && (~idle)) //当发送命令有效且线路为空闲时,启动新的数据发送进程
  29. begin
  30. send <= 1'b1;
  31. end
  32. else if(cnt == 8'd168) //一帧数据发送结束
  33. begin
  34. send <= 1'b0;
  35. end
  36. end
  37. //串口发送程序, 16 个时钟发送一个 bit
  38. always @(posedge clk or negedge rst_n)
  39. begin
  40. if (!rst_n) begin
  41. tx <= 1'b0;
  42. idle <= 1'b0;
  43. cnt<=8'd0;
  44. presult<=1'b0;
  45. end
  46. else if(send == 1'b1) begin
  47. case(cnt) //产生起始位
  48. 8'd0: begin
  49. tx <= 1'b0;
  50. idle <= 1'b1;
  51. cnt <= cnt + 8'd1;
  52. end
  53. 8'd16: begin
  54. tx <= datain[0]; //发送数据 0
  55. presult <= datain[0]^paritymode;
  56. idle <= 1'b1;
  57. cnt <= cnt + 8'd1;
  58. end
  59. 8'd32: begin
  60. tx <= datain[1]; //发送数据 1 位
  61. presult <= datain[1]^presult;
  62. idle <= 1'b1;
  63. cnt <= cnt + 8'd1;
  64. end
  65. 8'd48: begin
  66. tx <= datain[2]; //发送数据 2
  67. presult <= datain[2]^presult;
  68. idle <= 1'b1;
  69. cnt <= cnt + 8'd1;
  70. end
  71. 8'd64: begin
  72. tx <= datain[3]; //发送数据 3 位
  73. presult <= datain[3]^presult;
  74. idle <= 1'b1;
  75. cnt <= cnt + 8'd1;
  76. end
  77. 8'd80: begin
  78. tx <= datain[4]; //发送数据 4
  79. presult <= datain[4]^presult;
  80. idle <= 1'b1;
  81. cnt <= cnt + 8'd1;
  82. end
  83. 8'd96: begin
  84. tx <= datain[5]; //发送数据 5 位
  85. presult <= datain[5]^presult;
  86. idle <= 1'b1;
  87. cnt <= cnt + 8'd1;
  88. end
  89. 8'd112: begin
  90. tx <= datain[6]; //发送数据 6
  91. presult <= datain[6]^presult;
  92. idle <= 1'b1;
  93. cnt <= cnt + 8'd1;
  94. end
  95. 8'd128: begin
  96. tx <= datain[7]; //发送数据 7 位
  97. presult <= datain[7]^presult;
  98. idle <= 1'b1;
  99. cnt <= cnt + 8'd1;
  100. end
  101. 8'd144: begin
  102. tx <= presult; //发送奇偶校验位
  103. presult <= datain[0]^paritymode;
  104. idle <= 1'b1;
  105. cnt <= cnt + 8'd1;
  106. end
  107. 8'd160: begin
  108. tx <= 1'b1; //发送停止位
  109. idle <= 1'b1;
  110. cnt <= cnt + 8'd1;
  111. end
  112. 8'd168: begin
  113. tx <= 1'b1;
  114. idle <= 1'b0; //一帧数据发送结束
  115. cnt <= cnt + 8'd1;
  116. end
  117. default: begin
  118. cnt <= cnt + 8'd1;
  119. end
  120. endcase
  121. end
  122. else begin
  123. tx <= 1'b1;
  124. cnt <= 8'd0;
  125. idle <= 1'b0;
  126. end
  127. end
  128. endmodule

2.编写top文件,把连续接收的8bit的数据拼接成16bit数据(之后需要的位数)

光这个功能,搞了我两天,我也是崩了,有时候数据不变化,有时候错位(我就是个菜鸡)。

但好在自己看着Modelsim的仿真图,一点点改好了,接收到的十六位数据也正常了。这就是乐趣所在吧,在自己操作下,一点点实现它的价值,感觉就很棒!

3.删去原USB程序,把串口程序拼上去

先用Modelsim仿真,再用signaltap抓实时数据,最后用串口助手发送所需要的数据,成功被后续芯片接收,并测的有效果,表明已通过串口发送到目标芯片,并产生所需数据。

后续和团队软件人员沟通,作出一版通过串口发送的界面,再进行调试。


总结

第一次单独完成一个小功能,还是很开心的,记录下来,数年后再看看这个小菜鸡。

遇到问题,就想着去解决,不知道的东西,就去查资料,现在这个阶段所学的东西,肯定已经有人做过,参考一下,感谢CSDN能提供交流的平台。学无止境,继续前行。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/920108
推荐阅读
相关标签
  

闽ICP备14008679号