UART
通用异步收发器(Universal Asynchronous Receiver/Transmitter,UART)可以和各种标准串行接口,如RS 232和RS 485等进行全双工异步通信,具有传输距离远、成本低、可靠性高等优点。一般UART由专用芯片如8250,16450来实现,但专用芯片引脚都较多,内含许多辅助功能,在实际使用时往往只需要用到UART的基本功能,使用专用芯片会造成资源浪费和成本提高。 UART只需要两条信号线:RXD和TXD,其中RXD是UART的接收端,TXD是UART的发送端,接收与发送是全双工形式。下图为UART的工作原理如下 如上图所示,uart是将传输数据的每个字符一位接一位地传输。 其中每一位(Bit)的意义如下: 空闲位:高电平,表明当前无传输事务。 起始位:一位低电平信号,标志着数据传输的开始。 数据位:紧接着起始位之后。数据位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。 奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。 停止位:一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。 uart数据传输的速率用波特率表示,其含义为从一设备发到另一设备,每秒钟可以通信的数据比特个数。典型的波特率有300, 1200, 2400, 9600, 19200, 115200等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。
UART的Verilog实现
uart的设计分为两个部分,一部分为发送模块,另一部分为接收模块。程序设计主要通过状态机实现,在本设计中,我们略去了奇偶校验位,每次传输8bit数据,且停止位为1位。 我们共设置了如下几个状态: IDLE:空闲状态,电平恒为1; START:起始位,电平为0,1位; DATA:数据位,共8位,先发送低比特; STOP:停止位,高电平,共1位。 其中,发送模块在上一状态向下一状态切换时,改变电平,而接收模块,则在状态的中间位置进行采样,如下图所示:
代码实现
发送模块
`timescale 1ns / 1ps
module uart_tx_sim
#(parameter BPS=5208)
(
input clk,
input rst_n,
input start,
input [7:0] send_data,
output reg rs232_tx
);
parameter IDLE = 0;
parameter START = 1;
parameter SEND = 2;
parameter STOP =3;
reg [2:0] cur_state;
reg [2:0] next_state;
reg [31:0] count;
reg [31:0] send_cnt;
always@(posedge clk,negedge rst_n)
if(~rst_n)
cur_state<=IDLE;
else
cur_state<=next_state;
always@(*)
case(cur_state)
IDLE:if(start)
next_state=START;
else
next_state=IDLE;
START:if(count==BPS-1)
next_state=SEND;
else
next_state=START;
SEND:if(send_cnt==8-1&&count==BPS-1)
next_state=STOP;
else
next_state=SEND;
STOP:if(count==BPS-1)
next_state=IDLE;
else
next_state=STOP;
default:next_state=IDLE;
endcase
always@(posedge clk,negedge rst_n)
if(~rst_n)
count<=0;
else if(cur_state!=IDLE)
begin
if(count==BPS-1)
count<=0;
else
count<=count+1;
end
else
count<=0;
always@(posedge clk,negedge rst_n)
if(~rst_n)
send_cnt<=0;
else if(cur_state==SEND&&count==BPS-1)
send_cnt<=send_cnt+1;
else if(cur_state!=SEND)
send_cnt<=0;
always@(*)
case(cur_state)
IDLE:rs232_tx=1;
START:rs232_tx=0;
SEND:begin
case(send_cnt)
0:rs232_tx=send_data[0];
1:rs232_tx=send_data[1];
2:rs232_tx=send_data[2];
3:rs232_tx=send_data[3];
4:rs232_tx=send_data[4];
5:rs232_tx=send_data[5];
6:rs232_tx=send_data[6];
7:rs232_tx=send_data[7];
default:rs232_tx=1;
endcase
end
STOP:rs232_tx=1;
default:rs232_tx=1;
endcase
endmodule
接收模块
`timescale 1ns / 1ps
module uart_rx_sim
#(parameter BPS=5208)
(
input clk,
input rst_n,
input rs232_rx,
output reg valid,
output reg [7:0] recv_data
);
parameter IDLE = 0;
parameter START = 1;
parameter RECV = 2;
parameter STOP =3;
reg sample_edge;
reg [2:0] cur_state;
reg [2:0] next_state;
reg [31:0] count;
reg [2:0] recv_cnt;
reg rs232_rx_ff1;
always@(posedge clk)
rs232_rx_ff1<=rs232_rx;
always@(posedge clk,negedge rst_n)
if(~rst_n)
cur_state<=IDLE;
else
cur_state<=next_state;
always@(*)
begin
case(cur_state)
IDLE:if(~rs232_rx&&rs232_rx_ff1)
next_state=START;
else
next_state=IDLE;
START:if(count==BPS-2)
next_state=RECV;
else
next_state=START;
RECV:if(recv_cnt==8-1&&count==BPS-1)
next_state=STOP;
else
next_state=RECV;
STOP:if(count==BPS-1)
next_state=IDLE;
else
next_state=STOP;
default:next_state=IDLE;
endcase
end
always@(posedge clk,negedge rst_n)
if(~rst_n)
count<=0;
else
case(cur_state)
IDLE:count<=0;
START:if(count==BPS-2)
count<=0;
else
count<=count+1;
RECV:if(count==BPS-1)
count<=0;
else
count<=count+1;
STOP:if(count==BPS-1)
count<=0;
else
count<=count+1;
default:count<=0;
endcase
always@(posedge clk,negedge rst_n)
if(~rst_n)
recv_cnt<=0;
else if(cur_state==RECV&&count==BPS-1)
recv_cnt<=recv_cnt+1;
else if(cur_state==STOP)
recv_cnt<=0;
always@(posedge clk,negedge rst_n)
if(~rst_n)
sample_edge<=0;
else if(cur_state==RECV&&count==BPS/2-1)
sample_edge<=1;
else
sample_edge<=0;
always@(posedge clk)
if(cur_state==RECV&&sample_edge)
begin
case(recv_cnt)
0:recv_data[0]<=rs232_rx;
1:recv_data[1]<=rs232_rx;
2:recv_data[2]<=rs232_rx;
3:recv_data[3]<=rs232_rx;
4:recv_data[4]<=rs232_rx;
5:recv_data[5]<=rs232_rx;
6:recv_data[6]<=rs232_rx;
7:recv_data[7]<=rs232_rx;
default:;
endcase
end
always@(posedge clk,negedge rst_n)
if(~rst_n)
valid<=0;
else if(cur_state==STOP)
valid<=1;
else if(~rs232_rx&&rs232_rx_ff1&&cur_state==IDLE)
valid<=0;
endmodule
完整工程
见链接:https://pan.baidu.com/s/1TdDGv-eiPZ91tepzJGSvhg 提取码:zdfw
|