UART( Universal Asynchronous Receiver/Transmitter)指通用异步收发器。UART电平有TTL电平和RS232电平。TTL电平一般以3.3V居多。RS232是负电平逻辑,+5V—+12V为低电平,而-12V—-5V为高电平。然而FPGA引脚电平一般为TTL电平或者COMS电平,UART外接电平为RS232电平,这就需要将TTL转换为RS232电平的电平转换芯片,如MAX3232,MAX232等。有的电路还用UART转USB芯片,如CP2102、CH340等。
UART通讯协议分析如下:
UART通讯协议一般包括起始位、数据位、校验位和停止位。如下图所示:
一帧数据从一个低位起始位开始。数据位可以是7位也可以是8位。有一个可用的数据位,一个或者几个高位停止位。
如下分析uart_tx.v代码:
module uart_tx
#(
parameter CLK_FRE = 50,
parameter BAUD_RATE = 115200
)
(
input clk,
input rst_n,
input[7:0] tx_data,
input tx_data_valid,
output reg
tx_data_ready,
output tx_pin
);
模块uart_tx说明如下:
CLK_FRE 代表系统设置时钟。
BAUD_RATE表示UART通讯波特率。
clk表示输入时钟引脚。
rst_n表示复位引脚。
tx_data表示8位数据输入。
tx_data_valid为发送使能引脚,高电平表示UART为发送状态,低电平表示UART为接收状态。
tx_data_ready表示准备发送数据寄存器。
tx_pin表示发送引脚。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1’b0)
state <= S_IDLE;
else
state <= next_state;
end
此代码的意思是复位后uart_tx模块处于空闲状态,否则更新为next_state状态。
always @(*)
begin
case(state)
S_IDLE:
if(tx_data_valid == 1'b1)
next_state <= S_START;
else
next_state <= S_IDLE;
S_START:
if(cycle_cnt == CYCLE - 1)
next_state <= S_SEND_BYTE;
else
next_state <= S_START;
S_SEND_BYTE:
if(cycle_cnt == CYCLE - 1&& bit_cnt == 3'd7)
next_state <= S_STOP;
else
next_state <= S_SEND_BYTE;
S_STOP:
if(cycle_cnt == CYCLE - 1)
next_state <= S_IDLE;
else
next_state <= S_STOP;
default:
next_state <= S_IDLE;
endcase
end
此代码描述的是uart_tx模块发送数据时的状态机,分别为空闲态、开始态、发送态和停止态。复位后使得要发送数据时处于空闲态。
在空闲态时,检测tx_data_valid是否为1,如果为1,把next_state赋值为开始态,否则next_state继续为空闲态。
在开始态时,如果时钟计数值(cycle_cnt)达到1位传输时间(CYCLE - 1)时,next_state设置为发送态,否则为开始态。
在发送态时,如果时钟计数值(cycle_cnt)达到1位传输时间(CYCLE - 1)同时接收完本程序中设定的8位数据后next_state设置为停止态,否则为发送态。
在停止态时,如果时钟计数值(cycle_cnt)达到1位传输时间(CYCLE - 1)时,next_state设置为空闲态,否则next_state设置为停止态。
其他情况为空闲态。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
tx_data_ready <= 1'b0;
end
else if(state == S_IDLE)
if(tx_data_valid == 1'b1)
tx_data_ready <= 1'b0;
else
tx_data_ready <= 1'b1;
else if(state == S_STOP && cycle_cnt == CYCLE - 1)
tx_data_ready <= 1'b1;
end
此代码意思为复位状态时tx_data_ready设置为0;在空闲态时,如果tx_data_valid为1,则把tx_data_ready设置为0;,等到停止态结束时设置为1。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
tx_data_latch <= 8'd0;
end
else if(state == S_IDLE && tx_data_valid == 1'b1)
tx_data_latch <= tx_data;
end
此代码表示复位时8位tx_data_latch寄存器清零,在发送状态且处于空闲态时,把tx_data的输入值赋给tx_data_latch。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
bit_cnt <= 3'd0;
end
else if(state == S_SEND_BYTE)
if(cycle_cnt == CYCLE -1)
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
else
bit_cnt <= 3'd0;
end
此段代码表示uart_tx模块在发送数据状态时,每发送1位数据计数标记加1。其他状态或复位状态时,计数标记清零。
always @(negedge clk or posedge rst_n)
begin
if(rst_n == 1'b0)
cycle_cnt <= 16'd0;
else if((state == S_SEND_BYTE && cycle_cnt == CYCLE -1)|| next_state != state)
cycle_cnt <= 16'd0;
else
cycle_cnt <= cycle_cnt + 16'd1;
end
此段代码表示复位时cycle_cnt清0,在发送态并且cycle_cnt计数到CYCLE -1(1位发送时间)时清零或状态变化时清零。其他情况时cycle_cnt计数加1。
always @(negedge clk or posedge rst_n)
begin
if(rst_n == 1'b0)
tx_reg <= 1'b1;
else
case(state)
S_IDLE,S_STOP:
tx_reg <= 1'b1;
S_START:
tx_reg <= 1'b0;
S_SEND_BYTE:
tx_reg <= tx_data_latch[bit_cnt];
default:
tx_reg <= 1'b1;
endcase
end
此代码的意思为:开始态发送的时候,开始位为0;发送态时,tx_data_latch寄存器的值按位送到tx_reg,通过assign tx_pin = tx_reg送到tx_pin输出引脚输出。