ACX720开发板关于串口多字节发送模块学习——参考教材小梅哥版本

1.多字节串口发送原理与设计思路

错误示例 :8N1 (八个数据,没有奇偶效检位,一个停止位),认为只要填充起始信号和停止信号就可以了,例如串口发送Ox1234,串口模拟输出0_0010_1100_0100_1000_1 ;(LSB)小端读取方式。

这种数据按照8N1进行解析的话,提取其中的数据位,一次解析要接收10位数据,如果解析正确的话,提取中间的8位有效的数据。要解析到16位的Ox1234的话就要解析两次,也就是需要20位数据。模拟串口时,仅仅发送了18位数据,所以无论最终解析出来是什么,都不会得到我们期望收到的Ox1234。

所以正确的传输需要分成两次,第一次传输0_0100_1000_1 , 第二次传输0_0010_0110_1,传输过程如图所示

将两个8位的数据拼接后得到Ox1234 

所以我们可以把多字节的串口发送,看成连续的多个单字节数据串口发送的过程。设计思路只需要将待发送的数据拆分成多个单字节,然后调用之前写好的单字节发送模块逐个进行发送,就可以实现多字节串口数据的发送。

2.多字节串口发送原理

为了保证发送数据的连续性,可以改使用单字节串口发送完成信号byte_tx_done 作为条件信号,

1.byte_tx_done 拉高时候,说明一个字节的数据发送完成  ,此时就输出下一字节数据给单字节串口发送模块。  一次多字节串口发送,发送数据量是确定的。串口也不可能一直发送下去,因此我2每次发送完成,判断数据是否发送完成。3 信号计算当前已经发送的数据再与信号位宽进行进行比较,判断整个信号发送过程是否完成。产生串口发送完成信号,本次传输结束。设计可以使用状态机来判断字节是否发送完成。下图是整体设计框架图

从上图可以看出,uart_data_tx设计框架中包含两个模块,一个是调用直接调用uart_byte_tx模块,然后利用有限状态机来设计信号数据发送的具体流程。

2.1总输入输出信号

module uart_data_tx(
    clk , 
    reset_n ,
    baud_set ,
    send_en ,
    data , 
    
    uart_tx ,
    uart_state ,
    tx_done 
    );

2.2例化data_byte_tx模块

uart_byte_tx       uart_byte_tx_inst1 (
   .send_en                 (byte_send_en  )       ,
   .data_byte               (data_byte)       ,
   .baud_set                (baud_set )       ,
   .clk                     (clk      )       ,
   .reset_n                 (reset_n  )       , 
                            
   .uart_tx                 (uart_tx  )       ,
   .tx_done                 (byte_tx_done  )       , 
   .uart_state              (uart_state)
    );

2.3状态机设计FSM  

1.发送使能,等待数据发送。

2.byte_send_en 拉高,单个字节发送,分为两种接收数据模式,一个是MSB(大端字节序),一个是小端字节序(LSB)。

3,传送完成后,判断是否单个字节是否发送完成,拉高byte_tx_done信号电平,同时字节计数器累加传输位宽。

4.计数器计数的位宽数据值与传输位宽进行对比判断数据是否传输完成。没有完成的haul数据就继续传送。

//FSM  module
localparam          S0  = 0 ;  //SO状态是等待发送使能状态
localparam          S1  = 1 ;  //发起单字节数据发送
localparam          S2  = 2 ;  //等待单字节数据发送完成
localparam          S3  = 3 ;  //检查所有数据是否传输完成 

reg    [1 : 0 ]       state ;    //定义传输状态
reg    [ 8 : 0 ]       cnt   ;   //计数

always @ (posedge clk or negedge reset_n) begin 
    if (!reset_n) begin
         byte_send_en  <= 1'b0 ;
         data_byte [ 7 :0 ] <= 8'b0 ;
         tx_done <= 1'b0 ;
         cnt <= 8'b0 ;
    end
    else begin 
        case (state ) 
     
     S0 :  begin
           data_byte <= 8'b0 ; 
           tx_done <= 1'b0 ;
           cnt <= 8'b0 ;
        
           if (send_en) begin 
              state <=  S1 ; 
              data_r <= data ; 
           end
           else begin 
               state <= S0 ; 
              data_r <= data_r ; 
           end
      end
      S1 : begin 
          byte_send_en <= 1'b1 ;
          if (MSB_FIRST == 1 ) begin   // 大端字节序
               data_byte  <= data_r[DATA_WIDTH - 1 : DATA_WIDTH - 8 ] ;
               data_r  <= data_r << 8 ; 
           end
          else begin
               data_byte <=data_r [7 : 0 ] ;
               data_r <= data_r >> 8 ;  //小端传送
         end
          state <= S2 ;
       end
       
       S2: begin 
           byte_send_en <= 1'b0;
           
           if (byte_tx_done  == 1 ) begin
                state <= S3 ; 
                cnt  <= cnt + 9 'd8 ;
           end
           else 
                state <= S2 ; 
        end
        
      S3 : begin 
           if (cnt >= DATA_WIDTH ) begin   //大于位宽说明传输完成
               state <= S0 ;
               cnt  <= 0 ;
               tx_done <= 1'b1 ;
          end
          else  begin 
               state <= S1 ;
               tx_done <= 1'b0 ; 
          end
        end
      default : state <= S0 ;
      endcase
end
end

3.testbench仿真 

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/10/17 15:58:55
// Design Name: 
// Module Name: uart_data_tx_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`define CLK_PERIOD  20
 //时钟周期为20ns
module uart_data_tx_tb();
    parameter  DATA_WIDTH  = 32 ;
    parameter  MSB_FIRST = 0  ;  //小端字节序
    reg         clk ; 
    reg         reset_n ; 
   
    reg               send_en ; // 发送使能
    reg   [DATA_WIDTH - 1 : 0 ]     data ;   //输入数据
    
    wire           uart_tx ;
    wire           uart_state ; 
    wire          tx_done ;  
    
   //module instiation
   uart_data_tx # (
       .DATA_WIDTH (DATA_WIDTH) ,
       .MSB_FIRST(MSB_FIRST)
   )
   uart_data_inst(
               .clk                   (clk        )       ,      
               .reset_n               (reset_n    )       ,  
               .baud_set              (3'd4   )       , //波特率115200
               .send_en               (send_en    )       ,  
               .data                  (data       )       ,     
                                     
               .uart_tx               (uart_tx    )       ,  
               .uart_state            (uart_state )       ,
               .tx_done               (tx_done    )
   );
    
  initial    clk = 1 ;
  always #(`CLK_PERIOD / 10)   clk = !clk ;  //时钟翻转
  
  initial begin 
      reset_n = 0 ;
      data = 0 ; 
      send_en = 0 ; 
      #(`CLK_PERIOD * 10 + 1) ;
      reset_n = 1 ;
      #(`CLK_PERIOD * 100) ;
      data = 32'haabbccdd;
      send_en = 1'b1 ;
      #(`CLK_PERIOD ) ;
      send_en = 1'b0 ;
      #(`CLK_PERIOD ) ;
      @(posedge tx_done ) ;
      
      #1
      data = 32'h11223344 ;
      send_en = 1'b1 ;
      #(`CLK_PERIOD ) 
      send_en = 1'b0 ;
      #(`CLK_PERIOD) ;
      @(posedge tx_done ) 
      #1 ;
      #2000 ;
      $stop ;
 end
  
endmodule

仿真结果图

小端字节序(LSB)仿真结果图

发送数据aabbccdd  ,和11223344,data_byte的发送为 dd cc  bb aa , 和 44 33 22 11 说明发送阶段完成。

同理大端字节序(MSB)结果图

aa , bb ,cc ,dd   11 22 33 44 。

总结:

本次设计运用了合理的拆分字节发送,将多个字节的发送拆分成单个字节的发送,通过FSM状态机的设计来判断字节发送中各种情况和步骤,设计思路很巧妙,层次化设计明显。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值