一、波特率发生器
`timescale 1ns / 1ps
module baud_gen(
clk_50MHz,
rst,
bclk
);
input clk_50MHz;
input rst;
output bclk;
reg bclk;
reg [8:0] cnt;
always@(posedge clk_50MHz)begin
if(!rst)begin
cnt <= 0;
bclk <= 0;
end
else begin
if(cnt>324)begin
cnt <= 0;
bclk <=1 ;
end
else begin
cnt <= cnt + 1'b1;
bclk <= 0;
end
end
end
endmodule
二、发送模块
`timescale 1ns / 1ps
module uart_tx(
bclk,
rst,
tx_din,
tx_cmd,
tx_ready,
txd
);
input bclk; //发送模块时钟
input rst;
input tx_cmd; //发送控制信号,高有效
input [7:0] tx_din; //期望发送的字节
output tx_ready; //发送完成指示
output txd; //串口发送数据
reg tx_ready;
//定义串口参数
parameter [3:0] Lframe = 8;
parameter [2:0] s_idle = 3'b000;
parameter [2:0] s_start = 3'b001;
parameter [2:0] s_wait = 3'b010;
parameter [2:0] s_shift = 3'b011;
parameter [2:0] s_stop = 3'b100;
//定义所需中间变量
//发送模块状态机的状态寄存器
reg [2:0] state = s_idle;
reg [3:0] cnt = 0;
reg [3:0] dcnt = 0;
reg txdt ; //没加复位时 为txdt=1
assign txd = txdt;
always@(posedge bclk or posedge rst)begin
if(!rst)
begin
state <= s_idle;
cnt <= 0;
tx_ready <= 0;
txdt <= 1;
end
else begin
case(state)
//空闲状态,检测发送指令
s_idle:begin
tx_ready <= 1;
cnt <= 0;
txdt <= 1'b1;
if(tx_cmd == 1)
state <= s_start;
else
state <= s_idle;
end
//发送模块的开始状态
s_start:begin
tx_ready <= 0;
txdt <= 1'b0;
state <= s_wait;
end
//延迟等待状态,使每个有效数据位保持16个bclk周期,从而得到9600的波特率
s_wait: begin
tx_ready <= 0;
if(cnt >= 4'b1110)begin
cnt <= 0;
if(dcnt == Lframe)begin
state <= s_stop;
dcnt <= 0;
txdt <= 1'b1;
end
else begin
state <= s_shift;
txdt <= txdt;
end
end
else begin
state <= s_wait;
cnt <= cnt + 1'b1;
end
end
//移位状态,每进入一次就将下一个发送比特移动到发送数据端口上
s_shift :begin
tx_ready <=0;
txdt <= tx_din[dcnt];
dcnt <= dcnt +1'b1 ;
state <= s_wait;
end
//停止状态,发送停止位
s_stop :begin
txdt <= 1'b1;
if(cnt > 4'b1110)begin
state <= s_idle;
cnt <= 0;
tx_ready <= 1;
end
else begin
state <= s_stop;
cnt <= cnt + 1'b1;
end
end
endcase
end
end
endmodule
三、接收模块
`timescale 1ns / 1ps
module uart_rx(
bclk,
rst,
rxd,
rx_ready,
rx_dout
);
input bclk;
input rst;
input rxd; //串口接收数据
output rx_ready; //接收完成指示信号
output [7:0] rx_dout; //接收到的并行数据,以字节形式输出
parameter [3:0] Lframe = 8;
parameter [2:0] s_idle = 3'b000; //空闲状态,此状态下rx_ready为1,用于接收起始信号,一旦接收到起始信号立即进入s_sample.
parameter [2:0] s_sample = 3'b010; //采样状态,此状态下rx_ready为0,对16个采样值进行最大自然判决,得到相应逻辑,重复8次,接收8个数据后进入s_stop状态
parameter [2:0] s_stop = 3'b100; //检测停止位,为了使接收模块使用范围更广,等待一定时间后转跳回s_idle
reg rx_ready;
reg [2:0] state = s_idle;
reg [3:0] cnt = 0; //16个周期
reg [3:0] num = 0; //最大自然判决
reg [3:0] dcnt = 0; //用来判断是达到8个数据
reg [7:0] rx_doutmp = 0;
assign rx_dout = rx_doutmp;
//接收程序
always@(posedge bclk or posedge rst)
if(!rst)begin
state <= s_idle;
cnt <= 0;
dcnt <= 0;
num <= 0;
rx_doutmp <= 0;
rx_ready <= 0;
end
else begin
case(state)
//检测起始条件
s_idle:begin
rx_doutmp<=0;
dcnt<=0;
rx_ready<=1;
if(cnt == 4'b1111)begin
cnt <= 0;
if(num > 7)begin
state <= s_sample;
num <=0;
end
else begin
state <= s_idle;
num <= 0;
end
end
else begin
cnt <= cnt + 1'b1;
if(rxd == 1'b0)begin
num <= num + 1'b1 ;
end
else begin
num <= num;
end
end
end
//接收模块数据采样、判断以及串口并转换模块
s_sample:begin
rx_ready <= 1'b0;
if(dcnt == Lframe)begin
state <= s_stop;
end
else begin
state <= s_sample;
if(cnt == 4'b1111)begin
dcnt <= dcnt + 1'b1;
cnt <= 0;
if(num >7)begin
num <=0;
rx_doutmp[dcnt] <= 1;
end
else begin
rx_doutmp[dcnt] <= 0;
num <= 0;
end
end
else begin
cnt <= cnt + 1'b1;
if(rxd == 1'b1)begin
num <= num + 1'b1;
end
else begin
num <= num;
end
end
end
end
//接收模块的停止状态
s_stop:begin
rx_ready <= 1'b1;
if(cnt == 4'b1111)begin
cnt <= 0;
state <= s_idle;
end
else begin
cnt <= cnt + 1'b1;
end
end
endcase
end
endmodule
四、顶层模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 21:42:06 07/08/2019
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool versions:
// Description: 发送8位数据时稳定有效 eg:FE 发送FEFE不稳定
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module top(
clk,rst,rxd,txd
);
input clk;
input rst;
input rxd;
output txd;
wire bclk;
wire rx_ready;
wire tx_ready;
wire [7:0] rx_dout;
reg [7:0] tx_din;
reg tx_cmd;
reg [2:0] bv1;
//reg [2:0] bv2;
wire bv1_posedge;
//wire bv2_posedge;
always@(posedge bclk)begin
bv1 <= {bv1[1:0],rx_ready};
// bv2 <= {bv2[1:0],tx_ready};
end
assign bv1_posedge = (~bv1[2]) & bv1[1];
//assign bv2_posedge = (~bv2[2]) & bv2[1];
always@(posedge bclk)begin
if(bv1_posedge == 1'b1)begin
tx_cmd <= 1;
tx_din <= rx_dout;
end
else tx_cmd <= 0;
// else if(bv2_posedge == 1'b1)
// tx_cmd <= 0;
end
baud_gen inst_baud_gen(
.clk_50MHz(clk),
.rst(rst),
.bclk(bclk)
);
uart_rx inst_uart_rx(
.bclk(bclk),
.rst(rst),
.rxd(rxd),
.rx_ready(rx_ready),
.rx_dout(rx_dout)
);
uart_tx inst_uart_tx(
.bclk(bclk),
.rst(rst),
.tx_din(tx_din),
.tx_cmd(tx_cmd),
.tx_ready(tx_ready),
.txd(txd)
);
endmodule