ACX720学习板中串口发送与验证模块的总结——参考小梅哥教程

1 常见协议种类

UART - 通用串口异步协议 

IIC   -  双向两线总线  

SPI  - 串口外行外围总线

USB2.0/3.0 通用串行总线

Ethernet  以太网 

本次以UART (通用串行总线协议来)说明程序设计和基础原理

2 RS232 通信标准

RS-232标准中,最常用的配置是8N1(8个数据位,无奇偶校验位,一个停止位)

下图为uart中发送一个字节的时序图 

3设计框图   

 端口信号设计见下图,图中左边为输入信号,右侧是输出信号

 系统子模块的结构图,绿色部分表示单一的寄存器

各个子模块之间的描述和作用

波特率时钟生成模块

波特率是如何计算: 举例 :假设系统时钟频率为50mhz  系统的周期就是20ns,假定波特率为9600hz  波特率周期则为104167ns,波特率分频计数值 104167 / 20  = 5208  从0开始计数 ,也就是9600hz波特率下面, 要传输1bit的信号,50mhz的系统时钟需要计数 5208 -1 次 ,下图为四种常见的波特率时钟的计数方法。

LUT查找表模块

/LUT查找表模块,查找匹配的波特率分频计数最大值,根据波特率确定每1s钟传输的最大为比特数,选择波特率
always@(posedge clk or posedge rst_n) 
    if ( rst_n ) begin 
       bps_DR <= 16'd5207 ;
    end
    else begin
              case ( baud_set) 
        0 :  bps_DR <= 16'd5207 ;
        1 :  bps_DR <= 16'd2603 ;
        2 :  bps_DR <= 16'd1301 ;
        3 :  bps_DR <= 16'd867 ;
        4 :  bps_DR <= 16'd433 ;
        default : bps_DR <= 16'd5207 ;
            endcase 
         end

计数器生成波特率时钟模块

本模块设计:先进行分频计数模块,确定对应的波特率之后,计数到相对应的波特率的最大值计数

bps_DR ; 然后设计波特率时钟更新模块。div_cnt计数器梅重新计数到1的时候波特率时钟进行更新

// 分频计数模块
always @ (posedge clk or posedge rst_n) begin 
    if (rst_n) begin 
        div_cnt <= 16'd0 ;
     end
     else if (uart_state ) begin
         if (div_cnt == bps_DR) 
         div_cnt <= 16'd0 ;
      else  
          div_cnt <= div_cnt + 1'b1 ;
      end
      else
          div_cnt <= 16'd0 ;
 end
//bps_clk_reflash module 
always @ (posedge clk or posedge rst_n) begin
    if (rst_n) begin 
        bps_clk = 0;
    end
    else if (div_cnt == 16'd1 ) begin
        bps_clk = 1 ; //开始计数的时候更新时钟上升沿
    end
    else
        bps_clk =  0 ; //其他状态均为下降沿
end

数据输出模块设计

数据传输计数模块 ,一共传输10个数,其中包括 start  stop 还有 8位的data数据位。每到一个bps_clk时钟的上升沿,计数加一 。tx_done发送完成,在计数值到11的时候,说明发送完成此时拉高tx_done电平。发送状态,当send_en使能的时候表示数据正处在发送状态,当bps_cnt计数值更新到11的时候表明数据停止发送,此时数据发送态uart_state拉低 。数据寄存一拍是等待数据达到稳定的状态。  

//bps counter module
always@(posedge clk or posedge rst_n) begin 
    if(rst_n) begin
        bps_cnt <= 4'd0 ;
    end
    else if ( bps_cnt == 4'd11)   //计数到最后一个数的值
        bps_cnt <= 4'd0 ;
    else if ( bps_clk)
        bps_cnt <= bps_cnt + 1 ; 
    else 
        bps_cnt <= bps_cnt ; 
end

// tx_done module 
always @ (posedge clk or posedge rst_n) begin 
    if (rst_n) begin 
        tx_done  <= 1'b0 ;
    end
    else if ( bps_cnt  == 4'd11 ) begin
        tx_done <= 1'b1 ;    //等于11的时候说明发送完成
    end
    else begin 
        tx_done <= 1'b0 ;
    end
end  
//传输模块,发送状态位模块
always@(posedge clk or posedge rst_n)
	if(rst_n)
		uart_state <= 1'b0;
	else if(send_en)
		uart_state <= 1'b1;
	else if(bps_cnt == 4'd11)
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;
	

//寄存一拍数据等待稳定
always@(posedge clk or posedge rst_n) 
    if (rst_n ) begin 
        data_byte_reg <= 8'b0 ;
    end
    else if (send_en ) begin
        data_byte_reg <= data_byte ;  //寄存一拍
    end
    else begin
        data_byte_reg <= data_byte_reg ; 
    end

 数据传输状态控制模块

从系统总体设计框图可以看出,当数据寄存一拍稳定后,通过一个十选一多路选择器,控制选择数据,根据bps_cnt的值来选择对应的传输数据。个人认为也可以认为是一个串并转换模块。

//uart_tx  module  串并转换
always @ (posedge clk or posedge rst_n) begin
    if (rst_n) begin
       uart_tx  <= 1'b1 ;
    end
    else begin 
        case (bps_cnt) 
      0:uart_tx <= 1'b1;
      1:uart_tx <= START_BIT;
      2:uart_tx <= data_byte_reg[0];
      3:uart_tx <= data_byte_reg[1];
      4:uart_tx <= data_byte_reg[2];
      5:uart_tx <= data_byte_reg[3];
      6:uart_tx <= data_byte_reg[4];
      7:uart_tx <= data_byte_reg[5];
      8:uart_tx <= data_byte_reg[6];
      9:uart_tx <= data_byte_reg[7];
      10:uart_tx <= STOP_BIT;
    default :  uart_tx <= 1'b1; 
        endcase
    end

 综上上述所用的子模块都设计完成

4.电路图网表对应

 可见设计与综合出来的网表一致。

5.testbench仿真测试

`define  CLK_PERIOD   20     //时钟周期20ns
module uart_byte_tx_tb(

    );
//input signal 
reg      clk ;     //时钟
reg      reset_n ;  //复位信号

reg      send_en ;  //发送使能
reg     [7:0]   data_byte ; //等待传输的8bit数据
reg     [2:0]   baud_set  ; 

//output signal
wire  uart_tx  ;  //串口发送信号输出
wire  tx_done  ; //发送完毕
wire  uart_state ; 

//例化模块
 uart_byte_tx  uart_byte_tx_inst1(
   .send_en           ( send_en   )       ,
   .data_byte         ( data_byte )       ,
   .baud_set          ( baud_set  )        ,
   .clk               ( clk       )          ,
   .reset_n           ( reset_n   )         , 
                    
   .uart_tx           ( uart_tx   )          ,
   .tx_done           ( tx_done   )         , 
   .uart_state        ( uart_state)
   );
initial  clk  = 1 ; 
   always   # (`CLK_PERIOD / 2 )  clk = ~clk ;
   
initial begin 
   send_en = 1'b0 ;
   data_byte = 8'b0 ;
   baud_set = 3'd4 ;
   reset_n = 1'b0 ; 
   
   #(`CLK_PERIOD *500 + 1) //延时500个时钟周期后
   reset_n  = 1'b1 ;  //将复位信号拉高
   
   #(`CLK_PERIOD *50 ) ;
   
   //send frist byte 
   data_byte = 8'haa ;
   send_en = 1'b1 ;
   #`CLK_PERIOD 
   send_en = 1'b0 ;
   @(posedge tx_done ) 
   #(`CLK_PERIOD * 5000 ) ; 
   
   //send second byte 
   data_byte = 8'hbb ;
   send_en = 1'b1 ;
   #`CLK_PERIOD ;
   send_en = 1'b0 ;
   
   @(posedge tx_done ) 
   #(`CLK_PERIOD * 5000) ;
   $stop ;
end
endmodule
   
   
        
   
   

仿真结果图

从仿真结果图可以看出testbench,定义一个时钟周期为20ns,可以看出当发送aa ,bb 能接收到数据。仿真结果表明仿真正确。

总结:这里运用了分频和线性序列表的思想实现了字节的发送,设计思想为先查波特率LUT查找表选择出适合的波特率,然后设计出计数器计数到相对应每个bit对应的最大周期数,计数器计数到1时候更新一次波特率时钟,每次波特率时钟的上升沿发送1bit的数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值