基本上写的文章就是对于一个知识点的巩固
如果有什么出错的,还望大家指出,谢谢!
物理层
UART 是通用异步串行收发器 , 他是异步全双工的通信协议
它的物理层有两条线组成,一条是rx,一条是tx ,用来接收和发送数据的两条线。
协议层 :
他的协议层由四部分组成:
1 、 起始位 (1bit )
2、 数据位 (6/7/8bit)
3、 奇偶校验位 (1 bit )
4、 停止位 (1/1.5/2 bit)
他的传输是遵循LSB 的,即地位先发
1、 起始位 :
起始位是低电平有效
2、数据位:
低位先发,后发高位
3、 奇偶校验位:
奇偶校验位通过缩位异或的方式得到(xor)
4、 停止位:
停止位是高电平有效
Tips : 串口通信的速率用波特率来表示,他表示每秒传输二进制数据的位数,单位是bit/s (位/ 秒) 简称bps
如何计算传输1bit所需要的时间?
即 : 用50M 去除以对应的波特率 就可以得到相对应传输1bit 所需要的次数 。
以上就是uart传输一个字节的协议层原理
以下是我的代码部分
我一共分为四个模块来写:
1、uart的rx模块
2、uart的tx模块
3、uart的ctrl模块(将tx传输的数据用一个fifo存起来,再发往rx)
4、top模块,将以上三个模块整合成一个top
uart的rx模块
module uart_rx #(
parameter CLK_FREQ = 50000000 ,
parameter BPS = 115200 ,
parameter CHECK = "None" //"None" 无校验 "Odd" 奇校验 "Even" 偶校验
)(
input clk ,
input rst_n ,
output reg [7:0] rx_data ,
output rx_data_vld ,
input rx_din
);
reg rx_din_r1,rx_din_r2;
wire rx_din_nege;
localparam IDLE = 0 ,
START = 1 ,
DATA = 2 ,
CAIL = 3 , //校验位
STOP = 4 ;
reg [2:0] state ;
wire idle2start ;
wire start2data ;
wire data2stop ;
wire data2cail ;
wire cail2stop ;
wire stop2idle ;
reg [8:0] cnt_bps;
wire add_bps_cnt,end_bps_cnt;
localparam MAX_BPS = CLK_FREQ/BPS;
reg [2:0] cnt_bit;
wire add_bit_cnt,end_bit_cnt;
(* keep *) wire rx_data_check;
reg rx_check;
reg error;
/**************************************************************
下降沿检测
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
rx_din_r1 <= 1;
rx_din_r2 <= 1;
end
else begin
rx_din_r1 <= rx_din;
rx_din_r2 <= rx_din_r1;
end
assign rx_din_nege = !rx_din_r1 && rx_din_r2;
/**************************************************************
状态机
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
state <= IDLE;
else case(state)
IDLE : if(idle2start)
state <= START;
START : if(start2data)
state <= DATA;
DATA : if(data2stop)
state <= STOP;
else if(data2cail)
state <= CAIL;
CAIL : if(cail2stop)
state <= STOP;
STOP : if(stop2idle)
state <= IDLE;
default : state <= IDLE;
endcase
assign idle2start = state == IDLE && rx_din_nege;
assign start2data = state == START && end_bps_cnt;
assign data2stop = state == DATA && end_bit_cnt && CHECK == "None";
assign data2cail = state == DATA && end_bit_cnt;
assign cail2stop = state == CAIL && end_bps_cnt;
assign stop2idle = state == STOP && (cnt_bps == MAX_BPS >> 1) ;
/**************************************************************
波特率控制
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_bps <= 'd0;
else if(add_bps_cnt) begin
if(end_bps_cnt)
cnt_bps <= 'd0;
else
cnt_bps <= cnt_bps + 1'b1;
end
else
cnt_bps <= 'd0;
assign add_bps_cnt = state != IDLE;
assign end_bps_cnt = add_bps_cnt && cnt_bps == MAX_BPS - 1;
/**************************************************************
数据位控制
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_bit <= 'd0;
else if(add_bit_cnt) begin
if(end_bit_cnt)
cnt_bit <= 'd0;
else
cnt_bit <= cnt_bit + 1'b1;
end
assign add_bit_cnt = end_bps_cnt && state == DATA;
assign end_bit_cnt = add_bit_cnt && cnt_bit == 8 - 1;
/**************************************************************
数据接收逻辑
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
rx_data <= 0;
else if(state == DATA && (cnt_bps == MAX_BPS >> 1)) //波特率的中间时刻采样数据
rx_data <= {rx_din_r2,rx_data[7:1]};
assign rx_data_vld = stop2idle && !error;//(CHECK == "None")? data2stop : (stop2idle && !error);
/**************************************************************
校验
**************************************************************/
//计算接收到的数据
assign rx_data_check = (CHECK == "Odd")? ~^rx_data : ^rx_data;
//接收到的校验位
always@(posedge clk or negedge rst_n)
if(!rst_n)
rx_check <= 0;
else if(state == CAIL && (cnt_bps == MAX_BPS >> 1))
rx_check <= rx_din_r2;
always@(posedge clk or negedge rst_n)
if(!rst_n)
error <= 0;
else if(cail2stop)
error <= rx_check != rx_data_check;
endmodule
uart的tx模块
module uart_tx #(
parameter CLK_FREQ = 50000000 ,
parameter BPS = 115200 ,
parameter CHECK = "None" //"None" 无校验 "Odd" 奇校验 "Even" 偶校验
)(
input clk ,
input rst_n ,
input [7:0] tx_din ,
input tx_din_vld ,
output tx_ready ,
output reg tx_dout
);
localparam IDLE = 0 ,
START = 1 ,
DATA = 2 ,
CAIL = 3 , //校验位
STOP = 4 ;
reg [2:0] state ;
wire idle2start ;
wire start2data ;
wire data2stop ;
wire data2cail ;
wire cail2stop ;
wire stop2idle ;
reg [8:0] cnt_bps;
wire add_bps_cnt,end_bps_cnt;
localparam MAX_BPS = CLK_FREQ/BPS;
reg [2:0] cnt_bit;
wire add_bit_cnt,end_bit_cnt;
reg [7:0] tx_din_r;
/**************************************************************
状态机
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
state <= IDLE;
else case(state)
IDLE : if(idle2start)
state <= START;
START : if(start2data)
state <= DATA;
DATA : if(data2stop)
state <= STOP;
else if(data2cail)
state <= CAIL;
CAIL : if(cail2stop)
state <= STOP;
STOP : if(stop2idle)
state <= IDLE;
default : state <= IDLE;
endcase
assign idle2start = state == IDLE && tx_din_vld;
assign start2data = state == START && end_bps_cnt;
assign data2stop = state == DATA && end_bit_cnt && CHECK == "None";
assign data2cail = state == DATA && end_bit_cnt;
assign cail2stop = state == CAIL && end_bps_cnt;
assign stop2idle = state == STOP && end_bps_cnt;
/**************************************************************
波特率控制
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_bps <= 'd0;
else if(add_bps_cnt) begin
if(end_bps_cnt)
cnt_bps <= 'd0;
else
cnt_bps <= cnt_bps + 1'b1;
end
assign add_bps_cnt = state != IDLE;
assign end_bps_cnt = add_bps_cnt && cnt_bps == MAX_BPS - 1;
/**************************************************************
数据位控制
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_bit <= 'd0;
else if(add_bit_cnt) begin
if(end_bit_cnt)
cnt_bit <= 'd0;
else
cnt_bit <= cnt_bit + 1'b1;
end
assign add_bit_cnt = end_bps_cnt && state == DATA;
assign end_bit_cnt = add_bit_cnt && cnt_bit == 8 - 1;
/**************************************************************
发送数据寄存
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
tx_din_r <= 0;
else if(tx_din_vld)
tx_din_r <= tx_din;
/**************************************************************
计算校验位
**************************************************************/
(* keep *)wire uart_check;
assign uart_check = ^tx_din_r; //奇校验,缩位异或 1:奇数个1 0:偶数个1
/**************************************************************
UART发送时序
**************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
tx_dout <= 1;
else case(state)
START : tx_dout <= 0;
DATA : tx_dout <= tx_din_r[cnt_bit];
CAIL : tx_dout <= (CHECK == "Odd")? ~uart_check : uart_check;
default : tx_dout <= 1;
endcase
assign tx_ready = state == IDLE;
endmodule
ctrl模块和top模块就不拿出来了,简单实现了下uart的传输功能 。