基于FPGA的通用异步收发器设计
———————————————————————————————— 作者:
———————————————————————————————— 日期:
基于FPGA的通用异步收发器设计
作者: 学号:
指导教师
摘要:文章简要介绍了UART的基本功能,采用Verilog HDL语言作为硬件功能的描述,运用模块化设计方法设计了通用异步收发器的发送模块、接收模块和波特率发生器。实现了基于FPGA的UART基本功能设计,并给出了UART的软件编程实例。
关键字:Verilog HDL;FPGA;UART;
Abstract: this paper briefly introduces the basic function of UART, the Verilog HDL language as a description of the hardware function, using modular design method to design the general asynchronous transceiver module, receive send the module and baud rate generator. Realized the basic function of UART which based on FPGA , and gives the UART software programming examples。
Key word: Verilog HDL; FPGA; UART;
1。引言
串行通信要求的传输线少,可靠性高,传输距离远,被广泛应用于计算机和外设的数据交换。通常都由通用异步收发器(UART)来实现串口通信的功能。在实际应用中,往往只需要UART的几个主要功能,专用的接口芯片会造成资源浪费和成本提高。随着FPGA/CPLD的飞速发展与其在现代电子设计中的广泛应用,FPGA/CPLD功能强大、开发过程投资小、周期短、可反复编程、保密性好等特点也越来越明显。因此可以充分利用其资源,在芯片上集成UART功能模块,从而简化了电路、缩小了体积、提高了可靠性,而且设计时的灵活性更大,周期更短.鉴于此本文提出了一种采用FPGA实现UART功能的方法,可以有效地解决上述问题。
———————————————————————————————— 作者:
———————————————————————————————— 日期:
基于FPGA的通用异步收发器设计
作者: 学号:
指导教师
摘要:文章简要介绍了UART的基本功能,采用Verilog HDL语言作为硬件功能的描述,运用模块化设计方法设计了通用异步收发器的发送模块、接收模块和波特率发生器。实现了基于FPGA的UART基本功能设计,并给出了UART的软件编程实例。
关键字:Verilog HDL;FPGA;UART;
Abstract: this paper briefly introduces the basic function of UART, the Verilog HDL language as a description of the hardware function, using modular design method to design the general asynchronous transceiver module, receive send the module and baud rate generator. Realized the basic function of UART which based on FPGA , and gives the UART software programming examples。
Key word: Verilog HDL; FPGA; UART;
1。引言
串行通信要求的传输线少,可靠性高,传输距离远,被广泛应用于计算机和外设的数据交换。通常都由通用异步收发器(UART)来实现串口通信的功能。在实际应用中,往往只需要UART的几个主要功能,专用的接口芯片会造成资源浪费和成本提高。随着FPGA/CPLD的飞速发展与其在现代电子设计中的广泛应用,FPGA/CPLD功能强大、开发过程投资小、周期短、可反复编程、保密性好等特点也越来越明显。因此可以充分利用其资源,在芯片上集成UART功能模块,从而简化了电路、缩小了体积、提高了可靠性,而且设计时的灵活性更大,周期更短.鉴于此本文提出了一种采用FPGA实现UART功能的方法,可以有效地解决上述问题。
2. UART的工作原理
UART(Universal Asynchronous Receiver Transmitter,通用异步收发器)是广泛使用的异步串行数据传输协议。在串行通信中,数据以字节为单位的字节帧进行传送。发送端和接收端必须按照相同的字节帧格式和波特率进行通信.UART控制器所传输的一帧串行数据包括1位起始位(低电平)、5~8位数据位、1位校验位(可选)和停止位(可为1,1.5,2位)。起始位是字节帧的开始,使数据线处于逻辑0状态,用于向接收端表明开始发送数据帧,起到使发送和接收设备实现同步的功能。停止位是字节帧的终止,使数据线处于逻辑1状态。用于向接收端表明数据帧发送完毕。波特率采用标准速率9 600 b/s。数据在传输时,低位在前,高位在后。接收端检测并确认起始位后,接收数据位。停止位接收完毕后,向CPU发出中断信号,同时将数据发送到计算机的8位数据总线上;发送数据时,先由CPU设置波特率,然后将8位并行数据加上起始位和停止位发送给外设。停止位发送完毕后,向CPU发出中断信号.在数据发送和接收过程中,CPU可以通过控制信号来读取UART的工作状态,以便进行实时处理。图(1)为UART的传输结构图。文档为个人收集整理,来源于网络文档为个人收集整理,来源于网络
图(1)
3. UART的模块化设计
3。1系统总体结构
在大规模电路的设计中,广泛采用层次化、结构化的设计方法。它将一个完整的硬件设计任务从系统级开始,划分为若干个可操作的模块,编制出相应的模型并进行仿真验证,最后在系统级上进行组合。这样在提高设计效率的同时又提高了设计质量,是目前复杂数字系统实现的主要手段,也是本文设计思想的基础。按照系统功能进行划分,UART主要由波特率发生器、接收模块和发送模块三大部分组成。下面分别讨论发送模块、接收模块和波特率发生器模块的具体实现过程。
module uart_test(clock,key,rdata,wen,sdata,seg,seg_dig);
input clock; //系统时钟(48MHz)
input[2:0] key; //按键输入(KEY1~KEY3)
input[7:0]rdata; //接收到的数据
output wen; //发送数据使能
output[7:0]sdata; //要发送的数据
output[7:0]seg; //数码管段码输出
output[7:0]seg_dig; //数码管位码输出
//I/O寄存器
reg[7:0]sdata;
reg[7:0]seg;
reg[7:0]seg_dig;
//内部寄存器
reg[16:0]count; //时钟分频计数器
reg[2:0]dout1,dout2,dout3,buff; //消抖寄存器
reg[1:0] cnt; //数码管扫描计数器
reg[3:0]disp_dat; //数码管扫描显存
reg div_clk; //分频时钟
wire[2:0]key_edge; //按键消抖输出
//时钟分频部分
always @(posedge clock)
begin
if (count < 17’d120000)
begin
count <= count + 1’b1;
div_clk 〈= 1’b0;
end
else
begin
count <= 17’d0;
div_clk 〈= 1’b1;
end
end
//按键消抖部分
always @(posedge clock)
begin
if(div_clk)
begin
dout1 <= key;
dout2 <= dout1;
dout3 <= dout2;
end
end
//按键边沿检测部分
always @(posedge clock)
begin
buff 〈= dout1 | dout2 | dout3;
end
assign key_edge = ~(dout1 | dout2 | dout3) & buff;
//2位16进制数输出部分
always @(posedge clock) //按键1
begin
if(key_edge[0])
sdata[7:4] <= sdata[7:4] + 1’b1;
end
always @(posedge clock) //按键2
begin
if(key_edge[1])
sdata[3:0] 〈= sdata[3:0] + 1’b1;
end
assign wen = key_edge[2]; //按键3
//数码管扫描显示部分
always @(posedge clock) //定义上升沿触发进程
begin
if(div_clk)
cnt <= cnt + 1’b1;
end
always @(posedge clock)
begin
if(div_clk)
begin
case(cnt) //选择扫描显示数据
2’d0:disp_dat = sdata[7:4]; //第一个数码管
2’d1:disp_dat = sdata[3:0]; //第二个数码管
2’d2:disp_dat = rdata[7:4]; //第七个数码管
2’d3:disp_dat = rdata[3:0]; //第八个数码管
endcase
case(cnt) //选择数码管显示位
2’d0:seg_dig = 8’b01111111; //选择第一个数码管显示
2’d1:seg_dig = 8’b10111111; //选择第二个数码管显示
2’d2:seg_dig = 8’b11111101; //选择第七个数码管显示
2’d3:seg_dig = 8’b11111110; //选择第八个数码管显示
endcase
end
end
always @(disp_dat)
begin
case(disp_dat) //七段译码
4’h0:seg = 8’hc0; //显示0
4’h1:seg = 8’hf9; //显示1
4’h2:seg = 8’ha4; //显示2
4’h3:seg = 8’hb0; //显示3
4’h4:seg = 8’h99; //显示4
4’h5:seg = 8’h92; //显示5
4’h6:seg = 8’h82; //显示6
4’h7:seg = 8’hf8; //显示7
4’h8:seg = 8’h80; //显示8
4’h9:seg = 8’h90; //显示9
4’ha:seg = 8’h88; //显示a
4’hb:seg = 8’h83; //显示b
4’hc:seg = 8’hc6; //显示c
4’hd:seg = 8’ha1; //显示d
4’he:seg = 8’h86; //显示e
4’hf:seg = 8’h8e; //显示f
endcase
end
endmodule
3。2发送模块
发送模块主要实现对并行数据的缓存、并串转换,并把串行数据按照既定数据帧格式进行输出。数据发送的思想是,当启动字节发送时,通过TxD先发起始位,然后发数据位和奇偶数效验位,最后再发停止位,发送过程由发送状态机控制,每次中断只发送1个位,经过若干个定时中断完成1个字节帧的发送。【1】发送模块的代码如下:
module send(clk,clkout,Datain,TXD,TI,WR);
input WR;
input [7:0]Datain; //发送的一字节数据
input clk;
output clkout;
output TXD,TI; //串行数据,发送中断
reg[9:0]Datainbuf,Datainbuf2; //发送数据缓存
reg WR_ctr,TI,txd_reg;
reg [3:0]bincnt; //发送数据计数器
reg [15:0] cnt;
wire clk_equ;
parameter cout = 5000;
/*************波特率发生进程****************************/
always@(posedge clk)
begin
if(clk_equ)
cnt = 16’d0;
else
cnt=cnt+1’b1;
end
assign clk_equ = (cnt == cout);
assign clkout = clk_equ;
/*************读数据到缓存进程****************************/
always@(posedge clk)
begin
if(WR)
begin
Datainbuf = {1’b1,Datain[7:0],1’b0}; //读入数据,并把缓存组成一帧数据,10位
WR_ctr = 1’b1; //置开始标志位
end
else if(TI==0)
WR_ctr = 1’b0;
end
/*************主程序进程****************************/
always@(posedge clk)
begin
if(clk_equ)
begin
if(WR_ctr==1||bincnt<4’d10) //发送条件判断,保证发送数据的完整性
begin
if(bincnt<4’d10)
begin
txd_reg = Datainbuf2[0]; //从最低位开始发送
Datainbuf2 = Datainbuf〉>bincnt; //移位输出
bincnt = bincnt+4’d1; //发送数据位计数
TI = 1’b0;
end
else
bincnt = 4’d0;
end
else
begin //发送完毕或者处于等待状态时TXD和TI为高
txd_reg = 1’b1;
TI = 1’b1;
end
end
end
assign TXD = txd_reg; //TXD连续输出
endmodule
由CPU送来的待发送的并行数据,首先写入发送缓冲器TBR[7。。0]。发送缓冲区中有数据待发送时,数据自动装入移位寄存器TSR[7。.0]并自动完成串行数据的发送。首先传送一位起始位0,然后根据帧结构中定义的数据长度,分别串行移出TSR[7..0]中的数据,数据的低位在前,高位在后。当没有数据发送的时候,SDO管脚保持高电平.二进制数11110000从引脚DIN[7。。0]并行输入,当WRN为0时,启动发送程序,计数器开始计数,使发送器将并行数据锁存到发送缓冲器TBR[7.。0],并通过发送移位寄存器TSR[7.。0]逐位移位发送串行数据至串行数据输出端SDO.在数据发送过程中用输出信号TBRE,TSRE作为标志信号。当一帧数据由发送缓冲器TBR[7。。0]送到发送移位寄存器TSR[7。.0]时,TBRE信号为1。由发送数据缓冲器传给发送移位寄存器主要由信号TSRE控制.当TSRE为1时,表示发送移位寄存器TSR[7.。0]串行发送完毕;为0时表示还没有发送完一帧数据。由仿真结果验证了发送模块的正确性。
3.3数据接收模块
3.3.1 接收模块及其功能
接收模块的作用是把收到的串行数据转换成并行数据进行输出,并判断收到的数据是否有错。数据接收的思想是,当不在字节帧接收过程时,每次定时中断以3倍的波特率监视RxD的状态,当其连续3次采样电平依次为1、0、0时,就认为检测到了起始位,则开始启动一次字节帧接收,字节帧接收过程由接收状态机控制,每次中断只接收1个位,经过若干个定时中断完成1个字节帧的接收【1】。接收模块的代码如下:
module rec(clk,clkout,Dataout,RXD,RI);
input clk,RXD;
output clkout,RI;
output [7:0] Dataout; //并行数据输出
reg StartF,RI;
reg [9:0] UartBuff; //接收缓存区
reg [3:0]count,count_bit;
reg [15:0] cnt;
reg [2:0]bit_collect; //采集数据缓存区
wire clk_equ,bit1,bit2,bit3,bit;
parameter cout = 312; //时钟是48M所以16*9600的分频数为312。5,这里取整数
/*************波特率发生进程****************************/
always@(posedge clk)
begin
if(clk_equ)
cnt = 16’d0;
else
cnt=cnt+1’b1;
end
assign clk_equ = (cnt == cout);
assign clkout = clk_equ;
assign bit1 = bit_collect[0]&bit_collect[1];
assign bit2 = bit_collect[1]&bit_collect[2];
assign bit3 = bit_collect[0]&bit_collect[2];
assign bit = bit1|bit2|bit3;
always@(posedge clk)
begin
if(clk_equ)
begin
if(!StartF) //是否处于接收状态
begin
if(!RXD)
begin
count = 4’b0; //复位计数器
count_bit = 4’b0;
RI = 1’b0;
StartF = 1’b1;
end
else RI = 1’b1;
end
else
begin
count = count+1’b1; //位接收状态加1
if(count==4’d6)
bit_collect[0] = RXD; //数据采集
if(count==4’d7)
bit_collect[1] = RXD; //数据采集
if(count==4’d8)
begin
bit_collect[2] = RXD; //数据采集
UartBuff[count_bit] = bit;
count_bit = count_bit+1’b1;//位计数器加1
if((count_bit==4’d1)&&(UartBuff[0]==1’b1))//判断开始位是否为0
begin
StartF = 1’b0; //标志开始接收
end
RI = 1’b0; //中断标志位低
end
if(count_bit>4’d9) //检测是否接收结束
begin
RI = 1’b1; //中断标志为高标志转换结束
StartF = 1’b0;
end
end
end
end
assign Dataout = UartBuff[8:1]; //取出数据位
endmodule
接收器进入准备接收数据状态,不断监视串行输入线RXD端,如果出现低电平,立刻启动起始位检测电路进行确认,一旦确认为接收到正确的起始位,则以波特率作为采样时钟,对每个数据位的中间位置采样一次,并把采样到的信息以移位方式送人接收移位寄存器RSR。接收到一帧数据位后,把串行数据转化成并行数据,并进行奇偶校验、停止位、中止态的检查。接收完毕后,DAT_READ置1。
3.3。2 接收模块功能仿真
二进制数11101010从引脚RXD串行输入,接收器先要捕捉起始位,在RDN信号为0条件下,启动接收程序,计数器开始计数,数据从RXD[7。。0]串行输入,由接收移位寄存器RSR[7。。0]逐位移位接收,并在接收完成时传送给接收缓冲寄存器RBR[7.。0],最后接收缓冲寄存器RBR[7..0]将接收的数据传送至DOUT[7。。0],由它并行输出,同时输出一个接收数据准备好信号DATA _RE标志数据接收完毕。
3。4 波特率发生器模块
3。4。1 波特率发生器模块及其功能
波特率发生器模块主要用于产生接收模块和发送模块的时钟频率,其实质就是一个分频器,可以根据给定的系统时钟频率和要求的波特率算出波特率分频因子,作为分频器的分频数。波特率发生器产生的时钟频率CLK16X不是波特率时钟频率CLK,而是波特率时钟频率CLK的16倍。波特率的计算按照计算公式进行,在设置最高波特率时一定要考虑模拟串口程序代码的执行时间,该定时时间必须大于模拟串口的程序的规定时间.单片机的执行速度越快,则可以实现更高的串口通讯速度。[1]
UART在发送或接收数据时,使用的时钟信号频率f是波特率(b=9 600 b/s)的16倍,由外部系统时钟进行16分频得到。UART每16个波特时钟发送或接收一个二进制位,设计中采用的晶振频率c=25 MHz,那么波特率发生器输出的时钟信号周期为:
4。 结语
UlART是广泛使用的串行数据通信电路,因其要求的传输线少,可靠性高,传输距离远,所以系统间互联常采用异步串行通信接口方式。本文用Verilog HDL语言,结合有限状态机的设计方法实现了UART的功能,将其核心功能集成到FPGA上,使整体设计紧凑、小巧,实现的UART功能稳定、可靠.
参考文献
【1】 单片机软件UART(通用异步接收/发送装置)的设计资料 .电子电路网[引用日期 2012—05—31].
评论0