赞
踩
UART (Universal Asynchronous Receiver/Transmitter) 是一种常用的串行通讯协议,用于数据在电子设备之间的传输和通讯。它是一种异步数据传输协议,在通讯时不需要发送方和接收方之间的时钟信号同步。
UART 协议通常使用两条线路进行通讯,一条用于数据传输(TX),一条用于数据接收(RX)。uart的传输格式如下:(TX跟RX均为一位)
空闲状态:空闲状态时,uart传输位始终保持高电平状态
起始位:uart传输位拉低一个低电平并且持续一个周期,传输开始
数据传输状态:uart实际要传输的数据位数,可以是 5、6、7 或 8 位。
奇偶校验状态:是可选的,可以选择奇校验还是偶校验,用于数据的验证,通常为 0 (即不使用奇偶校验)或 1 位。
奇校验:数据1个数为奇时,校验为0,反之为1;
偶校验:数据0个数为奇时,校验为0,反之为1;
停止位状态:用于标识数据传输的结束位置,通常为 1 或 2 位。uart传输位恢复高电平
本次的实验代码使用的数据传输位数为8位,奇偶校验位数为1位,停止位为1位
uart_tx模块主要是负责将要传输的八位数据进行并串转化,输出八个单bit数据,优先输出高位uart的发送端模块分为空闲状态,开始状态,传输数据状态,奇偶校验状态和停止模块。状态图如下:
verilog代码如下:
- module uart_tx(
- input sysclk ,
- input rst_n ,
- input [7:0] tx_data,
- input tx_en ,
- output reg tx ,
- output reg tx_done
- );
-
- parameter CLK_FREQ = 50000000 ; //
- parameter UART_BPS = 9600 ;
- localparam BPS_CNT = CLK_FREQ/UART_BPS;//每个数据位占用的周期
- parameter EVEN_ODD_CHECK = 1 ;
-
- parameter IDLE =5'b00001;
- parameter START=5'b00010;
- parameter DATA =5'b00100;
- parameter CHECK=5'b01000;
- parameter DONE =5'b10000;
- reg [4:0] state ;
- reg tx_flag ;//数据正在传输
- reg [3:0] tx_cnt ;//数据传输位计数器,
- reg [15:0] data_cnt ;
- reg check_flag;
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- data_cnt<=16'd0 ;
- else if(data_cnt==BPS_CNT)
- data_cnt<=16'd0 ;
- else if(tx_en==1'b1)
- data_cnt<=data_cnt+1'b1;
- else
- data_cnt<=data_cnt ;
- end
-
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- tx_cnt<=4'd0 ;
- else if(tx_cnt==4'd11)
- tx_cnt<=4'd0 ;
- else if ((tx_en==1'b1)&&(data_cnt==BPS_CNT))
- tx_cnt<=tx_cnt+1'b1;
- else
- tx_cnt<=tx_cnt ;
- end
-
- always @(posedge sysclk or negedge rst_n )
- if(rst_n==1'b0) begin
- state<=IDLE;
- end
- else
- case (state)
- IDLE: begin
- if((tx_en==1'b1)&&(tx_cnt==4'd1))
- state<=START;
- else
- state<=IDLE;
- end
- START :begin
- if(tx_cnt==4'd2)
- state<=DATA;
- else
- state<=START;
- end
- DATA:begin
- if(tx_cnt==4'd10)
- state<=CHECK;
- else
- state<=DATA;
- end
- CHECK:begin
- if(check_flag)
- state<=DONE;
- else
- state<=CHECK;
- end
- DONE:begin
- if(tx_done==1'b1)
- state<=IDLE;
- else
- state<=DONE;
- end
- default begin
- state<=IDLE;
- end
- endcase
-
- always @(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- tx_flag<=1'b0;
- else if (state==DATA)
- tx_flag<=1'b1;
- else
- tx_flag<=tx_flag;
- end
- always@(posedge sysclk or negedge rst_n) begin
- if (rst_n==1'b0)
- tx_done<=1'b0;
- else if ((state==DONE)&&(data_cnt==BPS_CNT))
- tx_done<=1'b1;
- else
- tx_done<=1'b0;
- end
- reg [7:0] data;
- reg [2:0] cnt;
- reg check;
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- tx<=1'b1;
- else if(state==IDLE)
- tx<=1'b1;
- else if(state==START)
- tx<=1'b0;
- else if(state==DATA)
- tx<=data[7-cnt];
- else if(state==CHECK)
- tx<=check;
- else if(state==DONE)
- tx<=1'b1;
- else
- tx<=tx;
- end
-
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- data<=8'd0;
- else if (state==START)
- data<=tx_data;
- else
- data<=data;
- end
-
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- cnt<=3'd0;
- else
- case(tx_cnt)
- 4'd0:cnt<=3'd0;
- 4'd1:cnt<=3'd0;
- 4'd2:cnt<=3'd1;
- 4'd3:cnt<=3'd2;
- 4'd4:cnt<=3'd3;
- 4'd5:cnt<=3'd4;
- 4'd6:cnt<=3'd5;
- 4'd7:cnt<=3'd6;
- 4'd8:cnt<=3'd7;
- 4'd9:cnt<=3'd0;
- 4'd10:cnt<=3'd0;
- default begin
- cnt<=cnt;
- end
- endcase
- end
-
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- check_flag<=1'b0;
- else if ((data_cnt==BPS_CNT)&&(state==CHECK))
- check_flag<=1'b1;
- else
- check_flag<=1'b0;
- end
-
- reg even_check;
- reg odd_check;
- always@(posedge sysclk or negedge rst_n)
- if(rst_n==1'b0) begin
- even_check<=1'b0;
- odd_check <=1'b0;
- end
- else if(tx==1'b1) begin
- even_check<=^tx_data;
- odd_check<=~^tx_data;
- end
- else begin
- even_check<=even_check;
- odd_check<=odd_check;
- end
-
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- check<=1'b0;
- else if(tx_en==1'b1&&EVEN_ODD_CHECK==1'b1)
- check<=even_check;
- else if(tx_en==1'b1&&EVEN_ODD_CHECK==1'b0)
- check<=odd_check;
- else
- check<=check;
- end
- endmodule
uart接收模块负责将接收到的单bit数据进行串并转化,输出一个8位的数据,先传输过来的数据放在高位。uart的发送端模块分为空闲状态,开始状态,传输数据状态,奇偶校验状态和停止模块。状态图如下:
verilog代码如下:
- module uart_rx(
- input sysclk ,
- input rst_n ,
- input tx ,
- input tx_done,
- output reg[7:0] rx_data,
- output reg error ,
- output reg rx_done
- );
-
- parameter CLK_FREQ = 50000000 ; //
- parameter UART_BPS = 9600 ;
- localparam BPS_CNT = CLK_FREQ/UART_BPS;//每个数据位占用的周期
- parameter EVEN_ODD_CHECK = 1 ;
-
- parameter IDLE =5'b00001;
- parameter START=5'b00010;
- parameter DATA =5'b00100;//接收数据
- parameter CHECK=5'b01000;
- parameter DONE =5'b10000;
- reg [4:0]state;
- reg [15:0] data_cnt ;//计数到BPS_CNT
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- data_cnt<=16'd0 ;
- else if(data_cnt>BPS_CNT)
- data_cnt<=16'd0 ;
- else if(data_cnt<BPS_CNT)
- data_cnt<=data_cnt+1'b1;
- else
- data_cnt<=data_cnt ;
- end
- reg [3:0] rx_cnt;//每到bps_cnt计数
- always@(posedge sysclk or negedge rst_n)begin
- if(rst_n==1'b0)
- rx_cnt<=4'd0 ;
- else if(rx_cnt==4'd11)
- rx_cnt<=4'd0 ;
- else if (data_cnt==BPS_CNT)
- rx_cnt<=rx_cnt+1'b1;
- else
- rx_cnt<=rx_cnt ;
- end
-
- reg start_end;
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- start_end<=1'b0;
- else if((state==START)&&(data_cnt==BPS_CNT))
- start_end<=1'b1;
- else
- start_end<=start_end;
- end
- reg check_flag;
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- check_flag<=1'b0;
- else if ((data_cnt==BPS_CNT)&&(state==CHECK))
- check_flag<=1'b1;
- else
- check_flag<=1'b0;
- end
-
- reg [2:0]cnt;
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- cnt<=3'd0;
- else
- case(rx_cnt)
- 4'd0:cnt<=3'd0;
- 4'd1:cnt<=3'd0;
- 4'd2:cnt<=3'd1;
- 4'd3:cnt<=3'd2;
- 4'd4:cnt<=3'd3;
- 4'd5:cnt<=3'd4;
- 4'd6:cnt<=3'd5;
- 4'd7:cnt<=3'd6;
- 4'd8:cnt<=3'd7;
- 4'd9:cnt<=3'd0;
- 4'd10:cnt<=3'd0;
- default begin
- cnt<=cnt;
- end
- endcase
- end
- reg data_done;//当state==data,cnt=7时拉�?
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- data_done<=1'b0;
- else if (cnt==3'd7&&state==DATA)
- data_done<=1'b1;
- else
- data_done<=1'b0;
- end
-
- //state
- reg check;
- always @(posedge sysclk or negedge rst_n )
- if(rst_n==1'b0) begin
- state<=IDLE;
- end
- else
- case (state)
- IDLE: begin
- if(tx_done)
- state<=START;
- else
- state<=IDLE;
- end
- START :begin
- if(start_end)
- state<=DATA;
- else
- state<=START;
- end
- DATA:begin
- if(data_done)
- state<=CHECK;
- else
- state<=DATA;
- end
- CHECK:begin
- if(check_flag)
- state<=DONE;
- else
- state<=CHECK;
- end
- DONE:begin
- if(rx_done==1'b1)
- state<=IDLE;
- else
- state<=DONE;
- end
- default begin
- state<=IDLE;
- end
- endcase
-
- reg [7:0]shift_reg;
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- shift_reg<=8'd0;
- else if((state==DATA)&&(data_cnt==BPS_CNT))
- shift_reg<={tx,shift_reg[7:1]};
- else
- shift_reg<=shift_reg;
- end
-
- always@(posedge sysclk or negedge rst_n)
- if(rst_n==1'b0) begin
- rx_data<=8'd0;
- rx_done<=1'b0;
- end
- else if(state==DATA&&rx_cnt==3'd7) begin
- rx_data<=shift_reg;
- rx_done<=1'b1;
- end
- else begin
- rx_data<=rx_data;
- rx_done<=rx_done;
- end
-
- reg even_check;
- reg odd_check;
- always@(posedge sysclk or negedge rst_n)
- if(rst_n==1'b0) begin
- even_check<=1'b0;
- odd_check <=1'b0;
- end
- else if(tx==1'b1) begin
- even_check<=^rx_data;
- odd_check<=~^rx_data;
- end
- else begin
- even_check<=even_check;
- odd_check<=odd_check;
- end
-
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- check<=1'b0;
- else if(EVEN_ODD_CHECK==1'b1)
- check<=even_check;
- else if(EVEN_ODD_CHECK==1'b0)
- check<=odd_check;
- else
- check<=check;
- end
- always@(posedge sysclk or negedge rst_n) begin
- if(rst_n==1'b0)
- error<=1'b0;
- else if((state==CHECK)&&(tx==check))
- error<=1'b0;
- else if(state==CHECK&&tx!=check)
- error<=1'b1;
- else
- error<=error;
- end
- endmodule
- module uart_top(
- input sysclk ,
- input rst_n ,
- input [7:0] tx_data,
- input tx_en ,
- output [7:0] rx_data,
- output error ,
- output rx_done
- );
- wire tx_done;
- wire tx ;
-
- uart_tx uart_tx_u(
- .sysclk (sysclk ),
- .rst_n (rst_n ),
- .tx_data(tx_data),
- .tx_en (tx_en ),
- .tx (tx ),
- .tx_done(tx_done)
- );
-
- uart_rx uart_rx_u(
- .sysclk (sysclk ),
- .rst_n (rst_n ),
- .tx (tx ),
- .tx_done(tx_done),
- .rx_data(rx_data),
- .error (error ),
- .rx_done(rx_done)
- );
-
- endmodule
- module uart_tb();
- reg sysclk ;
- reg rst_n ;
- reg [7:0] tx_data;
- reg tx_en ;
- wire [7:0] rx_data;
- wire error ;
- wire rx_done;
- uart_top uart_top_u(
- .sysclk (sysclk ),
- .rst_n (rst_n ),
- .tx_data(tx_data),
- .tx_en (tx_en ),
- .rx_data(rx_data),
- .error (error ),
- .rx_done(rx_done)
- );
-
- initial begin
- sysclk <=1'b0 ;
- rst_n <=1'b0 ;
- tx_data<=8'd0 ;
- tx_en <=1'b0 ;
- #10;
- rst_n <=1'b1 ;
- tx_en <=1'b1 ;
- #15;
- tx_data<=8'd36;
- end
- always #10sysclk=!sysclk;
- endmodule
可以看出,uart_tx模块跟uart_rx模块仅使用两条线路进行通讯
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。