UART通信的一帧一般由11到12位数据组成。1bit的起始位,检测为低电平表示数据开始传输;紧接着8bits的数据;然后是1bit的奇偶校验位,可以是奇校验或者偶校验;最后是1bit或2bits的停止位,必须为高电平,表示一个字符数据的传输结束。
其中校验位是可选的,用来检验数据是否传输正确。如果有校验位,则需要保证收发双方选择同样的一种检验方式。奇校验就是保证数据中的1是奇数,比如如果8bit数据中有3bits的1,校验位置0;如果有4bits的1,校验位置1。偶校验就是保证数据中的1是偶数。
原文链接:https://blog.csdn.net/FPGADesigner/article/details/75201194
波特率:波特率表示数据传输的速率,单位bps,表示位每秒。比如9600bps就表示1s可以传输9600bits的数据。异步收发没有时钟打拍来控制数据的传输,就需要保证收发双方在波特率设置上的一致。确保接收数据的完整性。
默认采用115200的波特率。不使用校验位。设计一个波特率计数器对系统时钟进行分频而实现波特率时钟。
使用三段式状态机进行发送的时序控制,采用BCD码对状态进行编码。
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
//
// Create Date: 2019/12/29 15:55:40
// Design Name: uart_tx
// Module Name: uart_tx
// Project Name: Clock
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_tx
#(
parameter BAUD_RATE = 115200
)
(
input clk,
input rst,
output reg tx,
input [7:0] data_in,
input send_require,
output reg wr,
output reg tx_done
);
localparam baud_cnt_max = 50_000_000/BAUD_RATE-1;
reg[12:0] baud_cnt;
reg[3:0] state;
localparam IDLE =4'b0000;
localparam START =4'b0001;
localparam SEND_BIT0=4'b0011;
localparam SEND_BIT1=4'b0010;
localparam SEND_BIT2=4'b0110;
localparam SEND_BIT3=4'b0100;
localparam SEND_BIT4=4'b0101;
localparam SEND_BIT5=4'b0111;
localparam SEND_BIT6=4'b1111;
localparam SEND_BIT7=4'b1110;
wire sd_rq_pedge;//发送请求上升沿
reg sd_rq_temp0;
reg sd_rq_temp1;
assign sd_rq_pedge = (sd_rq_temp0)&(!sd_rq_temp1);
reg cnt_en;
reg cnt_full;
always@(posedge clk or negedge rst)begin
if(!rst)begin
sd_rq_temp0 <= 1'b0;
sd_rq_temp1 <= 1'b0;
end
else begin
sd_rq_temp0 <= send_require;
sd_rq_temp1 <= sd_rq_temp0;
end
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
baud_cnt <= 13'd0;
cnt_full <= 1'b0;
end
else begin
if(cnt_en)
if(baud_cnt==baud_cnt_max)begin
baud_cnt <= 13'd0;
cnt_full <= 1'b1;
end
else begin
baud_cnt <= baud_cnt + 1'b1;
cnt_full <= 1'b0;
end
else begin
baud_cnt <= 13'd0;
cnt_full <= 1'b0;
end
end
end
always@(posedge clk or negedge rst)begin
if(!rst)
state <= IDLE;
else
case(state)
IDLE:begin
if(sd_rq_pedge)
state <= START;
else
state <= IDLE;
end
START:begin
if(cnt_full)
state <= SEND_BIT0;
else
state <= START;
end
SEND_BIT0:begin
if(cnt_full)
state <= SEND_BIT1;
else
state <= SEND_BIT0;
end
SEND_BIT1:begin
if(cnt_full)
state <= SEND_BIT2;
else
state <= SEND_BIT1;
end
SEND_BIT2:begin
if(cnt_full)
state <= SEND_BIT3;
else
state <= SEND_BIT2;
end
SEND_BIT3:begin
if(cnt_full)
state <= SEND_BIT4;
else
state <= SEND_BIT3;
end
SEND_BIT4:begin
if(cnt_full)
state <= SEND_BIT5;
else
state <= SEND_BIT4;
end
SEND_BIT5:begin
if(cnt_full)
state <= SEND_BIT6;
else
state <= SEND_BIT5;
end
SEND_BIT6:begin
if(cnt_full)
state <= SEND_BIT7;
else
state <= SEND_BIT6;
end
SEND_BIT7:begin
if(cnt_full)
state <= IDLE;
else
state <= SEND_BIT7;
end
default:begin
state <= IDLE;
end
endcase
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
cnt_en <= 1'b0;
tx <= 1'b1;
wr <= 1'b1;//表明可写
tx_done <= 1'b0;
end
else
case(state)
IDLE:begin
cnt_en <= 1'b0;
tx <= 1'b1;
wr <= 1'b1;
tx_done <= 1'b0;
end
START:begin
cnt_en <= 1'b1;
tx <= 1'b0;
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT0:begin
cnt_en <= 1'b1;
tx <= data_in[0];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT1:begin
cnt_en <= 1'b1;
tx <= data_in[1];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT2:begin
cnt_en <= 1'b1;
tx <= data_in[2];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT3:begin
cnt_en <= 1'b1;
tx <= data_in[3];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT4:begin
cnt_en <= 1'b1;
tx <= data_in[4];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT5:begin
cnt_en <= 1'b1;
tx <= data_in[5];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT6:begin
cnt_en <= 1'b1;
tx <= data_in[6];
wr <= 1'b0;
tx_done <= 1'b0;
end
SEND_BIT7:begin
cnt_en <= 1'b1;
tx <= data_in[7];
wr <= 1'b0;
tx_done <= 1'b1;
end
default:begin
cnt_en <= 1'b0;
tx <= 1'b1;
wr <= 1'b0;
tx_done <= 1'b0;
end
endcase
end
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
//
// Create Date: 2019/12/29 15:55:40
// Design Name: uart_rx
// Module Name: uart_rx
// Project Name: Clock
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_rx
#(
parameter BAUD_RATE = 115200
)
(
input clk,
input rst,
input rx,
output reg rd,
output reg[7:0] data_out,
output rx_done
);
reg rx_done;
localparam baud_cnt_max = 50_000_000/BAUD_RATE-1;
localparam baud_cnt_half = (50_000_000/BAUD_RATE)/2-1;
wire rx_pin_nedge;//rx_pin下降沿
reg rx_pin_temp0;
reg rx_pin_temp1;
reg[3:0] state;
reg[12:0] baud_cnt;
reg cnt_en;
reg cnt_half;
reg cnt_full;
reg rx_over;
reg[7:0] data_out_reg;
localparam IDLE =4'b0000;
localparam GET_START_BIT=4'b0001;
localparam GET_BIT0 =4'b0011;
localparam GET_BIT1 =4'b0010;
localparam GET_BIT2 =4'b0110;
localparam GET_BIT3 =4'b0100;
localparam GET_BIT4 =4'b0101;
localparam GET_BIT5 =4'b0111;
localparam GET_BIT6 =4'b1111;
localparam GET_BIT7 =4'b1110;
assign rx_pin_nedge = (!rx_pin_temp0)&(rx_pin_temp1);//下降沿
always@(posedge clk or negedge rst)begin
if(!rst)begin
rx_pin_temp0 <= 1'b1;
rx_pin_temp1 <= 1'b1;
end
else begin
rx_pin_temp0 <= rx;
rx_pin_temp1 <= rx_pin_temp0;
end
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
baud_cnt <= 13'd0;
cnt_full <= 1'b0;
cnt_half <= 1'b0;
end
else begin
if(cnt_en)
if(baud_cnt==baud_cnt_max)begin
baud_cnt <= 13'd0;
cnt_full <= 1'b1;
cnt_half <= 1'b0;
end
else if(baud_cnt==baud_cnt_half)begin
baud_cnt <= baud_cnt + 1'b1;
cnt_full <= 1'b0;
cnt_half <= 1'b1;
end
else begin
baud_cnt <= baud_cnt + 1'b1;
cnt_full <= 1'b0;
cnt_half <= 1'b0;
end
else begin
baud_cnt <= 13'd0;
cnt_full <= 1'b0;
cnt_half <= 1'b0;
end
end
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
state <= IDLE;
end
else begin
case(state)
IDLE:begin
if(rx_pin_nedge)
state <= GET_START_BIT;
else
state <= IDLE;
end
GET_START_BIT:begin
if(cnt_full)
state <= GET_BIT0;
else
state <= GET_START_BIT;
end
GET_BIT0:begin
if(cnt_full)
state <= GET_BIT1;
else
state <= GET_BIT0;
end
GET_BIT1:begin
if(cnt_full)
state <= GET_BIT2;
else
state <= GET_BIT1;
end
GET_BIT2:begin
if(cnt_full)
state <= GET_BIT3;
else
state <= GET_BIT2;
end
GET_BIT3:begin
if(cnt_full)
state <= GET_BIT4;
else
state <= GET_BIT3;
end
GET_BIT4:begin
if(cnt_full)
state <= GET_BIT5;
else
state <= GET_BIT4;
end
GET_BIT5:begin
if(cnt_full)
state <= GET_BIT6;
else
state <= GET_BIT5;
end
GET_BIT6:begin
if(cnt_full)
state <= GET_BIT7;
else
state <= GET_BIT6;
end
GET_BIT7:begin
if(cnt_full)
state <= IDLE;
else
state <= GET_BIT7;
end
default:state <= IDLE;
endcase
end
end
always@(posedge clk or negedge rst)begin
if(!rst)begin
data_out_reg <= 8'b0000_0000;
cnt_en <= 1'b0;
rx_over <= 1'b0;
rd <= 1'b1;
rx_done <= 1'b0;
end
else begin
case(state)
IDLE:begin
data_out_reg <= 8'b0000_0000;
cnt_en <= 1'b0;
rx_over <= 1'b0;
rd <= 1'b1;
rx_done <= 1'b0;
end
GET_START_BIT:begin
data_out_reg <= 8'b0000_0000;
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
end
GET_BIT0:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[0] <= rx_pin_temp0;
else
data_out_reg[0] <= data_out_reg[0];
end
GET_BIT1:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[1] <= rx_pin_temp0;
else
data_out_reg[1] <= data_out_reg[1];
end
GET_BIT2:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[2] <= rx_pin_temp0;
else
data_out_reg[2] <= data_out_reg[2];
end
GET_BIT3:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[3] <= rx_pin_temp0;
else
data_out_reg[3] <= data_out_reg[3];
end
GET_BIT4:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[4] <= rx_pin_temp0;
else
data_out_reg[4] <= data_out_reg[4];
end
GET_BIT5:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[5] <= rx_pin_temp0;
else
data_out_reg[5] <= data_out_reg[5];
end
GET_BIT6:begin
cnt_en <= 1'b1;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
if(cnt_half)
data_out_reg[6] <= rx_pin_temp0;
else
data_out_reg[6] <= data_out_reg[6];
end
GET_BIT7:begin
cnt_en <= 1'b1;
rx_over <= 1'b1;
rd <= 1'b0;
rx_done <= 1'b1;
if(cnt_half)
data_out_reg[7] <= rx_pin_temp0;
else
data_out_reg[7] <= data_out_reg[7];
end
default:begin
data_out_reg <= data_out_reg;
cnt_en <= 1'b0;
rx_over <= 1'b0;
rd <= 1'b0;
rx_done <= 1'b0;
end
endcase
end
end
always@(posedge clk or negedge rst)begin
if(!rst)
data_out <= 8'b0000_0000;
else
if(rx_over)
data_out <= data_out_reg;
else
data_out <= data_out;//保持
end
endmodule