如题,我将设置一个单端口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计科小学生