UART_RX_TX && 单端口RAM verilog实现发送与接收

如题,我将设置一个单端口RAM1用来存放数据,UART发送端将RAM1中的数据发送出去,UART接受端接受发送端传来的单比特数据,并实现串转并,最后将数据再存在RAM2中。

在这里插入图片描述

首先先介绍一下UART,其中TX为为发送端,RX为接收端

在这里插入图片描述

再介绍一下波特率与周期的关系,认真看图里写的就行
这里我波特率是115200,周期是20ns,请认真理解一下这里的434的由来。

在这里插入图片描述

这里再说一下UART一帧的概念:是由起始位,数据位,校验位,终止位。这里我将校验位省去,并规定数据位为8位。

这里用cnt1用来计数,add_cnt1是开始计数,end_cnt1终止计数

在这里插入图片描述

那么用什么来标志开始发送数据呢?

这里先科普一下,在线路上,空闲状态时全是高电平“1”
当要开始发送数据时,就下拉一下(变为低电平“0”)
这里我用rx_in_ff表示当前的前一个BPS内的电平信号,rx_in表示当前电平信号

在这里插入图片描述
所以我们就得到一个判断语句
这里的flag就是开始计数的标志

if(flag == 0 && rx_in_ff ==1 && rx_in == 0) begin
        flag <=1;
    end

在接受数据时,因为在BPS个周期内只接受1bit数据,所以,这里我取BPS/2-1(中间)来获取这个bit
用来消除信号的不稳定

cnt0用来计数BPS,add_cot0是开始计数,end_cont0是结束计数。rx_in是input接受端,接受1bit数据
rx_data是接受端的一个八位寄存器,用于串并转换
在这里插入图片描述

所以接收端大致是这样的

在这里插入图片描述

这里再讲讲发送端

这里设置四个状态,和两个状态寄存器。。如图所示
start是发送端的一个使能信号,send_cnt是用于为发送数据计数

在这里插入图片描述

与接受端相比,发送端使用状态机的方法,大大减轻了代码的理解难度

在这里插入图片描述

大致如此
在这里插入图片描述

最后贴出代码:

RAM1

`timescale 1ns / 1ps



module ram(
    input clk,
    input rst_n,
    input enb,
    input [3:0]addr,
    input [7:0]w_data,

    output wire [7:0]r_data
);
//*************code***********//
    reg [7:0] data_tmp[9:0];
    integer i;
    integer j;
    
    always @ (posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            for(i=0 ; i < 10; i=i+1)begin
                for(j=0 ; j < 8; j=j+1)begin
                    data_tmp[i][j] <= 0;
                end
            end
        end
        else if(enb)
            data_tmp[addr] <= w_data;
    end
    
   assign r_data = (!enb) ? data_tmp[addr] :r_data;
endmodule

UART_TX

`timescale 1ns / 1ps

module uart_trans
#(parameter BPS=434)
(
input clk,
input rst_n,
input start,
input  wire[7:0] send_data,
input [7:0]w_data1,

output reg tx_out,
input  enb,
input  [3:0]addr
    );

//

parameter IDLE = 0;
parameter START = 1;     
parameter SEND = 2;       
parameter STOP =3;    
    
reg [2:0] cur_state;
reg [2:0] next_state;
reg [9:0] count;         
reg [3:0] send_cnt;   
wire [7:0]r_data1;

assign send_data = r_data1;

//always@(*)
// send_data[0] <= r_data1[0];






always@(posedge clk,negedge rst_n)
if(~rst_n)begin
    cur_state <= IDLE;
    end
else
    cur_state <= next_state;



always@(*)
    case(cur_state)
        IDLE:if(start)
                 next_state = START;
             else
                 next_state = IDLE;
        START:if(count == BPS-1)
                 next_state=SEND;
              else
                 next_state = START;
        SEND:if(send_cnt == 7 && count == BPS-1)
                 next_state=STOP;
             else
                 next_state=SEND;
        STOP:if(count == BPS-1)
                 next_state = IDLE;
             else
                 next_state = STOP;
        default:next_state = IDLE;
    endcase

//count
always@(posedge clk,negedge rst_n)
    if(~rst_n)
        count <= 0;
    else if(cur_state != IDLE)begin
            if(count == BPS-1)
                count <= 0;
            else
                count <= count+1;
        end
    else
        count <= 0;
        
//send_cnt
always@(posedge clk,negedge rst_n)
    if(~rst_n)
        send_cnt <= 0;
    else if(cur_state == SEND && count == BPS-1)
        send_cnt <= send_cnt+1;
    else if(cur_state != SEND)
        send_cnt <= 0;
        
    
//tx_out
always@(*)
    case(cur_state)
        IDLE:tx_out = 1;
        START:tx_out = 0;
        SEND:begin
             case(send_cnt)
                0:tx_out = send_data[0]; 
                1:tx_out = send_data[1];
                2:tx_out = send_data[2];
                3:tx_out = send_data[3];
                4:tx_out = send_data[4];
                5:tx_out = send_data[5];
                6:tx_out = send_data[6];
                7:tx_out = send_data[7];
                default:tx_out = 1;
            endcase
        end
        STOP:tx_out = 1;
        default:tx_out = 1;
    endcase

ram RAM(
    .clk(clk),
    .rst_n(rst_n),
    .enb(enb),
    .addr(addr),
    .w_data(w_data1),
    .r_data(r_data1)
);

endmodule

UART_RX

`timescale 1ns / 1ps

module UART_RX(
    input clk,
    input rst_n,
    input rx_in,
    output reg [7:0] rx_data,
    output reg [3:0]addr,
    output wire end_cnt1
    );
   
 //BPS计数  
// 计数时间 = 1000000000ns/9600 = 104166.7ns
//	50MHz的时钟周期为20ns
//	所以计数传输一个比特的次数为104166.7 / 20 = 5208
parameter BPS=434;
reg [9:0] cnt0;
wire add_cnt0;
wire end_cnt0;

reg rx_in_ff; //后一拍
reg flag;     //计数标志
wire post_data;


always @(posedge clk or	negedge	rst_n)	begin
    if(rst_n == 0)begin 
        cnt0 <= 0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
        cnt0 <= 0;
        else
        cnt0 <= cnt0+1;
    end
end

assign add_cnt0 = flag == 1;
assign end_cnt0 = add_cnt0 && cnt0==BPS-1;



 always @(posedge clk or	negedge	rst_n)	begin
    if(rst_n ==0)begin 
        rx_in_ff <=1;
    end
    else begin
        rx_in_ff <=rx_in;
    end
 end
 


reg [3:0] cnt1;
wire add_cnt1;
//wire end_cnt1;
always @(posedge clk or	negedge	rst_n)	begin
    if(rst_n ==0)begin 
        cnt1 <=0;
    end
    else if(add_cnt1)begin
        if(end_cnt1)begin
            cnt1 <= 0;
        end
        else
        cnt1 <= cnt1+1;
    end
end
assign add_cnt1 =end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==9-1;

 always @(posedge clk or	negedge	rst_n)	begin
    if(rst_n ==0)begin 
        flag <=0;
    end
    else if(flag == 0 && rx_in_ff ==1 && rx_in == 0) begin
        flag <=1;
    end
    else if(end_cnt1)begin
        flag <= 0;
    end
 end
 
 
 always @(posedge clk or	negedge	rst_n)	begin
    if(rst_n ==0)begin 
        rx_data <=0;
        addr <= 0;
    end
    else if(add_cnt0 && cnt0 == BPS/2-1 && cnt1 >= 1 && cnt1 < 9)begin
        rx_data[cnt1-1] <= rx_in;
    end
    else if( end_cnt1)begin
        addr <= addr+1;
    end
 end
       
 RAM_1port ram_1(
    .clk(clk),
    .rst(rst_n),
    .enb(end_cnt1),
    .addr(addr),
    .w_data(rx_data)
);  
   
endmodule


RAM2

`timescale 1ns / 1ps
module RAM_1port(
    input clk,
    input rst,
    input enb,
    input [3:0]addr,
    input [7:0]w_data
);
//*************code***********//
    reg [7:0] myRAM [9:0];
    reg [7:0] r_data_r;
    
  	// 写锟斤拷RAM
    genvar i;
    generate
        for(i=0;i<10;i=i+1)
            always@(posedge clk or negedge rst) begin
                if(~rst)
                    myRAM[i] <= 0;
                else
                    myRAM[addr] <= enb? w_data: myRAM[addr];
            end
                    
    endgenerate
            
  	// 锟斤拷取RAM
    always@(*) begin
        if(~rst)
            r_data_r <= 0;
        else
            r_data_r <= ~enb? myRAM[addr]: r_data_r;
    end

    assign r_data = r_data_r;
//*************code***********//
endmodule

TB

module UART_tb();
reg clk;
reg rst_n;
reg start1;
reg enb;
reg [3:0]addr;
reg [7:0]w_data2;
wire tx_out;

integer      i ;

reg [7:0] test_num [9:0];

initial begin
 test_num[0] =8'b1000_1000;
 test_num[1] =8'b1100_1100;
 test_num[2] =8'b1101_1101;
 test_num[3] =8'b1110_1110;
 test_num[4] =8'b1011_1011;
 test_num[5] =8'b1101_0100; 
 test_num[6] =8'b1111_0000;
 test_num[7] =8'b1000_0000;
 test_num[8] =8'b1000_0001;
 test_num[9] =8'b1000_0010;


end

initial begin
addr = 0;
enb = 1;
start1 = 0; 
 #8680;
 
for (i=0; i<10; i=i+1) begin
      w_data2 = test_num[i] ;
      #8680;
      if(addr!=9)
            addr = addr+1;
       else
           enb = 0;
end
addr = 0;
#8680;
for (i=0; i<10; i=i+1) begin
   start1 = 1;  
   #86800;
   start1 = 0;  
   #8680;
   if(addr!=9)
        addr = addr+1;
  end
$finish;

end

initial begin
    clk = 1;
    rst_n = 0; #10 rst_n = 1;
end
always #10 clk = ~clk;

parameter BPS=434;

uart_trans #(.BPS(BPS))
uart(
.clk(clk),
.rst_n(rst_n),
.start(start1),
.w_data1(w_data2),
.enb(enb),
.addr(addr),
.tx_out(tx_out)
);

UART_RX UART_RX_1(
.clk(clk),
.rst_n(rst_n),
.rx_in(tx_out)
);

endmodule

波形图

## 往RAM1中写数据

在这里插入图片描述

## 发送前两个数据

在这里插入图片描述

## 接收最后两个数据
在这里插入图片描述

by计科小学生

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值