FPGAUART实验.docx
《FPGAUART实验.docx》由会员分享,可在线阅读,更多相关《FPGAUART实验.docx(15页珍藏版)》请在冰豆网上搜索。
![FPGAUART实验.docx](https://file1.bdocx.com/fileroot1/2023-1/27/158d9187-7603-4b4b-9994-9f64c08e9ffc/158d9187-7603-4b4b-9994-9f64c08e9ffc1.gif)
FPGAUART实验
FPGA—UART实验
串口通信设计
一、实验目的
1、熟练使用ISE设计工具;
2、理解串口传输协议。
理解采用“自顶向下”设计思路,分解模块的方法;
3、在ISE使用VerilogHDL设计串口接收模块,完成仿真、下载。
二、实验原理
1、串口传输协议概述
设计完成异步串口通信通用异步收发是一种典型的异步串口通信,简称UART。
串口通信时序如图1所示。
图1通用异步收发时序图
由图1可以看出,在没有数据传送时,通信线会一直处于高电平,即逻辑1状态;当有数据传送时,数据帧以起始位开始,以停止位结束。
起始位为低电平,即逻辑0状态;停止位为高电平,即逻辑1状态,其持续时间可选为1位、1.5位或2位(本次设计选择持续时间1位)。
接收端在接收到停止位后,知道一帧数据已经传完,转为等待数据接收状态;只要再接收到0状态,即为新一帧数据的起始状态。
数据帧的数据位低位(LSB)在前,高位(MSB)在后,根据不同的编码规则,数据位可能为5位、6位、7位或者8位(本次设计数据位定位8位)。
校验位也可根据需要选择奇校验、偶校验或者不要校验(本次设计不要校验位)。
2、串口时序分析
串口通讯常用“波特率”表述串口传输速率,常用的参数有9600bps和115200bps等。
在硬件传输角度看,波特率表征了传输一位数据所需要的时间。
例如:
波特率是9600bps,传输一位数据的时间是1/9600=0.0001041666666667s;
本次FPGA系统时钟是40MHZ,则一位数据传输时间相当于(1/9600)/(1/40M)=4167个40MHZ时钟周期。
设一帧数据位数=1(开始位)+8(数据位)+1(校验位)+1(结束位)=11位,所以传输一帧数据的时间是11*1/9600=0.0011458333333333333333333333s。
为了稳定采集串口数据帧的数据,需要在每位数据的“中间时刻”采样,由此,需要在每位数据开始时刻对时钟进行计数,若系统时钟是40MHZ,则在计数至4167/2=2084时采样此时刻的数值。
3、数据显示
PC通过串口发送的数据应该在下载板上有所显示,以此来确定发送成功与否。
所以实验中用到8个数码管以二进制的方式来显示通过串口助手发送的两个十六进制的数据。
4、本次实验的设计一共有20个端口
输入信号:
CLK——系统时钟;RSTn——复位信号;Rx_EN_Sig——通信使能信号。
Rx_Pin_In——串口数据输入。
输出信号:
SEG[7:
0]——数码管段选信号;CON[7:
0]——数码管位选信号。
三、实验步骤
1、整个系统主要设计的模块是:
帧监测开始模块(detect_module)、数据位中心定位模块(Rx_Rbps_module)、数据装载模块(Rx_Control_module)和数码管显示模块(display_module)。
接下来进行进行分模块设计。
2、帧监测开始模块(detect_module)
检测串行输入数据RX_Pin_In的值,判断是否开始传送一帧的数据。
并将判断结果H2L_Sig输送给数据装载模块(Rx_Control_module)。
模块结构图如图2:
图2帧监测开始模块
3、数据位中心定位模块(Rx_Rbps_module)
为了稳定采集串口数据帧的数据,需要在每位数据的“中间时刻”采样,所以需要一个该模块用来检测每一位数据的持续时间的“中间时刻”。
该模块原理为:
当接收到数据装载模块传来的一个“当前数据有效(Count_Sig==1)”的信号时开始计数,一直计数到该数据持续时间的一半时便发送一个确认信号(BPS_CLK==1)给数据装载模块,提示其开始进行数据采集。
模块结构图如图3:
图3数据位中心定位模块
4、数据装载模块(Rx_Control_module)
该模块用来接收自串口发送来的数据,并进行判断,将8位数据装载到寄存器中。
并且在每接收完一帧数据时给显示模块一个确认信号(RX_Done_Sig=1),让数码管更新显示。
模块结构图如图4:
图4数据装载模块
5、数码管显示模块(display_module)
在接收到来自数据装载模块发送的数据接收完毕的信号之后,将接收到的数据按位显示到每一位数码管上。
模块结构图如图5:
图5数码管显示模块
6、顶层模块(top)
对各个模块进行仿真验证,确认无误后。
例化各个模块并将它们连接到一起。
则系统结构图如图6:
图6系统结构图
7、根据板子锁定引脚,并生成下载文件。
CLK为系统40M时钟即是P82脚;RSTn复位信号选择拨码开关1,即P20脚;Rx_EN_Sig使能信号选择拨码开关2,即P26脚;Rx_Pin_In为串口0的RX端,即P14;CON[0:
7]数码管位选信号锁定对应的数码管共阳端引脚,LED[0:
7]即选择对应的数码管脚锁定即可。
四、实验结果
1、数据装载模块(Rx_Control_module)与数据位中心定位模块(Rx_Rbps_module)连接仿真测试
激励文件的编写应该首先产生40M的CLK时钟信号,然后复位信号无效,使能信号有效,帧开始信号H2L_Sig有效。
然后再每104166个时钟给Rx_Pin_In一个值,该激励文件给定的值为:
10010101。
图7数据装载波形图
由图可知,模块实现了依次将数据10010101装载到寄存器Rx_Data[7:
0]里。
2、数码管显示模块(display_module)
激励文件的编写应该为首先产生一个40M的CLK时钟信号,然后复位信号无效,帧数据接收完毕即Rx_Done_Sig=1。
给一个Rx_Data[7:
0]赋一个值,看是否显示正确,即通过CON[7:
0]和SEG[7:
0]联立观察。
图8数码管显示
由图形可知,给Rx_Data[7:
0]赋值为11111101。
在看CON[7:
0]和SEG[7:
0],数码管1显示的为1,数码管2显示的为0,数码管3~数码管7都显示的为1,故模块设计无误。
3、下载到实验板上面后的结果
将拨动开关0和1都拨动到上方,即为高电平时。
数码管初始显示为0。
连接好串口线,打开串口助手,打开串口以十六进制的方式发送两位数据如11。
此时下载板上的数码管显示为00010001,即是十六进制的数据11对应的二进制下的数据。
图9数码管显示
4、VGA下载实验效果
下载后,将板子的VGA线连接显示器上面。
显示器显示如图10所示,拨动拨码开关0,显示器显示另一张图形如图11所示。
图10VGA显示
图11VGA显示
五、思考题
1、简述帧开始监测模块(detect_module),数据位中心定位模块(rx_bps_module),数据装载模块(rx_control_module)的功能各是什么?
这三个模块是如何配合实现了串口数据的接收?
答:
帧开始检测模块的功能是检测该数据传送的位数;数据位中心定位模块的功能是从数据的稳定状态提取数据;数据装载模块的功能是将取得的完整的数据传输给FPGA显示。
2、如果串口比特率改为115200bps,代码应该做怎样的修改?
modulerx_bps_module(CLK,RSTn,Count_Sig,BPS_CLK);
inputCLK;
inputRSTn;
inputCount_Sig;
outputBPS_CLK;
reg[11:
0]Count_BPS;
always@(posedgeCLKornegedgeRSTn)
if(!
RSTn)
Count_BPS<=8'd0;
elseif(Count_BPS==8'd173)
Count_BPS<=8'd0;
elseif(Count_Sig)
Count_BPS<=Count_BPS+1'b1;
else
Count_BPS<=8'd0;
assignBPS_CLK=(Count_BPS==12'd1041)?
1'b1:
1'b0;
endmodule
3、如果要设计串口数据发送模块,该如何设计,简要写出设计系统任务书(包括设计目标,功能模块划分,子模块功能描述等)
答:
串口数据发送模块设计目的:
通过在FPGA板上输入数据,然后在电脑的串口端显示数据;功能模块划分:
按键(作为数据的输入),数码管(显示当前数据用于比较电脑端接受的数据是否正确),状态接受(处于某个状态时数据的状态),分频模块。
六、代码
1、顶层模块代码:
`timescale1ns/1ps
moduletop(CLK,RSTn,Rx_EN_Sig,Rx_Pin_In,SEG,CON);
inputCLK;
inputRSTn;
inputRx_EN_Sig;
inputRx_Pin_In;
output[7:
0]SEG;
output[7:
0]CON;
wireH2L_Sig;
wireCount_Sig;
wireBPS_CLK;
wireRx_Done_Sig;
wire[7:
0]Rx_Data;
detect_moduledetect(.CLK(CLK),.RSTn(RSTn),
.Rx_Pin_In(Rx_Pin_In),.H2L_Sig(H2L_Sig));
Rx_Control_moduleRx_Control(.CLK(CLK),.RSTn(RSTn)
.H2L_Sig(H2L_Sig),.Rx_Pin_In(Rx_Pin_In),.BPS_CLK(BPS_CLK),
.Rx_EN_Sig(Rx_EN_Sig),.Count_Sig(Count_Sig),
.Rx_Data(Rx_Data),.Rx_Done_Sig(Rx_Done_Sig));
Rx_bps_moduleRx_bps(.CLK(CLK),.RSTn(RSTn),
.Count_Sig(Count_Sig),.BPS_CLK(BPS_CLK));
display_moduledisplay(.CLK(CLK),.RSTn(RSTn),
.Rx_Done_Sig(Rx_Done_Sig),.Rx_Data(Rx_Data),.SEG(SEG),.CON(CON));
endmodule
2、帧监测开始模块(detect_module):
`timescale1ns/1ps
//帧开始监测模块(detect_module)
moduledetect_module(CLK,RSTn,Rx_Pin_In,H2L_Sig);
inputCLK;
inputRSTn;//复位信号
inputRx_Pin_In;//串行输入数据RX_Pin_In
outputH2L_Sig;
regH2L_F1;
regH2L_F2;
always@(posedgeCLKornegedgeRSTn)
if(!
RSTn)
begin
H2L_F1<=1'b1;
H2L_F2<=1'b1;
end
else
begin
H2L_F1<=Rx_Pin_In;
H2L_F2<=H2L_F1;
end
assignH2L_Sig=H2L_F2&!
H2L_F1;
endmodule
3、数据位中心定位模块(Rx_Rbps_module):
``timescale1ns/1ps
//数据位中心定位模块(Rx_Rbps_module)
moduleRx_bps_module(CLK,RSTn,Count_Sig,BPS_CLK);
inputCLK;
inputRSTn;//复位信号RSTn,当RSTn=0,系统复位
inputCount_Sig;//串口数据帧开始确认信号:
Count_Sig,当Count_Sig=1,
//表示串口输入帧开始时刻,持续一个系统时钟周期
outputBPS_CLK;//BPS_CLK,当计数至每一位的中间位置,BPS_CLK=1,
//提示信号采集时间到,否则不进行信号采集
reg[12:
0]Count_BPS;
parameter[12:
0]BPS=13'd4167;//2083*2(40Mhz)
always@(posedgeCLKornegedgeRSTn)
if(!
RSTn)
Count_BPS<=13'd0;//计数
elseif(Count_BPS==BPS)
Count_BPS<=13'd0;
elseif(Count_Sig)
Count_BPS<=Count_BPS+1'b1;
else
Count_BPS<=13'd0;
assignBPS_CLK=(Count_BPS==BPS/2)?
1'b1:
1'b0;
endmodule
4、数据装载模块(Rx_Control_module):
`timescale1ns/1ps
//数据装载模块(Rx_Control_module)
moduleRx_Control_module(
CLK,RSTn,
H2L_Sig,Rx_Pin_In,BPS_CLK,Rx_EN_Sig,
Count_Sig,Rx_Data,Rx_Done_Sig
);
inputCLK;
inputRSTn;//复位信号RSTn,当RSTn=0时,系统复位
inputH2L_Sig;//帧开始信号H2L_Sig,当H2L_Sig=1,表示一帧信号开始
inputRx_EN_Sig;//串口接收使能信号RX_En_Sig,
//当RX_En_Sig=1,系统正常工作。
反正不接收数据
inputRx_Pin_In;//串口数据输入信号:
RX_Pin_In
inputBPS_CLK;//位中心定位信号:
BPS_CLK
outputCount_Sig;//数据位有效信号Count_Sig,
//当Count_Sig=1,表示有效位传输
output[7:
0]Rx_Data;//装载好的串口数据:
RX_Data,位宽为8bits
outputRx_Done_Sig;//串口数据接收结束信号:
RX_Done_Sig,
//当RX_Done_Sig=1表示一帧串口数据接收完毕
reg[3:
0]i=4'b0;
reg[7:
0]rData=8'd0;
regisCount=1'b0;
regisDone=1'b0;
always@(posedgeCLKornegedgeRSTn)
if(!
RSTn)
begin
i<=4'd0;
rData<=8'd0;
isCount<=1'b0;
isDone<=1'b0;
end
elseif(Rx_EN_Sig)
case(i)
4'd0:
if(H2L_Sig)begini<=i+1'b1;isCount<=1'b1;end
4'd1:
if(BPS_CLK)begini<=i+1'b1;end
4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8,4'd9:
if(BPS_CLK)begini<=i+1'b1;rData[i-2]<=Rx_Pin_In;end
4'd10:
if(BPS_CLK)begini<=i+1'b1;end
4'd11:
if(BPS_CLK)begini<=i+1'b1;end
4'd12:
beginI<=i+1'b1;isDone<=1'b1;isCount<=1'b0;end
4'd13:
begini<=1'b0;isDone<=1'b0;end
endcase
assignCount_Sig=isCount;
assignRx_Data=rData;
assignRx_Done_Sig=isDone;
endmodule
5、数码管显示模块(display_module):
`timescale1ns/1ps
//显示模块(display_module)
moduledisplay_module(CLK,RSTn,Rx_Done_Sig,Rx_Data,SEG,CON);
inputCLK;
inputRSTn;
inputRx_Done_Sig;//串口数据接收结束信号:
RX_Done_Sig,
//当RX_Done_Sig=1表示一帧串口数据接收完毕
input[7:
0]Rx_Data;//装载好的串口数据:
RX_Data,位宽为8bits
output[7:
0]SEG;
output[7:
0]CON;
reg[7:
0]SEG;
reg[7:
0]CON;
reg[23:
0]CNT;
reg[2:
0]dig;
always@(posedgeCLKornegedgeRSTn)
if(!
RSTn)begin
dig<=3'b000;
CNT<=24'b0;
end
elsebegin
if(CNT==24'd25000)
begin
CNT<=24'b0;
if(dig==3'd7)
dig<=3'd0;
else
dig<=dig+1'b1;
end
else
CNT<=CNT+1'b1;
end
reg[7:
0]Data=8'b00000000;//数据寄存器
//Rx_Done_Sig信号上升沿来到时将串口接收到的数据送给Data
always@(posedgeRx_Done_Sig)
Data<=Rx_Data;
always@(posedgeCLKornegedgeRSTn)
if(!
RSTn)begin
SEG<=8'b1000000;
CON<=8'b11111111;
end
else
case(dig)
3'd0:
beginSEG<=display(Data[0]);CON<=8'b1111_1110;end
3'd1:
beginSEG<=display(Data[1]);CON<=8'b1111_1101;end
3'd2:
beginSEG<=display(Data[2]);CON<=8'b1111_1011;end
3'd3:
beginSEG<=display(Data[3]);CON<=8'b1111_0111;end
3'd4:
beginSEG<=display(Data[4]);CON<=8'b1110_1111;end
3'd5:
beginSEG<=display(Data[5]);CON<=8'b1101_1111;end
3'd6:
beginSEG<=display(Data[6]);CON<=8'b1011_1111;end
3'd7:
beginSEG<=display(Data[7]);CON<=8'b0111_1111;end
default:
beginSEG<=display(Rx_Data[1]);CON<=8'b1111_1110;end
endcase
function[7:
0]display;
inputData_In;
case(Data_In)
1'b0:
display=8'b11000000;
1'b1:
display=8'b11111001;
default:
display=8'b10000000;
endcase
endfunction
endmodule
6、引脚锁定(display_module):
netCLKloc=p82;
netRSTnloc=p20;
netRx_EN_Sigloc=p26;
netRx_Pin_Inloc=p14;
netSEG[0]loc=p102;
netSEG[1]loc=p99;
netSEG[2]loc=p107;
netSEG[3]loc=p109;
netSEG[4]loc=p112;
netSEG[5]loc=p100;
netSEG[6]loc=p106;
netSEG[7]loc=p108;
netCON[0]loc=p127;
netCON[1]loc=p128;
netCON[2]loc=p129;
netCON[3]loc=p132;
netCON[4]loc=p120;
netCON[5]loc=p122;
netCON[6]loc=p123;
netCON[7]loc=p126;