发 帖  
原厂入驻New
[经验]

【"小梅哥 AC620V2 FPGA 开发板"免费试用】+串口收发程序

2020-11-4 15:52:16  275 AC620V2 串口收发 CH341电路
分享
0
今天坐坐下串口收发程序。用FPGA于其他单片机的很大区别在于,用FPGA你必须弄懂芯片运行的正真时序。单片机只要有硬件支持,你仅需配置它的对应寄存器即可,除非引脚软件模拟时序控制。
串口作为最通用最常见的通讯接口之一,时序也是很经典。我们这里配置串口为115200-n-8-1的模式来进行通讯。
废话不多说。我们先看下硬件的布局(我们使用ch341 TTL转的虚拟串口):
CH341电路
C2.png
对应的引脚(A6-->TXD,B5-->RXD):
C1.png

好了我们下载开始写程序(程序参考自网络,写的很好,把每一功能分开独立开写,易读):
  1. //****************************************************************************************//
复制代码
接收模块程序:

  1. module uart_recv(
  2.     input                          sys_clk,                  //系统时钟
  3.     input             sys_rst_n,                //系统复位,低电平有效
  4.    
  5.     input             uart_rxd,                 //UART接收端口
  6.     output  reg       uart_done,                //接收一帧数据完成标志信号
  7.     output  reg [7:0] uart_data                 //接收的数据
  8.     );
  9.    
  10. //parameter define
  11. parameter  CLK_FREQ = 50000000;                 //系统时钟频率
  12. parameter  UART_BPS = 115200;                     //串口波特率
  13. localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,
  14.                                                 //需要对系统时钟计数BPS_CNT次
  15. //reg define
  16. reg        uart_rxd_d0;
  17. reg        uart_rxd_d1;
  18. reg [15:0] clk_cnt;                             //系统时钟计数器
  19. reg [ 3:0] rx_cnt;                              //接收数据计数器
  20. reg        rx_flag;                             //接收过程标志信号
  21. reg [ 7:0] rxdata;                              //接收数据寄存器 8位

  22. //wire define
  23. wire       start_flag;

  24. //*****************************************************
  25. //**                    main code
  26. //*****************************************************
  27. //捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
  28. assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);   

  29. //对UART接收端口的数据延迟两个时钟周期
  30. always @(posedge sys_clk or negedge sys_rst_n) begin
  31.     if (!sys_rst_n) begin
  32.         uart_rxd_d0 <= 1'b0;
  33.         uart_rxd_d1 <= 1'b0;         
  34.     end
  35.     else begin
  36.         uart_rxd_d0  <= uart_rxd;                  
  37.         uart_rxd_d1  <= uart_rxd_d0;
  38.     end   
  39. end

  40. //当脉冲信号start_flag到达时,进入接收过程           
  41. always @(posedge sys_clk or negedge sys_rst_n) begin         
  42.     if (!sys_rst_n)                                 
  43.         rx_flag <= 1'b0;
  44.     else begin
  45.         if(start_flag)                          //检测到起始位
  46.             rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
  47.         else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))//单次接收9bit( N 8 1 模式)
  48.             rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程
  49.         else
  50.             rx_flag <= rx_flag;
  51.     end
  52. end

  53. //进入接收过程后,启动系统时钟计数器与接收数据计数器
  54. always @(posedge sys_clk or negedge sys_rst_n) begin         
  55.     if (!sys_rst_n) begin                             
  56.         clk_cnt <= 16'd0;                                 
  57.         rx_cnt  <= 4'd0;
  58.     end                                                      
  59.     else if ( rx_flag ) begin                   //处于接收过程 (一个波特率脉冲)
  60.             if (clk_cnt < BPS_CNT - 1) begin
  61.                 clk_cnt <= clk_cnt + 1'b1;
  62.                 rx_cnt  <= rx_cnt;
  63.             end
  64.             else begin
  65.                 clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
  66.                 rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1(接收的BIT加1)
  67.             end
  68.         end
  69.         else begin                              //接收过程结束,计数器清零
  70.             clk_cnt <= 16'd0;
  71.             rx_cnt  <= 4'd0;
  72.         end
  73. end

  74. //根据接收数据计数器来寄存uart接收端口数据
  75. always @(posedge sys_clk or negedge sys_rst_n) begin
  76.     if ( !sys_rst_n)  
  77.         rxdata <= 8'd0;                                    
  78.     else if(rx_flag)                            //系统处于接收过程
  79.         if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
  80.             case ( rx_cnt )
  81.              4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
  82.              4'd2 : rxdata[1] <= uart_rxd_d1;
  83.              4'd3 : rxdata[2] <= uart_rxd_d1;
  84.              4'd4 : rxdata[3] <= uart_rxd_d1;
  85.              4'd5 : rxdata[4] <= uart_rxd_d1;
  86.              4'd6 : rxdata[5] <= uart_rxd_d1;
  87.              4'd7 : rxdata[6] <= uart_rxd_d1;
  88.              4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
  89.              default:;                                    
  90.             endcase
  91.         end
  92.         else
  93.             rxdata <= rxdata;
  94.     else
  95.         rxdata <= 8'd0;
  96. end

  97. //数据接收完毕后给出标志信号并寄存输出接收到的数据
  98. always @(posedge sys_clk or negedge sys_rst_n) begin        
  99.     if (!sys_rst_n) begin
  100.         uart_data <= 8'd0;                              
  101.         uart_done <= 1'b0;
  102.     end
  103.     else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
  104.         uart_data <= rxdata;                    //寄存输出接收到的数据
  105.         uart_done <= 1'b1;                      //并将接收完成标志位拉高
  106.     end
  107.     else begin
  108.         uart_data <= 8'd0;                                   
  109.         uart_done <= 1'b0;
  110.     end   
  111. end

  112. endmodule       
复制代码
发送模块程序:


  1. <font color="#ff0000" size="4">//

  2. <!--StartFragment-->uart_en<!--EndFragment--> 实际与接收结束uart_done的标志是一个信号,当接收结束后会从0-->1 ,所以会产生一个上升沿 </font>
复制代码
编译仿真无误,配置对应管脚:
C3.png
再次全局编译,下载,观看串口现象:
C4.png




评论

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发经验
关闭

站长推荐 上一条 /9 下一条

快速回复 返回顶部 返回列表