verilog实现的UART,带中断、奇偶校验、帧错误
module uart_top
(
input wire clk, //50MHz
input wire rst_n,
input wire rx_in, //串行输入
outputwire intrrupt, //接收数据中断,已收到一个8bit的数据
outputwire tx //串行输出
);
parameter BPS9600 = 16'd5200; //50MHz时的计数值
parameter PARITY_EN = 1'b1; //无校验 PARITY_EN = 0,PARITY_ODD = 0,PARITY_EVEN = 0;
parameter PARITY_ODD= 1'b1; //奇校验 PARITY_EN = 1,PARITY_ODD = 1,PARITY_EVEN = 0;
parameter PARITY_EVEN = 1'b0; //偶校验 PARITY_EN = 1,PARITY_ODD = 0,PARITY_EVEN = 1;
wire bps_start; //接收数据bps开始标志
wire rx_bps_clk; //接收数据标志,在一个bit位的中点
wire tx_bps_clk; //发送数据标志,在一个bit位的起点
wire data_flag; //进入数据位(8位数据位)的标志
wire parity_flag; //进入校验位的标志
wire stop_flag; //进入停止位的标志
wire end_stop; //停止位结束标志
wire parity_enable; //校验使能标志
wire[7:0] rec_data; //接收到的8bit数据
wire bps_start1; //发送数据bps开始标志
wire data_flag1; //进入数据位(8位数据位)的标志
wire parity_flag1; //进入校验位的标志
wire stop_flag1; //进入停止位的标志
wire end_stop1; //停止位的标志
uart_bpsinst_rx_bps
(
.clk (clk ),
.rst_n (rst_n ),
.bps_set (BPS9600 ),
.bps_start (bps_start ),
.parity_enable(PARITY_EN ),
.rx_bps_clk (rx_bps_clk ),
.tx_bps_clk ( ),
.data_flag (data_flag ),
.parity_flag(parity_flag),
.stop_flag (stop_flag ),
.end_stop (end_stop )
);
uart_bpsinst_tx_bps
(
.clk (clk ),
.rst_n (rst_n ),
.bps_set (BPS9600 ),
.bps_start (bps_start1 ),
.parity_enable(PARITY_EN ),
.rx_bps_clk ( ),
.tx_bps_clk (tx_bps_clk ),
.data_flag (data_flag1 ),
.parity_flag(parity_flag1 ),
.stop_flag (stop_flag1 ),
.end_stop (end_stop1 )
);
uart_rx inst_uart_rx
(
.clk (clk ),
.rst_n (rst_n ),
.rx_in (rx_in ),
.rx_bps_clk (rx_bps_clk ),
.pari_odd (PARITY_ODD ),
.pari_even (PARITY_EVEN),
.data_flag (data_flag ),
.parity_flag(parity_flag),
.stop_flag (stop_flag ),
.end_stop (end_stop ),
.bps_start (bps_start ),
.rec_data (rec_data ),
.intrrupt (intrrupt )
);
uart_tx inst_uart_tx
(
.clk (clk ),
.rst_n (rst_n ),
.rec_data (rec_data ),
.tx_bps_clk (tx_bps_clk ),
.pari_odd (PARITY_ODD ),
.pari_even (PARITY_EVEN),
.data_flag (data_flag1 ),
.parity_flag(parity_flag1 ),
.stop_flag (stop_flag1 ),
.end_stop (end_stop1 ),
.intrrupt (intrrupt ),
.bps_start (bps_start1 ),
.tx (tx )
);
endmodule
module uart_bps
(
input wire clk,
input wire rst_n,
input wire[15:0]bps_set,
input wire bps_start,
input wire parity_enable,
outputwire rx_bps_clk,
outputwire tx_bps_clk,
outputwire data_flag,
outputwire parity_flag,
outputwire stop_flag,
outputwire end_stop
);
reg[ 3:0] frame_num;
reg[15:0] cnt;
reg[ 3:0] num_bit;
reg en_cnt;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
frame_num <= 4'd9;
else if(parity_enable)
frame_num <= 4'd10; //有校验位,则一帧为10bit
else
frame_num <= 4'd9; //无校验位,一帧为9bit
end
assignrx_bps_clk= ( cnt == bps_set/2); //接收数据标志,在一个bit位的中点
assigntx_bps_clk= ( cnt == 16'd2); //发送数据标志,在一个bit位的起点
assigndata_flag = ((cnt == 16'd0) & (num_bit == 4'd1)); //进入数据位(8位数据位)的标志
assignparity_flag = parity_enable ? ((cnt == 16'd0) & (num_bit == (frame_num - 1'b1))) : 1'b0; //进入校验位的标志
assignstop_flag = ((cnt == 16'd0) & (num_bit == frame_num));//进入停止位的标志
assignend_stop = ((cnt == bps_set) & (num_bit == frame_num));//停止位结束标志
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
cnt <= 16'b0;
num_bit <= 4'b0;
en_cnt<= 1'b0;
end
else
begin
if(bps_start)
en_cnt <= 1'b1;
if((cnt == bps_set) & (num_bit == frame_num))
en_cnt <= 1'b0;
if(cnt == bps_set)
cnt <= 16'b0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 16'b0;
if((cnt == bps_set) & (num_bit == frame_num))
num_bit <= 16'b0;
else if(cnt == bps_set)
num_bit <= num_bit + 1'b1;
end
end
endmodule
module uart_rx
(
input wire clk,
input wire rst_n,
input wire rx_in,
input wire rx_bps_clk,
input wire pari_odd,
input wire pari_even,
input wire data_flag,
input wire parity_flag,
input wire stop_flag,
input wire end_stop,
outputreg bps_start,
outputreg[7:0]rec_data,
outputreg intrrupt
);
parameter IDLE = 4'd0; //空闲状态
parameter START = 4'd1; //开始位状态
parameter REC_DAT = 4'd2; //接收数据位状态
parameter PARITY= 4'd3; //校验为状态
parameter STOP = 4'd4; //停止位状态
parameter INT_GEN = 4'd5; //接收数据中断状态
reg rx_in_r1;
reg rx_in_r2;
reg rx_in_r3;
reg[3:0] int_cnt;
reg data_error;
reg frame_error;
reg[3:0] state;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
rx_in_r1 <= 1'b0;
rx_in_r2 <= 1'b0;
rx_in_r3 <= 1'b0;
end
else
begin
rx_in_r1 <= rx_in;
rx_in_r2 <= rx_in_r1;
rx_in_r3 <= rx_in_r2;
end
end
wireneg_rx_flag = ~rx_in_r2 & rx_in_r3; //检测数据开始标志1 --> 0变化
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
state <= IDLE;
bps_start <= 1'b0;
rec_data <= 8'b0;
intrrupt <= 1'b0;
int_cnt <= 4'b0;
data_error<= 1'b0;
frame_error <= 1'b0;
end
else
begin
case(state)
IDLE :
begin
intrrupt <= 1'b0;
data_error<= 1'b0;
frame_error <= 1'b0;
int_cnt <= 4'b0;
if(neg_rx_flag)
begin
state <= START;
bps_start <= 1'b1; //产生接收数据波特率开始标志
end
else
state <= IDLE;
end
START :
begin
bps_start <= 1'b0;
if(data_flag)
state <= REC_DAT;
else
state <= START;
end
REC_DAT :
begin
if(stop_flag)
state <= STOP;
else if(parity_flag)
state <= PARITY;
else
state <= REC_DAT;
if(rx_bps_clk)
rec_data <= {rx_in,rec_data[7:1]}; //接收数据
end
PARITY :
begin
if(stop_flag)
state <= STOP;
else
state <= PARITY;
if(rx_bps_clk)
begin
if(((pari_odd) & ((^rec_data) == (~rx_in))) | ((pari_even) & ((^rec_data) == rx_in)))
data_error <= 1'b0;
else
data_error <= 1'b1;
end
end
STOP :
begin
if(end_stop)
state <= INT_GEN;
else
state <= STOP;
if(rx_bps_clk)
begin
if(rx_in == 1'b1)
frame_error <= 1'b0;
else
frame_error <= 1'b1;
end
end
INT_GEN :
begin
if(int_cnt < 4'd10) //产生中断计数
int_cnt <= int_cnt + 1'b1;
if(int_cnt == 4'd10)
state <= IDLE;
if((int_cnt >= 4'd0) & (int_cnt <= 4'd10) & (data_error == 1'b0) & (frame_error == 1'b0))
intrrupt <= 1'b1;
else
intrrupt <= 1'b0;
end
default :
begin
state <= IDLE;
bps_start <= 1'b0;
rec_data <= 8'b0;
intrrupt <= 1'b0;
int_cnt <= 4'b0;
data_error<= 1'b0;
frame_error <= 1'b0;
end
endcase
end
end
endmodule
module uart_tx(
input wire clk,
input wire rst_n,
input wire[7:0]rec_data,
input wire tx_bps_clk,
input wire pari_odd,
input wire pari_even,
input wire data_flag,
input wire parity_flag,
input wire stop_flag,
input wire end_stop,
input wire intrrupt,
outputreg bps_start,
outputreg tx
);
parameter IDLE = 4'd0; //空闲状态
parameter START = 4'd1; //开始状态
parameter TX_DAT= 4'd2; //发送数据位状态
parameter PARITY= 4'd3; //校验位状态
parameter STOP = 4'd4; //停止位状态
reg parity_r;
reg[3:0] state;
reg[7:0] data_temp;
reg intrrupt_r1;
reg intrrupt_r2;
wire neg_intrrupt;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
intrrupt_r1 <= 1'b0;
intrrupt_r2 <= 1'b0;
end
else
begin
intrrupt_r1 <= intrrupt;
intrrupt_r2 <= intrrupt_r1;
end
end
assign neg_intrrupt = (~intrrupt_r1) & intrrupt_r2; //检测接收数据中断的下降沿
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
state <= IDLE;
bps_start <= 1'b0;
data_temp <= 8'b0;
tx <= 1'b1;
end
else
begin
case(state)
IDLE :
begin
if(neg_intrrupt)
begin
state <= START;
bps_start <= 1'b1; //产生发送数据波特率开始标志
data_temp <= rec_data;
end
else
state <= IDLE;
end
START :
begin
bps_start <= 1'b0;
if(data_flag)
state <= TX_DAT;
else
state <= START;
if(tx_bps_clk)
tx <= 1'b0;
end
TX_DAT :
begin
if(stop_flag)
state <= STOP;
else if(parity_flag)
state <= PARITY;
else
state <= TX_DAT;
if(tx_bps_clk)
begin
tx <= data_temp[0];
data_temp <= {data_temp[0],data_temp[7:1]};
end
end
PARITY :
begin
if(stop_flag)
state <= STOP;
else
state <= PARITY;
if(tx_bps_clk)
begin
if(pari_odd & (^data_temp))
tx <= 1'b0;
if(pari_odd & (~(^data_temp)))
tx <= 1'b1;
if(pari_even & (^data_temp))
tx <= 1'b1;
if(pari_even & (~(^data_temp)))
&