回答

收藏

[评测分享] 【超越者Spartan-6 FPGA开发板】 + 数码管显示接收的串口数据

#板卡评测 #板卡评测 4737 人阅读 | 0 人回复 | 2021-05-28

        在上篇https://www.cirmall.com/bbs/thread-205909-1-1.html的基础上来学习串口的接收处理,
    实现的功能:将接收的到的串口数据以十进制的方式显示在开发板的数码管上。



    一、硬件部分


    和上篇一样的硬件电路,使用串口COM2接收。


    二、程序部分
   
    2.1、串口接收部分
   
  1. //****************************************Copyright (c)***********************************//
  2. //原子哥在线教学平台:www.yuanzige.com
  3. //技术支持:www.openedv.com
  4. //淘宝店铺:http://openedv.taobao.com
  5. //关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
  6. //版权所有,盗版必究。
  7. //Copyright(C) 正点原子 2018-2028
  8. //All rights reserved                                       
  9. //----------------------------------------------------------------------------------------
  10. // File name:           uart_recv
  11. // Last modified Date:  2019/10/9 9:56:36
  12. // Last Version:        V1.1
  13. // Descriptions:        UART串口接收模块
  14. //----------------------------------------------------------------------------------------
  15. // Created by:          正点原子
  16. // Created date:        2019/10/9 9:56:36
  17. // Version:             V1.0
  18. // Descriptions:        The original version
  19. //
  20. //----------------------------------------------------------------------------------------
  21. //****************************************************************************************//

  22. module uart_recv(
  23.     input                             sys_clk,                  //系统时钟
  24.     input              sys_rst_n,                //系统复位,低电平有效
  25.    
  26.     input              uart_rxd,                 //UART接收端口
  27.     output  reg        uart_done,                //接收一帧数据完成标志
  28.     output  reg        rx_flag,                  //接收过程标志信号
  29.     output  reg [ 3:0] rx_cnt,                  //接收数据计数器
  30.     output  reg [ 7:0] rxdata,
  31.     output  reg [7:0]  uart_data                 //接收的数据
  32.     );
  33.    
  34. //parameter define
  35. parameter   CLK_FREQ = 50000000;                //系统时钟频率
  36. parameter   UART_BPS = 9600;                    //串口波特率
  37. localparam  BPS_CNT  = CLK_FREQ/UART_BPS;       //为得到指定波特率,
  38.                                                 //需要对系统时钟计数BPS_CNT次
  39. //reg define
  40. reg        uart_rxd_d0;
  41. reg        uart_rxd_d1;
  42. reg [15:0] clk_cnt;                              //系统时钟计数器

  43. //wire define
  44. wire       start_flag;

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

  50. //对UART接收端口的数据延迟两个时钟周期
  51. always @(posedge sys_clk or negedge sys_rst_n)
  52. begin
  53.     if (!sys_rst_n)
  54.                 begin
  55.         uart_rxd_d0 <= 1'b0;
  56.         uart_rxd_d1 <= 1'b0;         
  57.                 end
  58.     else
  59.                 begin
  60.         uart_rxd_d0  <= uart_rxd;                  
  61.         uart_rxd_d1  <= uart_rxd_d0;
  62.     end   
  63. end

  64. //当脉冲信号start_flag到达时,进入接收过程           
  65. always @(posedge sys_clk or negedge sys_rst_n)
  66. begin         
  67.     if (!sys_rst_n)                                 
  68.         rx_flag <= 1'b0;
  69.     else begin
  70.         if(start_flag)                          //检测到起始位
  71.             rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
  72.                                                 //计数到停止位中间时,停止接收过程
  73.         else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2))
  74.             rx_flag <= 1'b0;                    //接收过程结束,标志位rx_flag拉低
  75.         else
  76.             rx_flag <= rx_flag;
  77.     end
  78. end

  79. //进入接收过程后,启动系统时钟计数器
  80. always @(posedge sys_clk or negedge sys_rst_n)
  81. begin         
  82.     if (!sys_rst_n)                             
  83.         clk_cnt <= 16'd0;                                 
  84.     else if ( rx_flag )
  85.                 begin                   //处于接收过程
  86.         if (clk_cnt < BPS_CNT - 1)
  87.             clk_cnt <= clk_cnt + 1'b1;
  88.         else
  89.             clk_cnt <= 16'd0;                       //对系统时钟计数达一个波特率周期后清零
  90.     end
  91.     else                                                             
  92.         clk_cnt <= 16'd0;                                                //接收过程结束,计数器清零
  93. end

  94. //进入接收过程后,启动接收数据计数器
  95. always @(posedge sys_clk or negedge sys_rst_n)
  96. begin         
  97.     if (!sys_rst_n)                             
  98.         rx_cnt  <= 4'd0;
  99.     else if ( rx_flag )
  100.                 begin                   //处于接收过程
  101.         if (clk_cnt == BPS_CNT - 1)                                //对系统时钟计数达一个波特率周期
  102.             rx_cnt <= rx_cnt + 1'b1;                        //此时接收数据计数器加1
  103.         else
  104.             rx_cnt <= rx_cnt;      
  105.                 end
  106.          else
  107.         rx_cnt  <= 4'd0;                                                //接收过程结束,计数器清零
  108. end

  109. //根据接收数据计数器来寄存uart接收端口数据
  110. always @(posedge sys_clk or negedge sys_rst_n)
  111. begin
  112.     if ( !sys_rst_n)  
  113.         rxdata <= 8'd0;                                    
  114.     else if(rx_flag)                            //系统处于接收过程
  115.         if (clk_cnt == BPS_CNT/2)
  116.                         begin         //判断系统时钟计数器计数到数据位中间
  117.             case ( rx_cnt )
  118.              4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
  119.              4'd2 : rxdata[1] <= uart_rxd_d1;
  120.              4'd3 : rxdata[2] <= uart_rxd_d1;
  121.              4'd4 : rxdata[3] <= uart_rxd_d1;
  122.              4'd5 : rxdata[4] <= uart_rxd_d1;
  123.              4'd6 : rxdata[5] <= uart_rxd_d1;
  124.              4'd7 : rxdata[6] <= uart_rxd_d1;
  125.              4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
  126.              default:;                                    
  127.             endcase
  128.         end
  129.         else
  130.             rxdata <= rxdata;
  131.     else
  132.         rxdata <= 8'd0;
  133. end

  134. //数据接收完毕后给出标志信号并寄存输出接收到的数据
  135. always @(posedge sys_clk or negedge sys_rst_n)
  136. begin        
  137.     if (!sys_rst_n)
  138.                 begin
  139.         uart_data <= 8'd0;                              
  140.         uart_done <= 1'b0;
  141.                 end
  142.     else if(rx_cnt == 4'd9)
  143.                 begin               //接收数据计数器计数到停止位时           
  144.         uart_data <= rxdata;                    //寄存输出接收到的数据
  145.         uart_done <= 1'b1;                      //并将接收完成标志位拉高
  146.                 end
  147.     else
  148.                 begin
  149.         uart_data <= 8'd0;                                   
  150.         uart_done <= 1'b0;
  151.                 end   
  152. end

  153. endmodule       
复制代码
     2.2、接收到的数据处理部分
   

  1. module uart_hdl(
  2.         input                   sys_clk,                   //系统时钟
  3.         input            sys_rst_n,                 //系统复位,低电平有效

  4.         input            recv_done,                 //接收一帧数据完成标志
  5.         input      [7:0] recv_data,                 //接收的数据

  6.         input            tx_busy,                   //发送忙状态标志      
  7.         output reg       send_en,                   //发送使能信号
  8.         output reg [7:0] send_data,                  //待发送数据
  9.         output reg [7:0] led_data                  //待发送数据
  10.     );
  11.          
  12.          
  13. //reg define
  14. reg recv_done_d0;
  15. reg recv_done_d1;
  16. reg tx_ready;



  17. //wire define
  18. wire recv_done_flag;

  19. //*****************************************************
  20. //**                    main code
  21. //*****************************************************




  22. //捕获recv_done上升沿,得到一个时钟周期的脉冲信号
  23. assign recv_done_flag = (~recv_done_d1) & recv_done_d0;
  24.                                                 
  25. //对发送使能信号recv_done延迟两个时钟周期
  26. always @(posedge sys_clk or negedge sys_rst_n) begin         
  27.     if (!sys_rst_n) begin
  28.         recv_done_d0 <= 1'b0;                                 
  29.         recv_done_d1 <= 1'b0;
  30.     end                                                      
  31.     else begin                                               
  32.         recv_done_d0 <= recv_done;                              
  33.         recv_done_d1 <= recv_done_d0;                           
  34.     end
  35. end

  36. //判断接收完成信号,并在串口发送模块空闲时给出发送使能信号
  37. always @(posedge sys_clk or negedge sys_rst_n) begin         
  38.     if (!sys_rst_n) begin
  39.         tx_ready  <= 1'b0;
  40.         send_en   <= 1'b0;
  41.         send_data <= 8'd0;
  42.     end                                                      
  43.     else begin                                               
  44.         if(recv_done_flag)begin                 //检测串口接收到数据
  45.             tx_ready  <= 1'b1;                  //准备启动发送过程
  46.             send_en   <= 1'b0;
  47.             send_data <= recv_data;             //寄存串口接收的数据
  48.                                 led_data <= recv_data;
  49.         end
  50.         else if(tx_ready && (~tx_busy)) begin   //检测串口发送模块空闲
  51.             tx_ready <= 1'b0;                   //准备过程结束
  52.             send_en  <= 1'b1;                   //拉高发送使能信号
  53.         end
  54.     end
  55. end


  56. endmodule
复制代码

    2.3、顶层设计


    将接收的串口数据送到动态数码管


  1. module fpga_test (
  2.         input               sys_clk  ,       // 系统时钟
  3.         input               sys_rst_n,       // 系统复位信号(低有效)
  4.         input                          touch_key,             // 触摸按键

  5.         output    [5:0]     seg_sel  ,       // 数码管位选
  6.         output    [7:0]     seg_led ,        // 数码管段选
  7.         output    [3:0]            led  ,                        //4个LED灯
  8.         output                        beep,
  9.        
  10.         //串口COM2
  11.         input           uart_rxd,           //UART接收端口
  12.         output          uart_txd            //UART发送端口
  13. );

  14. //parameter define
  15. parameter  TIME_SHOW = 25'd25000_000;   // 数码管变化的时间间隔0.5s
  16. parameter  CLK_FREQ = 50000000;         //定义系统时钟频率
  17. parameter  UART_BPS = 115200;           //定义串口波特率
  18. parameter  led_en = 1;
  19. //wire define
  20. wire                 flag;                         // 数码管变化的通知信号
  21. wire     flag_10ms;
  22. wire                 key_val;

  23. //wire define
  24. wire    [19:0]  data;                 // 数码管显示的数值
  25. wire    [ 5:0]  point;                // 数码管小数点的位置
  26. wire            en;                   // 数码管显示使能信号
  27. wire            sign;                 // 数码管显示数据的符号位

  28. wire       uart_recv_done;              //UART接收完成
  29. wire [7:0] uart_recv_data;              //UART接收数据
  30. wire       uart_send_en;                //UART发送使能
  31. wire [7:0] uart_send_data;              //UART发送数据
  32. wire       uart_tx_busy;                //UART发送忙状态标志


  33. //*****************************************************
  34. //**                    main code
  35. //*****************************************************

  36. //动态LED数码管驱动
  37. seg_led_dynamic u_seg_led_dynamic(
  38.         .clk                (sys_clk),
  39.         .rst_n        (sys_rst_n),
  40.        
  41.         .data          (data     ),       // 显示的数值
  42.         .point         (point    ),       // 小数点具体显示的位置,高电平有效
  43.    .en            (led_en),//(en       ),       // 数码管使能信号
  44.    .sign          (sign     ),       // 符号位,高电平显示负号(-)
  45.    
  46.    .seg_sel       (seg_sel  ),       // 位选
  47.    .seg_led       (seg_led  )        // 段选
  48. );



  49. //串口接收模块     
  50. uart_recv #(                          
  51.     .CLK_FREQ       (CLK_FREQ),         //设置系统时钟频率
  52.     .UART_BPS       (UART_BPS))         //设置串口接收波特率
  53. u_uart_recv(                 
  54.     .sys_clk        (sys_clk),
  55.     .sys_rst_n      (sys_rst_n),
  56.    
  57.     .uart_rxd       (uart_rxd),
  58.     .uart_done      (uart_recv_done),
  59.     .uart_data      (uart_recv_data)
  60.     );
  61.          
  62. //串口处理   
  63. uart_hdl u_uart_hdl(
  64.     .sys_clk        (sys_clk),            
  65.     .sys_rst_n      (sys_rst_n),           
  66.    
  67.     .recv_done      (uart_recv_done),   
  68.     .recv_data      (uart_recv_data),   

  69.          .led_data       (data)      
  70. );
  71. endmodule
复制代码

    三、执行结果

    在串口上发送十六进制数,开发板显示对应的十进制数
   


   


   


002.jpg (2.32 MB, 下载次数: 36)

002.jpg
分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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