UART : Universal Asynchronous Receiver/Transmitter : 异步收发传输器; 分为2个PART(发送 和接收);-------------学习笔记(一) Alex.Lee
**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
PART I 发送部分
本实验是以波特率为9600,为例来讲述UART;
首先,先介绍下串口的发送机制( 如图一 )
图一
即 UART 的发送(TX)机制,一般分为5个状态,即空闲位、 起始位、发送数据位、校验、停止位;
空闲(Idle):TX空闲时为High Level status;
起始(Start):TX 从高跳变到低电平,标志着下一个Bit将传送有效的数据;
数据(Data): TX将根据发送寄存器里的数据值,依次发送;(【注】:在传送的数据顺序为 First LSB ,Last MSB,先低位,后高位;)数据一般为7或8bit;
校验( Check): TX 发送完数据位后,可使用校验位来使传送的数据更加准确,即使用 奇偶校验; 也可以不使用校验;
停止(Stop): 发送停止位,即TX发送一 个BIt 的高电平,标志本次数据传送结束;一般用 帧错误检测 (Frame error:传送一帧数据是否出错);
发送机制的过程可概括 为:
Step 1 : 在空闲时TX为High Level ,当要发送数据时,则将pull down TX 线 作为 发送起始位标志,即TX 发送一个Bit 位的低电平。
Step 2 : 发送完起始位后,将进入发送数据, TX 将从接收缓冲器中依次从最低位 到最高位取出数据并在时钟周期到来时发送;一般数据位为8位即 1Byte。
Step 3 : 发送完一帧数据后,为了确保数据的准确传输,一般会使一个bit位 用 于奇偶校验,来判断数据是否出错。
Step 4 ::最后将发送一个bit的高电平作为发送停止位的标志,同时表明一帧数据传输完成。
CODE :
`timescale 1ns / 1ps
module Uart_tx(clk,rst_n,wrig,datain,tx,idle);
input clk;
input rst_n;
input wrig;
input [7:0]datain;
output tx;
output idle;
reg tx, idle;
reg send;
reg result;
reg[7:0] timer;
reg tx_temp,tx_raising;
parameter poritymode = 1'b0;
always@(posedge clk) // raise edge valid
begin
tx_temp <= wrig;
tx_raising <= wrig & (~tx_temp);
end
always@(posedge clk)
begin
if(tx_raising &&(~idle))
begin
send <= 1'b1;
end
else if(timer == 8'd168)
begin
send <= 1'b0;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
tx <= 1'b0;
idle <= 1'b0;
timer <= 8'd0;
result <= 1'b0;
end
else if(send == 1'b1)
begin
case(timer)
8'd0: //Start
begin
tx <= 1'b0;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd16://Send Bit0
begin
tx <= datain[0];
result <= datain[0]^poritymode;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd32://Send Bit1
begin
tx <= datain[1];
result <= datain[1]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd48:// Send Bit2
begin
tx <= datain[2];
result <= datain[2]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd64: //Send Bit3
begin
tx <= datain[3];
result <= datain[3]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd80://Send Bit4
begin
tx <= datain[4];
result <= datain[4]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd96:// Send Bit5
begin
tx <= datain[5];
result <= datain[5]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd112://Send Bit6
begin
tx <= datain[6];
result <= datain[6]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd128://Send Bit7
begin
tx <= datain[7];
result <= datain[7]^result;
idle <= 1'b1;
timer <= timer + 8'd1;
end
8'd144://Send Poritymode
begin
tx <= result;
result <= datain[0]^poritymode; //non-blocking assign
idle <= 1'b1;
timer <= timer + 8'd1;
//if(tx == result)
end
8'd160://Send stop Bit
begin
idle <= 1'b1;
tx <= 1'b1;
timer <= timer + 8'd1;
end
8'd168:// a frame data finished
begin
tx <= 1'b1;
idle <= 1'b0;
timer <= timer + 8'd1;
end
default: begin
timer <= timer + 8'd1;
end
endcase
end
else begin
tx <= 1'b1;
timer <= 8'd0;
idle <= 1'b0;
end
end
endmodule
*****************************************
*****************************************
RTL图:
图二 RTL
**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
PART II 接收部分
接收部分 : 由RX来负责接收数据;
图三 RX
CODE:
`timescale 1ns / 1ps
module Uart_rx(clk,rst_n,rx,dataout,error,frameerror,rsig);
input clk;
input rst_n;
input rx;
output reg [7:0]dataout;
output error;
output frameerror;
output rsig;
//output idle;
reg rsig ,error;
reg[7:0]timer;
//reg [7:0]dataout;
reg frameerror;
reg rx_temp, rx_falling;
reg result;
reg idle;
reg receive;
parameter poritymode = 1'b0;
always@(posedge clk ) //Generate falling edge timing //first high ,than low .
begin
rx_temp <= rx;
rx_falling <= rx_temp &(~rx);
end
//Generate Ack Signal
always@(posedge clk )
begin
if(rx_falling &&(~idle)) // !!!!!!!! at the same time satisfy the select
begin
receive <= 1'b1;
end
else if(timer == 8'd168)
begin
receive <= 1'b0;
end
end
//Receive Data
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
error <= 1'b0; // high voltage represent error !
frameerror <= 1'b0;// H
idle <= 1'b0; //
timer <= 8'd0; // counter clear 0
result <= 1'b0; // clear 0
//dataout <= 8'd0;
rsig <= 1'b0;
end
else if(receive == 1'b1) // receive data becycle
begin
case(timer)
8'd0://Generate Start pulse
begin
idle <= 1'b1;
timer <= timer + 8'd1;
rsig <= 1'b0;
end
8'd24:// Receive Bit0
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[0] <= rx;
timer <= timer + 8'd1;
// data restore in buffer
result <= poritymode^rx; // compare odd
end
8'd40: // Received Bit1
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[1] <= rx;
timer <= timer + 8'd1;
result <= result^rx;
end
8'd56: // Receive Bit2
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[2]<= rx;
timer <= timer + 8'd1;
result <= result^rx;
end
8'd72: // Receive Bit3
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[3] <= rx;
timer <= timer + 8'd1;
result <= result^rx;
end
8'd88: // Receive Bit4
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[4] <= rx;
timer <= timer + 8'd1;
result <= result^rx;
end
8'd104: // Receive Bit5
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[5] <= rx;
timer <= timer + 8'd1;
result <= result^rx;
end
8'd120: // Receive Bit6
begin
idle <= 1'b1;
rsig <= 1'b0;
dataout[6] <= rx;
timer <= timer + 8'd1;
result <= result^rx;
end
8'd136: // Receive Bit7
begin
idle <= 1'b1;
dataout[7] <= rx;
result <= result^rx;
timer <= timer + 8'd1;
rsig <= 1'b1;
end
8'd152: // Receive Pority
begin
idle <= 1'b1;
if(result == rx)
error <= 1'b0;
else
error <= 1'b1;
timer <= timer + 8'd1;
rsig <= 1'b1;
end
8'd168: //Receive Stop Bit . Frame Judge
begin
idle <= 1'b1;
if(1'b1 == rx)
frameerror <= 1'b0;
else
frameerror <= 1'b1;
//timer <= 8'd0;
timer <= timer + 8'd1;
rsig <= 1'b1;
end
default : timer <= timer + 8'd1;
endcase
end
else
begin
timer <= 8'd0;
idle <= 1'b0;
rsig <= 1'b0;
end
end
endmodule