FPGA的UART完整设计.docx
《FPGA的UART完整设计.docx》由会员分享,可在线阅读,更多相关《FPGA的UART完整设计.docx(26页珍藏版)》请在冰豆网上搜索。
FPGA的UART完整设计
第三章UART设计
3.1UART的帧格式
在UART中,数据位是以字符为传送单位,数据的前、后要有起始位、停止位,另外可以在停止位的前面加上一个比特(bit)的校验位。
其帧格式如图所示。
数据位
起始位D0D1D2D3——————D7校验位停止位
以9600波特率接收或发送,每一位时间为
1/9600秒,或48MHZ晶振5000次计数
图3_1数据帧格式
文章通过分析UART的功能,利用有限状态机来描述UART核心控制逻辑的方法,将其核心功能集成,从而使整个设计更加稳定、可靠。
基本的UART通信只需要两条信号线就可以完成数据的相互通信。
UART的功能模块如图3_2所示。
波特发生器
Uart控制器
接收模块发送模块
对象模块
图3_2UART的功能模块图
3.2UART模块
在大规模电路的设计中,广泛采用层次化,结构化的设计方法。
它将一个完整的硬件设计任务从系统级开始,划分为若干个可操作的模块,编制出相应的模型并进行仿真验证,最后在系统级上进行组合。
这样在提高设计效率的同时又提高了设计质量,是目前复杂数字系统实现的主要手段,也是本文设计思想的基础。
read
send
clear_check
其系统模块可划分为4个部分,如波特发生器,控制器,接收器,发送器,如图3-3所示:
readsend
Clr3clr4ks
csData_in
Data_outclear
Read_enablesend_enable
counterscounters
resetCounters(control)
state
T1clk_enable
Clk_clear
Clk(波特发生器)
clk
图3-3uart结构图
3.2.1主要引脚功能介绍
Read:
串行输入send:
串行输出
Data_in:
并行输入data_out:
并行输出
Cs:
通知cpu接收数据位ks:
通知cpu发送准备位
Reset:
重启输入state:
uart状态输入
Clk:
48M时钟输入
3.2.2UART主体程序
`timescale1ns/1ns
modulegs_opt(
inputwireread,
inputwireclk,
inputwirereset,
inputwirestate,
inputwire[7:
0]dat_in,
outputwiresend,
outputwirecs,
outputwireks,
outputwire[7:
0]dat_out
);
wiresend_enable;
wireread_enable;
wireclk_enable3;
wireclk_enable4;
wireclear3;
wireclear4;
wireclk_enable;
wire[7:
0]counters;
wireclear;
wiret1;
/*
read,send,cs,ks,reset,state,clk,dat_in,dat_out);
//moduleuart(read,send,cs,ks,reset,state,clk,dat_in,dat_out);
inputread,clk,reset,state;
//read为串行输入,clk为时钟输入50MHZ,reset为重启键
input[7:
0]dat_in;//并行数据输入
outputsend,cs,ks;
//send为串行输出,cs为通知cpu接收数据位,ks为发送准备位
output[7:
0]dat_out;//并行数据输出
wireclear,clk_enable,read_enable,clear3,send_enable,clear4,t1;
wire[7:
0]counters,dat_in;*/
rxdu1(
.dat_out(dat_out),
.cs(cs),
.read(read),
.reset(reset),
.clk_enable3(clk_enable3),
.clk(clk),
.read_enable(read_enable),
.clear3(clear3),
.counters(counters)
);//接收数据module
txdu2(
.dat_in(dat_in),
.ks(ks),
.send(send),
.reset(reset),
.clk_enable4(clk_enable4),
.clk(clk),
.send_enable(send_enable),
.clear4(clear4),
.counters(counters)
);//发送数据module
clk_bauu3(
.clk(clk),
.t1(t1),
.clk_enable(clk_enable)
);//时钟计数器模块
ctrlu4(
.read_enable(read_enable),
.send_enable(send_enable),
.clk(clk),
.state(state),
.t1(t1),
.read(read),
.counters(counters),
.reset(reset),
.clear(clear)
);
check_cleu5(
.state(state),
.clear3(clear3),
.clear4(clear4),
.clear(clear),
.clk_enable3(clk_enable3),
.clk_enable4(clk_enable4),
.clk_enable(clk_enable)
);
endmodule///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3.3UART发送模块
3.3.1UART的数据发送服务
发送器实现的功能是将输入的8位并行数据变为串行数据,同时在数据头部加起始位,在数据位尾部加奇偶校验位和停止位。
数据发送服务如表3.1
计数器
0
1~~~8
9
10
操作
发送低电平
发送数据和奇偶校验
发送奇偶校验结果
发送高电平
表3.1数据发送
其基本特点是:
①在信号线上共有两种状态,可分别用逻辑1和逻辑。
来区分。
在发送器空闲时,数据线应该保持在逻辑高电平状态。
②发送起始位:
该位是一个逻辑0,总是加在每一帧的头部,提示接受器数据传输即将开始,在接收数据位过程中又被分离出去,占据一个数据位的时间。
③发送数据位:
在起始位之后就是数据位,一般为8位一个字节的数据,低位在前,高位在后。
如字母C在ASCII表中是十进制67,二进制01000011,那么传输的将是110000100。
并在数据发送过程当中,进行数据位奇偶校验。
④发送校验位:
该位一般用来判断接收的数据位有无错误,常用的校验方法是奇偶校验法。
将3过程当中奇偶校验的结果输入到数据线,并占一个数据位时钟。
⑤停止位:
停止位总在每一帧的末尾,为逻辑1,用于标志一个字符传送的结束,占据一个数据位的时间。
⑥帧:
从起始位到停止位之间的一组数据称为一帧。
3.3.2UART的数据发送操作
如图3-4
拉低电平空闲检测
Cpu发送位检测
自检测
接cpu传入数据拉高电平
发送等待数据发送和奇偶校验奇偶结果发送
图3-4数据发送操作
解释:
采用9600波特率发送
从cpu传入数据:
是指将data_in端口的数据存入寄存器中
Cpu发送为检测:
是指将ks寄存器置位,即数据发送完毕
3.3.3UART的数据发送模块程序
modulerxd(dat_out,cs,read,reset,
clk_enable3,clk,read_enable,clear3,counters);
//接收数据module
inputread_enable;
inputread,reset,clk;//read为串行输入,read_control为时钟控制,reset为重启键
input[7:
0]counters;
outputcs,clear3,clk_enable3;//cs为通知cpu读取数据位
output[7:
0]dat_out;//wireclear3;
regcs,cs1,clk_enable3;
reg[7:
0]data_out;//移位寄存器
regparity_check_result,parity_result,clear3,clear1;/////////////////////////////////////////////////////////////////////////
always@(posedgeclk)
begin
if(read_enable)//当read_enable为高电平时为发送操作状态
begin
clk_enable3<=1;
clear3<=clear1;
end
else
begin
clear3<=1;
end
end
//////////////////////////////////////////////////////////////////////////////
always@(negedgecounters[0])///接收操作
if(read_enable&!
reset)
begin
if(counters==8'b00011000)//1
begin
data_out[7]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b00101000)//2
begin
data_out[6]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b00111000)//3
begin
data_out[5]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b01001000)//4
begin
data_out[4]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b01011000)//5
begin
data_out[3]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b01101000)//6
begin
data_out[2]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b01111000)//7
begin
data_out[1]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b10001000)//8
begin
data_out[0]<=read;
parity_check_result<=parity_check_result+read;
end
elseif(counters==8'b10011000)//9进行奇偶校验检测
begin
parity_result<=read;
parity_result<=#2(parity_check_result==parity_result)?
1:
0;
end
elseif(counters==8'b10101000)//0进行帧检测
begin
cs1<=(read)?
1:
0;
end
elseif(counters==8'b10101010)//01给cpu发送接收信号
begin
cs<=(cs1&&parity_result)?
1:
0;//当奇偶校验结果与帧检测结果都为1时,cs置位
clear1<=1;
//clk_enable<=0;
//clk_enable3<=0;
end
elseif(counters==8'b00001000)//检测是否是毛刺
begin
clear1<=(!
read)?
0:
1;
end
elseclear1<=0;
end
elseclear1<=1;
endmodule
3.3.4UART的数据发送模块程序仿真图
当reset为零时
图3-5reset为零时仿真图
如图为UART的数据发送模块的功能仿真图,为方便观察,其中的时钟是直接给出来的,根据图中的数据判读,其功能为正确,UART的数据发送模块编译成功。
1.当计时器为140ns时,为数据接收
2.当计时器为357ns时,为数据发送
3.当计时器为705ns时,为奇偶校验结果发送
4.当计时器为825ns时,发送高电平
当reset为1时
如图3-6
图3-6reset为1时仿真图
3.4UART接收模块
3.4.1UART数据接收服务
串行数据帧和接收时钟是异步的,由逻辑1跳变为逻辑0可视为一个数据帧的开始,所以接收器首先要判断起始位。
如表3.2
计数器
0
1~~~~8
9
10
操作
数据起始位检测
数据接收和奇偶校验
奇偶校验
数据判断
表3.2uart的数据接收服务
其基本特点是:
UART接收状态一共有4个:
state0(检测起始位),state1(对数据位进行采样,并串/并转换),state2(奇偶校验分析),state3(接收数据正确与否检测)。
①起始位判读:
当UART接收器复位以后,接收器将处于这一状态。
在该状态,控制器一直等待read电平的跳变,即从逻辑1变为逻辑0,也就是等待起始位的到来。
一旦检测到起始位,就对采样时钟elk一rev上跳沿计数,当计数为8时,也就是确保在起始位的中间点,然后转到state1状态。
②数据接收:
该状态下,每间隔16位倍频采样一位串行数据,接收8位异步数据并进行串/并转换。
即对clk一rev上跳沿计数,当为16时,就对数据采样,这样保证了数据位是在中点处被采样的,同时串/并转换,当检测到已收到8个数据后以后,便进入了state2状态。
③奇偶校验:
该状态实现的功能是奇偶校验。
本文采用的是偶校验。
校验结束以后,转到state3状态。
④数据帧判读:
该状态是用来帧校验的,即在校验位以后,检测停止位是否为逻辑高电平
3.4.2UART数据接收操作
图3-7UART数据接收操作
起始位检测空闲检测
Cpu接收位检测
检测
毛刺检测数据帧检测
接收等待数据位读取和奇偶校验奇偶结果比较
图3-7UART数据接收操作
解释:
数据接收速度9600波特率,以16倍频接收
cpu接收位检测:
当奇偶结果比较和数据帧检测都正确时,cpu检测接收位cs置位
3.4.3UART的数据接收模块程序
///发送数据模块
moduletxd(
dat_in,send,reset,clk_enable4,clk,
send_enable,clear4,counters,ks);//发送数据module
input[7:
0]dat_in,counters;
inputreset,clk,send_enable;
outputsend,clk_enable4,clear4;
outputks;//jia
wireclear;
wire[7:
0]dat_s;
regsend,parity_result,ks;
regclk_enable,clear1,clear4,clk_enable4;
reg[7:
0]date_s;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
always@(posedgeclk)
begin
if(send_enable&!
reset)//当send_enable为高电平时为发送操作状态
begin
clk_enable4<=1;
clear4<=clear1;
end
else
begin
clear4<=1;
end
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////
always@(posedgeclk)
if(send_enable&!
reset)
begin
if(counters==8'b00000001)//0
begin
send<=0;
date_s<=dat_in;//?
parity_result<=1;
end
elseif(counters==8'b00010000)//1
begin
send<=date_s[0];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b00100000)//2
begin
send<=date_s[1];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b00110000)//3
begin
send<=date_s[2];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b01000000)//4
begin
send<=date_s[3];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b01010000)//5
begin
send<=date_s[4];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b01100000)//6
begin
send<=date_s[5];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b01110000)//7
begin
send<=date_s[6];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b10000000)//8
begin
send<=date_s[7];
parity_result<=parity_result+date_s[0];
end
elseif(counters==8'b10010000)//9发送奇偶校验结果
begin
send=parity_result;
end
elseif(counters==8'b10100000)//0发送高电平
begin
send<=1;
end
elseif(counters==8'b10101111)//0
begin
clear1<=1;
ks<=(send&&parity_result)?
1:
0;
end
elseif(counters==8'b00000000)
begin
send<=1;
end
elseclear1<=0;
end
else
send<=1;
endmodule
/////////////////////////////////////////////////////////////////
3.4.4UART的数据接收模块程序功能仿真图
图3-8当counters指定时间时功能仿真
图3-8当counters指定时间时
解释:
由图可明显看出data[0]和data[1]变化,模块功能仿真通过
图3-9当counters未指定时间时功能仿真
图3-9当counters未指定时间时功能仿真
3.5UART控制器
3.5.1UART控制器服务
UART控制器实质上是一组计数器,由state决定