//UART串行口模块,波特率9600bps
//20110118
module UART (
sys_clk,//系统时钟输入
reset_n,//异步复位输入
Rx,//数据输入引脚
NewRxData,//接收到新数据
RxDATA//RxDATA当前接收的数据
);
input sys_clk,reset_n,Rx;
output NewRxData;
output [7 : 0] RxDATA;
reg [7 : 0] RxDATA;
parameter SYS_CLK = 20000000;//系统时钟
parameter Rx_CLK = 9600;//9600bps
parameter RxDATA_W = 12;//波特率时钟发生器分频寄存器位宽
parameter RXCLK_DATA = SYS_CLK / Rx_CLK - 1;//波特率分频器时钟分频值 (2083)
//波特率时钟发生器
reg [RxDATA_W-1 : 0] clk_cnt;
reg EN_RXCLK;//使能接收时钟
wire RX_CLK;//接收波特率时钟
always @ (posedge sys_clk or negedge reset_n)
if(!reset_n)
clk_cnt <= 12'd0;
else if(!EN_RXCLK)//不需要使能时钟
clk_cnt <= 12'd0;
else if(clk_cnt == RXCLK_DATA)
clk_cnt <= 12'd0;
else
clk_cnt <= clk_cnt + 1'b1;
assign RX_CLK = (clk_cnt == RXCLK_DATA/2);//产生接收时钟
//接收数据线下降沿检测,用来启动数据接收
//采用边沿检测法,因为数据线空闲位高,起始位位低,因此1帧数据开始有一个下降沿
reg RxThis,RxLast;
wire RxStart;
always @ (posedge sys_clk or negedge reset_n)
if(!reset_n) begin
RxThis = 1'b0;
RxLast = 1'b0;
end
else begin
RxLast <= RxThis;
RxThis <= Rx;
end
assign RxStart = RxLast&&(!RxThis);//产生起始信号
//数据接收控制逻辑
reg [10 : 0] RxTemp;
reg [4 : 0] RxState;
reg NewRxData;
always @ (posedge sys_clk or negedge reset_n)
if(!reset_n) begin
RxDATA = 8'd0;
RxTemp = 11'd0;
RxState = 5'd0;
EN_RXCLK = 1'b0;//停止接收时钟
NewRxData = 1'b0;//去除新数据标志
end
else if((RxState==5'd0) && RxStart)begin//有起始信号,并且接收器空闲,则再次检测起始信号
EN_RXCLK <= 1'd1;//启动接收时钟
RxState <= 5'b1; //进入接收状态机
end
else if(RX_CLK) begin //每个接收时钟启动一次
case (RxState) //synthesis full_case
5'd1 : begin
RxTemp[0] = Rx;//接收起始位
RxState <= 5'd2;
end
5'd2 : begin
RxTemp[1] = Rx;//bit0
RxState <= 5'd3;
end
5'd3 : begin
RxTemp[2] = Rx;//bit1
RxState <= 5'd4;
end
5'd4 : begin
RxTemp[3] = Rx;//bit2
RxState <= 5'd5;
end
5'd5 : begin
RxTemp[4] = Rx;//bit3
RxState <= 5'd6;
end
5'd6 : begin
RxTemp[5] = Rx;//bit4
RxState <= 5'd7;
end
5'd7 : begin
RxTemp[6] = Rx;//bit5
RxState <= 5'd8;
end
5'd8 : begin
RxTemp[7] = Rx;//bit6
RxState <= 5'd9;
end
5'd9 : begin
RxTemp[8] = Rx;//bit7
RxState <= 5'd10;
end
5'd10 : begin
RxTemp[9] = Rx;//校验位
RxState <= 5'd11;
end
5'd11 : begin
RxTemp[10] = Rx;//结束位,接收完成
EN_RXCLK <= 1'b0;//停止接收时钟
RxState <= 5'd0;//接收进入空闲状态
if(!RxTemp[0] && RxTemp[10]) begin//有正确的起始和停止位
RxDATA <= RxTemp[8 : 1];//保存接收的数据
NewRxData = 1'b1;//新数据标志置位
end
end
endcase
end //end else if
else
NewRxData = 1'b0;//去除新数据标志
endmodule
串口资料大家网上找找,我也是个新手,欢迎交流.