Verilog之UART源程序.docx
《Verilog之UART源程序.docx》由会员分享,可在线阅读,更多相关《Verilog之UART源程序.docx(17页珍藏版)》请在冰点文库上搜索。
Verilog之UART源程序
//2011-12-08zheng
/*****************程序说明**************************************************
功能:
UART串口通讯实信实验
描述:
本程序共四个模块
模块1:
接收数据的波特率发生模块,接收模块在接收到下降沿时,通过标志位启
动该模块的波特率计数器,并在计数中返回一个采样标志位给接受模块,
通知接收模块采样;
----------------------------------------------------------------------
模块2:
数据接收模块,该模块一旦监测到数据输入端有下降沿,就立即启动波
特率(标志位置1),并使能接收标志位rx_int,接收开始;
----------------------------------------------------------------------
模块3:
发送数据的波特率发生模块,发送模块在监测到接收标志位rx_int产生下
降沿时,通过标志位启动该模块的的波特率计数器,并在计数中返回一
个发送标志位给发送模块,通知发送模块发送数据;
----------------------------------------------------------------------
模块4:
数据发送模块,该模块一旦监测到接收标志位rx_int有下降沿,就立即启
动波特率(标志位置1),并使能接收标志位tx_en,发送开始;
----------------------------------------------------------------------
引脚:
clk:
50Mhz时钟输入,Pin23;
rst_n:
复位,低电平有效,Pin144;
receive:
数据接收端,Pin160,需要跳线帽
send:
数据发送端,Pin163,需要跳线帽
******************************************************************************/
modulelesson5(clk,rst_n,receive,send);
inputclk;
inputrst_n;
inputreceive;
outputsend;
wire[7:
0]data;//连接接收模块与发送模块,以便数据传输
wirebaud_start1,baud_start2;
//baud_start1:
接收模块的波特率启动标志位;
//baud_start2:
发送模块的波特率启动标志位;
wiremid_flag1,mid_flag2;
//mid_flag1:
接收数据标志位,由接收波特率发生模块发来;
//mid_flag2:
发送数据标志位,由发送波特率发生模块发来;
wireinterrupt;
//接收完数据的标志位,同时也是发送数据的启示标志位;
/********************************************************************
本程序采用模块化设计,即模块例化,分为4个模块,其中两个
波特率发生模块共用;
注意:
例化的格式很重要~!
!
********************************************************************/
baud_selectbaud_receive(
.clk(clk),
.rst_n(rst_n),
.baud_start(baud_start1),
.mid_flag(mid_flag1)
);
//模块1:
接收数据的波特率发生模块;
//------------------------------------------------------------------
receive_uartrecsive_232(
.clk(clk),
.rst_n(rst_n),
.rs232_rx(receive),
.baud_start(baud_start1),
.mid_flag(mid_flag1),
.rx_int(interrupt),
.rx_data(data)
);
//模块2:
数据接收模块;
//------------------------------------------------------------------
baud_selectbaud_send(
.clk(clk),
.rst_n(rst_n),
.baud_start(baud_start2),
.mid_flag(mid_flag2)
);
//模块3:
发送数据的波特率发生模块;
//------------------------------------------------------------------
send_uartsend_232(
.clk(clk),
.rst_n(rst_n),
.rs232_tx(send),
.baud_start(baud_start2),
.mid_flag(mid_flag2),
.tx_int(interrupt),
.tx_data(data)
);
//模块4:
数据发送模块;
//------------------------------------------------------------------
endmodule
//**************************over******************************//
//2011-12-08zheng
/*****************程序说明**************************************************
功能:
波特率发生模块
描述:
在收到来自接收模块或者发送模块的启动信号baud_start后,启动波特率计数器,
产生9600的比特率
端口:
clk:
50Mhz时钟输入,Pin23;
rst_n:
复位,低电平有效,Pin144;
mid_flag:
接收/发送数据标志位,接收或者发送数据位的中间采样点;
baud_start:
波特率启动标志位;
波特率计算:
eg:
9600bps=9600bit/s
9600bit/s=9600bit/1000000us,
那么传输每bit要1000000/9600us,而一个时钟周期位0.02us,
由此可计算出1000000/9600us有多少个0.02us,即多少个时钟,
计算得:
传输每bit要5208个时钟周期,计数从0到5207;
*****************************************************************************/
modulebaud_select(clk,rst_n,baud_start,mid_flag);
inputclk;
inputrst_n;
inputbaud_start;
outputmid_flag;
//parameterbps9600=5207,//波特率为9600bps
//bps19200=2603,//波特率为19200bps
//bps38400=1301,//波特率为38400bps
//bps57600=867,//波特率为57600bps
//bps115200=433;//波特率为115200bps
//
//parameterbps9600_2=2603,
//bps19200_2=1301,
//bps38400_2=650,
//bps57600_2=433,
//bps115200_2=216;
`defineBPS_PARA5207
`defineBPS_PARA_22603
//***************************************************************************
//波特率分频计数器,当启动信号标志位为1时计数开始
reg[12:
0]cont;
always@(posedgeclkornegedgerst_n)
if(!
rst_n)cont<=13'd0;
elseif((cont==`BPS_PARA)||!
baud_start)cont<=13'b0_0000_0000_0000;
elsecont<=cont+1'b1;
//***************************************************************************
//发送一个位需要5028个时钟周期,在一个数据位中间时刻,即计数到2603时,接收或发送
//标志位置1,并传输给接收模块或者发送模块,以发送或接收数据;
regmid_flag_1;
always@(posedgeclkornegedgerst_n)
if(!
rst_n)mid_flag_1<=1'b0;
elseif((cont==`BPS_PARA_2))mid_flag_1<=1'b1;
elsemid_flag_1<=1'b0;
assignmid_flag=mid_flag_1;
//***************************************************************************
endmodule
//*****************************over***************************************//
//2011-12-08zheng
/*****************程序说明**************************************************
功能:
接收数据模块
描述:
在接收波特率的驱动下,该模块将从数据输入端接收的数据存放在寄存器
rx_data[7:
0]里,并输出给发送模块
端口:
clk:
50Mhz时钟输入,Pin23;
rst_n:
复位,低电平有效,Pin144;
rs232_rx:
与顶层模块的输入引脚receive对应;
mid_flag:
由接收波特率发生模块发来,1--标志采样,0--不采样;
与顶层mid_flag1对应;
baud_start:
接收波特率启动标志位,与顶层mbaud_start1对应;
rx_data[7:
0]:
将接收的数据输出,与顶层的data[7:
0]对应;
rx_int:
接收数据标志位:
在接收数据时一直保持1,接收完或者
接收数据时保持0,对应顶层interrupt;
UART时序:
——___********————
……0********1……
0:
启示位0,*:
8位数据,1:
结束位1
*****************************************************************************/
modulereceive_uart(clk,rst_n,rs232_rx,mid_flag,baud_start,rx_data,rx_int);
inputclk;
inputrst_n;
inputrs232_rx;
inputmid_flag;
outputbaud_start;
output[7:
0]rx_data;
outputrx_int;
//*************************************************************************
//利用按键消抖原理,先后采样接收端的的电平进行对比,以判断是否有下降沿;
regrs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
rs232_rx0<=1'b0;
rs232_rx1<=1'b0;
rs232_rx2<=1'b0;
rs232_rx3<=1'b0;
end
elsebegin
rs232_rx0<=rs232_rx;
rs232_rx1<=rs232_rx0;
rs232_rx2<=rs232_rx1;
rs232_rx3<=rs232_rx2;
end
end
wireneg_rs232_rx=rs232_rx3&rs232_rx2&~rs232_rx1&~rs232_rx0;
//**************************************************************************
//如果有下降沿来临,即neg_rs232_rx为1时,波特率发生标志位置1,接收数据标志置1;
//一旦数据接收结束,即num为12时,关断波特率发生器,接收数据标志清零;
regbaud_start_r,rx_int_r;
reg[3:
0]num;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
baud_start_r<=1'b0;
rx_int_r<=1'b0;
end
elseif(neg_rs232_rx)
begin
baud_start_r<=1'b1;
rx_int_r<=1'b1;
end
elseif(num==4'd12)
begin
baud_start_r<=1'b0;
rx_int_r<=1'b0;
end;
end
assignbaud_start=baud_start_r;
assignrx_int=rx_int_r;
//**************************************************************************
//num:
接收位数标志;
//buffer:
接收数据缓冲器;
//data:
数据寄存器;
//波特率发生模块发来采样标志信号(mid_flag为1)后就进行采样;
reg[7:
0]data;
reg[7:
0]buffer;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
data<=8'd0;
buffer<=8'd0;
num<=4'd0;
end
elseif(rx_int_r)
begin
if(mid_flag)
begin
num<=num+1'b1;
//注意:
此句与下面case语句是并行的,即case中的num是自加1之前的值;
case(num)
//num=0时为起始位,不存储
4'd1:
buffer[0]<=rs232_rx;
4'd2:
buffer[1]<=rs232_rx;
4'd3:
buffer[2]<=rs232_rx;
4'd4:
buffer[3]<=rs232_rx;
4'd5:
buffer[4]<=rs232_rx;
4'd6:
buffer[5]<=rs232_rx;
4'd7:
buffer[6]<=rs232_rx;
4'd8:
buffer[7]<=rs232_rx;
//num=9时为结束位,不存储
default:
;
endcase
end
elseif(num==4'd12)
begin
num<=4'd0;
data<=buffer;
end
end
end
assignrx_data=data;
//**************************************************************************
endmodule
//******************************over************************************//
//2011-12-08zheng
/*****************程序说明**************************************************
功能:
发送数据模块
描述:
在发送波特率的驱动下,该模块将从接收模块传输来的数据发送出去
端口:
clk:
50Mhz时钟输入,Pin23;
rst_n:
复位,低电平有效,Pin144;
rs232_tx:
与顶层模块的输入引脚send对应;
mid_flag:
由发送波特率发生模块发来,1--发送,0--不发送;
与顶层mid_flag2对应;
baud_start:
发送波特率启动标志位,与顶层baud_start2对应;
tx_data[7:
0]:
准备发送的数据,与顶层的data[7:
0]对应;
tx_int:
接收数据标志位:
在接收数据时一直保持1,接收完或者
接收数据时保持0,对应顶层interrupt;
UART时序:
——___********————
……0********1……
0:
启示位0,*:
8位数据,1:
结束位1
*****************************************************************************/
modulesend_uart(clk,rst_n,rs232_tx,mid_flag,tx_data,tx_int,baud_start);
inputclk;
inputrst_n;
inputmid_flag;
outputbaud_start;
outputrs232_tx;
input[7:
0]tx_data;
inputtx_int;
//****************************************************************************
//利用按键消抖原理,先后采样接收数据标志位tx_int的电平,以判断是否有下降沿产生
regint0,int1,int2;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
int0<=1'b0;
int1<=1'b0;
int2<=1'b0;
end
elsebegin
int0<=tx_int;
int1<=int0;
int2<=int1;
end
end
wireint_lock=~int1&int2;
//****************************************************************************
//如果tx_int有下降沿产生,即int_lock为1,就启动波特率发生器,同时使能发送数据,
//并将接收模块发来的数据送入发送数据缓冲器;
//如果发送数据结束,即num=11时,波特率关断,发送使能清零,发送数据缓冲器清零;
regbaud_start_t,send_en;
reg[7:
0]data;
reg[3:
0]num;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
baud_start_t<=1'b0;
send_en<=1'b0;
data<=8'd0;
end
elseif(int_lock)
begin
baud_start_t<=1'b1;
send_en<=1'b1;
data<=tx_data;
end
elseif(num==4'd11)
begin
baud_start_t<=1'b0;
send_en<=1'b0;
data<=8'd0;
end
end
assignbaud_start=baud_start_t;
//****************************************************************************
//rs232_tx_r:
数据输出寄存器;
//num:
发送数据位数;
regrs232_tx_r;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
num<=1'b0;
rs232_tx_r<=1'b0;
end
elseif(send_en)
begin
if(mid_flag)
begin
num<=num+1'b1;
case(num)
4'd0:
rs232_tx_r<=1'b0;//起始信号0;
4'd1:
rs232_tx_r<=data[0];
4'd2:
rs232_tx_r<=data[1];
4'd3:
rs232_tx_r