用串口来发送信号发生器的数据

一、在串口模块的基础上加一点修改

1. 这一段讲做什么

我的博客是连续剧,觉得有参考/纠错/鼓励的价值的话,我是非常期待能与大家多多交流的呀

梅哥的视频P14集,后半部分讲,能不能通过在大模块中操作一个控制信号send_go,进而影响子模块(就是串口模块,以下称串口模块)种的send_en信号,进而来操控串口发送数据的节奏呢?↓↓↓

在这里插入图片描述

想要在大模块中操纵send_go信号,那就需要在大模块中给send_go信号赋值。而send_go信号的变化凭借的是:信号发生器希望在哪一个时刻发送数据,这完全取决于信号发生器的设置。当然,由于我还没学到写信号发生器的模块,所以假设不随信号发生器的喜好,随我的喜好。我选择每隔10ms通过串口发送8bit数据。那么回到“send_go应该何时发送的问题”,通过分析,认为send_go每隔10ms来一个脉冲挺合适。发送流程是这样的:每隔10mssend_en拉高一个时钟周期,然后把send_go当做串口模块的输入端口,send_go一拉高,send_en就拉高,起始位、数据位、停止位,就是在send_en拉搞的时段没发送数据的。直到停止位的到来,send_en拉低。下一个send_go的到来将再次激发串口传输数据。

2. 这一段讲为什么要在这次的代码中加入r_data

大模块把data传输给串口模块,串口模块会分时刻把data传给uart_tx。这个传输的过程是one by one,说不准就会有一位受到干扰由0变1,因此,把要传的数据寄存到寄存器里面,保证传输尽量少出错。r_data就是那个寄存器。我是这样理解的。

二. 代码

1. 较之前代码的区别

  • 大模块里加入下面这几句话
/*--------------send_en--------------*/
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin
        send_go<=0;
    end
    else if (cnt_10ms == 1) begin
        send_go<=1'b1;
    end
    else
        send_go<=0;   
end
  • 在串口模块里面要加入send_go如何驱动send_en:
/*-----------------------send_en-------------------------------*/
always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n)
        send_en<=32'd0;
    else if(send_go)
        send_en<=1;
    else if (tx_done)
        send_en<=0;
    else
        send_en<=send_en;
end
  • 以及r_data
/*-----------------------r_data-------------------------------*/
always @(posedge sys_clk) begin
    if(!rst_n)
        r_data<=1'b1;
    else if (send_go)
        r_data<=data;
    else
        r_data<=r_data;
end
/*-----------

2. 完整的代码

2.1 设计代码

  • 大模块代码
module byte_send(
input sys_clk,
input rst_n,
output uart_tx
);

reg  [7:0] data        ;
reg  send_go           ;
wire tx_done          ;

send_byte s1(   
.sys_clk      (sys_clk )   ,
.rst_n        (rst_n   )   ,
.time_set     (2)   ,
.data         (data    )   ,//之前是在tb文件里面给data,send_en,现在是在顶层模块给                            
.send_go      (send_go )   ,//顶层模块就是负责给子模块赋值的
.uart_tx      (uart_tx )   ,
.tx_done      (tx_done) 
);
/*--------------变量的声明-------------------*/
reg [31:0] cnt_10ms;
parameter time_10ms = 500_000;
/*-------------- 1 0 ms ---------------*/
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_10ms<=0;
    end
    else if (cnt_10ms==time_10ms-1) begin
        cnt_10ms<=0;
    end
    else
        cnt_10ms<=cnt_10ms+1;
end
/*--------------send_en--------------*/
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin
        send_go<=0;
    end
    else if (cnt_10ms == 1) begin
        send_go<=1'b1;
    end
    else
        send_go<=0;   
end
/*--------------data--------------*/
always @(posedge sys_clk or negedge rst_n) begin
    if (!rst_n) begin
        data<=0;
    end
    else if (tx_done) begin
        data<=data+1;
    end
    else
        data<=data;
end
endmodule
  • 串口模块代码
module send_byte (                           
input sys_clk         ,          
input rst_n           ,          
input [2:0] time_set  ,   //基础计数器的设置       
input [7:0] data      ,          
input send_go         ,          
output reg uart_tx    ,          
output reg tx_done  
    );
/*-----------------------变量的声明-----------------------------*/
reg [31:0] cnt;//基本计数器
reg [3:0] cnt2;//2级定时器 
reg [31:0] time_cnt;
reg send_en;
reg [7:0] r_data;
/*-----------------------设置时间间隔-----------------------------*/ 
always@(*)
    if(!rst_n)
        time_cnt<=434;
    else
        case(time_set)  
            0:time_cnt<=10416;                 //4800; 
            1:time_cnt<=5208;                  //9600; 
            2:time_cnt<=434;                   //115200;
            default:time_cnt<=434;             //115200;
        endcase
/*-----------------------r_data-------------------------------*/
always @(posedge sys_clk) begin
    if(!rst_n)
        r_data<=1'b1;
    else if (send_go)
        r_data<=data;
    else
        r_data<=r_data;
end
/*-----------------------send_en-------------------------------*/
always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n)
        send_en<=32'd0;
    else if(send_go)
        send_en<=1;
    else if (tx_done)
        send_en<=0;
    else
        send_en<=send_en;
end
/*-----------------------基本计数器-----------------------------*/
always@(posedge sys_clk or negedge rst_n)
    if(!rst_n)
        cnt<=32'd0;
    else if(send_en)
        if(cnt==time_cnt-1)
            cnt<=32'd0;
        else
            cnt<=cnt+1;
    else//!send_en
        cnt<=32'd0;     
/*-----------------------2级计数器-----------------------------*/
always@(posedge sys_clk or negedge rst_n)
    if(!rst_n)
        cnt2<=4'd0;//默认发start
    else if(send_en)begin
        if((cnt2>=0)&&(cnt2<10))begin
            if(cnt==time_cnt-1)
                cnt2<=cnt2+1;
            else  
                cnt2<=cnt2;
        end
        else if(cnt2==10)
            cnt2<=0;//cnt2的清0
        else  
                cnt2<=cnt2;
    end
    else //!send_en
        cnt2<=4'd0;
/*-----------------------uart_tx-----------------------------*/
always@(posedge sys_clk or negedge rst_n)
    if(!rst_n)
        uart_tx<=0;
    else if(send_en)
        case(cnt2)
            0: begin uart_tx<=0;  end                        
            1:  uart_tx<=r_data[0] ;                  
            2:  uart_tx<=r_data[1] ;                  
            3:  uart_tx<=r_data[2] ;                  
            4:  uart_tx<=r_data[3] ;                  
            5:  uart_tx<=r_data[4] ;                  
            6:  uart_tx<=r_data[5] ;                  
            7:  uart_tx<=r_data[6] ;                  
            8:  uart_tx<=r_data[7] ;                  
            9:  uart_tx<=1 ;       
            default:uart_tx<=1;    
        endcase
    else//!send_en
        uart_tx<=uart_tx;                                          
/*-----------------------tx_done-----------------------------*/
always@(posedge sys_clk or negedge rst_n)
    if(!rst_n)
        tx_done<=0;
    else if(cnt2==9 && cnt == time_cnt-1)                                    
            tx_done<=1;     
    else if(send_en)
            tx_done<=0;                
    else
            tx_done<=0;
endmodule          
                               

2.2 tb文件代码

`timescale 1ns/1ps
module tb ;
reg  sys_clk;
reg  rst_n;  
wire uart_tx ;

byte_send b1(
. sys_clk(sys_clk),
. rst_n  (rst_n  ),  
. uart_tx(uart_tx) 
);
/*-----------------sys_clk-----------------*/
initial 
    sys_clk=0;
    always #10 sys_clk=~sys_clk;
/*-------------------rst_n-----------------*/
initial begin
    rst_n=0;
    #201
    rst_n=1;
    #500_000_0;
    $stop;
end 


endmodule

三、仿真效果

  • 一次串口发送,显示uart_tx为
    在这里插入图片描述

  • 所以除去最左边的start位、最右边的stop位,发送的数据为:0000_1100
    在这里插入图片描述

  • 一个send_go脉冲时间为一个时钟周期:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值