资源描述
电子科技大学成都学院毕业设计论文
第三章UART设计
3.1 UART的帧格式
在 UART 中,数据位是以字符为传送单位,数据的前、后要有起始位、停止位,另外可以在停止位的前面加上一个比特(bit)的校验位。其帧格式如图所示。
数据位
起始位 D0 D1 D2 D3 —————— D7 校验位 停止位
以9600波特率接收或发送,每一位时间为
1/9600秒,或48MHZ晶振5000次计数
图3_1数据帧格式
文章 通 过 分析UART的功能,利用有限状态机来描述UART核心控制逻辑的方法,将其核心功能集成,从而使整个设计更加稳定、可靠。基本的UART通信只需要两条信号线就可以完成数据的相互通信。UART的功能模块如图3_2所示。
波特发生器
Uart控制器
接收模块 发送模块
对象模块
图3_2UART的功能模块图
3.2 UART模块
在大规模电路的设计中,广泛采用层次化,结构化的设计方法。它将一个完整的硬件设计任务从系统级开始,划分为若干个可操作的模块,编制出相应的模型并进行仿真验证,最后在系统级上进行组合。这样在提高设计效率的同时又提高了设计质量,是目前复杂数字系统实现的主要手段,也是本文设计思想的基础。
其系统模块可划分为4个部分,如波特发生器,控制器,接收器,发送器,如图3-3所示:
read
send
clear_check
read send
Clr3 clr4 ks
cs Data_in
Data_out clear
Read_enable send_enable
counters counters
reset Counters(control)
state
T1 clk_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主体程序
`timescale 1ns/1ns
module gs_opt(
input wire read,
input wire clk,
input wire reset,
input wire state,
input wire [7:0] dat_in,
output wire send,
output wire cs,
output wire ks,
output wire [7:0] dat_out
);
wire send_enable;
wire read_enable;
wire clk_enable3;
wire clk_enable4;
wire clear3 ;
wire clear4 ;
wire clk_enable;
wire [7:0] counters;
wire clear ;
wire t1;
/*
read,send,cs,ks,reset,state,clk,dat_in,dat_out);
//module uart(read,send,cs,ks,reset,state,clk,dat_in,dat_out);
input read,clk,reset,state;
//read为串行输入,clk为时钟输入50MHZ,reset为重启键
input[7:0] dat_in;//并行数据输入
output send,cs,ks;
//send为串行输出,cs为通知cpu接收数据位,ks为发送准备位
output[7:0] dat_out;//并行数据输出
wire clear,clk_enable,read_enable,clear3,send_enable,clear4,t1;
wire[7:0] counters,dat_in;*/
rxd u1 (
.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
txd u2 (
.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_bau u3 (
.clk(clk) ,
.t1 (t1),
.clk_enable (clk_enable)
); //时钟计数器模块
ctrl u4(
.read_enable (read_enable) ,
.send_enable (send_enable),
.clk (clk),
.state (state),
.t1 (t1),
.read (read ),
.counters (counters),
.reset (reset ),
.clear (clear)
);
check_cle u5 (
.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的数据发送模块程序
module rxd(dat_out,cs,read,reset,
clk_enable3,clk,read_enable,clear3,counters);
//接收数据module
input read_enable;
input read,reset,clk;//read为串行输入,read_control为时钟控制,reset为重启键
input[7:0] counters;
output cs,clear3,clk_enable3;//cs为通知cpu读取数据位
output[7:0] dat_out;//wire clear3;
reg cs,cs1,clk_enable3;
reg[7:0] data_out;//移位寄存器
reg parity_check_result,parity_result,clear3,clear1;/////////////////////////////////////////////////////////////////////////
always@(posedge clk)
begin
if(read_enable)//当read_enable为高电平时为发送操作状态
begin
clk_enable3<=1;
clear3<=clear1;
end
else
begin
clear3<=1;
end
end
//////////////////////////////////////////////////////////////////////////////
always@(negedge counters[0]) ///接收操作
if(read_enable & !reset)
begin
if (counters==8'b00011000) //1
begin
data_out[7]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b00101000) //2
begin
data_out[6]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b00111000) //3
begin
data_out[5]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b01001000) //4
begin
data_out[4]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b01011000) //5
begin
data_out[3]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b01101000) //6
begin
data_out[2]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b01111000) //7
begin
data_out[1]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b10001000) //8
begin
data_out[0]<=read;
parity_check_result<=parity_check_result + read;
end
else if (counters==8'b10011000) //9进行奇偶校验检测
begin
parity_result<=read;
parity_result<=#2 (parity_check_result == parity_result) ? 1:0;
end
else if (counters==8'b10101000) //0进行帧检测
begin
cs1<=(read) ? 1:0;
end
else if (counters==8'b10101010) //01给cpu发送接收信号
begin
cs<=(cs1 && parity_result) ? 1:0;//当奇偶校验结果与帧检测结果都为1时,cs置位
clear1<=1;
//clk_enable<=0;
//clk_enable3<=0;
end
else if(counters==8'b00001000)//检测是否是毛刺
begin
clear1<=(!read)?0:1;
end
else clear1<=0;
end
else clear1<=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(检测起始位),stat e1( 对数据位进行采样,并串/并转换),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的数据接收模块程序
///发送数据模块
module txd(
dat_in,send,reset,clk_enable4,clk,
send_enable,clear4,counters,ks);//发送数据module
input[7:0] dat_in,counters;
input reset,clk,send_enable;
output send,clk_enable4,clear4;
output ks;//jia
wire clear;
wire[7:0] dat_s;
reg send,parity_result,ks;
reg clk_enable,clear1,clear4,clk_enable4;
reg[7:0] date_s;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
always@(posedge clk)
begin
if(send_enable & !reset)//当send_enable为高电平时为发送操作状态
begin
clk_enable4<=1;
clear4<=clear1;
end
else
begin
clear4<=1;
end
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////
always@(posedge clk)
if(send_enable & !reset)
begin
if(counters==8'b00000001)//0
begin
send<=0;
date_s<=dat_in;//?
parity_result<=1;
end
else if(counters==8'b00010000)//1
begin
send<=date_s[0];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b00100000)//2
begin
send<=date_s[1];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b00110000)//3
begin
send<=date_s[2];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b01000000)//4
begin
send<=date_s[3];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b01010000)//5
begin
send<=date_s[4];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b01100000)//6
begin
send<=date_s[5];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b01110000)//7
begin
send<=date_s[6];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b10000000)//8
begin
send<=date_s[7];
parity_result<=parity_result + date_s[0];
end
else if(counters==8'b10010000)//9发送奇偶校验结果
begin
send=parity_result;
end
else if(counters==8'b10100000)//0发送高电平
begin
send<=1;
end
else if(counters==8'b10101111)//0
begin
clear1<=1;
ks<=(send && parity_result) ? 1:0;
end
else if(counters==8'b00000000)
begin
send<=1;
end
else clear1<=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决定计数器数据发送对象,在这里指定当state为1时,发送到UART接收模块,反之,发送到UART发送模块。当计数到指定数据时,触发指定模块的制定操作。
3.5.2UART控制器模块程序
module counters(read_enable,send_enable,
clk,state,t1,read,counters,reset,clear);//程序计数寄存器
input clk,state,t1,read,reset,clear;//state为uart状态输入,
//clear为程序计数寄存器清零控制位
output[7:0] counters;
output read_enable,send_enable;
reg read_enable,send_enable,control;//read_enable为接收控制位?////
//////send_enable为发送控制位,control为程序计数寄存器为零状态寄存位
reg[7:0] counters;//8位程序计数寄存器
always@(posedge clk)
//当程序计数寄存器为零时,程序计数寄存器为零状态寄存位置位
begin
control<=(!counters)? 1 : 0;
end
///////////////////////////////////////////////////////////////////////////////////////
always@(negedge read)//uart发送或接收状态判断
if(control)
begin
if(state)
begin
if(!read)
begin
read_enable<=1;
send_enable<=0;
end
else
begin
send_enable<=0;
end
end
else
begin
send_enable<=1;
read_enable<=0;
end
end
////////////////////////////////////////////////////////////
always@(posedge t1)
if(!reset && !clear)//reset为1时,clear为1时程序计数寄存器清零
begin
if(counters>8'b10101111)
counters<=8'b00000000;
else
counters<=counters + 1;
end
else
begin
counters<=8'b00000000;
end
endmodule
3.5.2UART控制器模块程序仿真图
图3-10UART控制器模块程序仿真图
由图判读有:
1. 当计时器为175ns时,!计时器==0,control被赋予1;xx_enable未被赋值
2. 当计时器为265ns时,xx_enable未被赋值
3. 当计时器为335ns时,xx_enable被赋值
4. 当计时器为475ns时,xx_enable被赋值
5. 当计时器为630ns时,xx_enable被赋值
6. 当计时器为721ns时,xx_enable未被赋值
7. 当计时器为850ns时,xx_enable被赋值
可判断UART控制器模块程序编译成功
3.6UART波特发生器
3.6.1UART波特发生器服务
为UART控制器提供时钟,本文采用9600波特率发送或接收数据。波特率发生器实际上就是分频器,设计比较简单。
3.6.2UART波特发生器模块程序
///波特率产生模块
module clk_bau(clk,t1,clk_enable);//时钟计数器模块
input clk,clk_enable;
output t1;
//output[8:0] counter1;
reg t1;
reg[7:0] counter1;
//(48,000,000/9,600)=5,000 为一个数据发送计数,接收为16倍频为5,000/16=312
always@(posedge clk)
if(clk_enable)//当clk_enable有效时,计数器计数
begin
if(counter1==8'b10010111)//当counter等于156时
begin
counter1<=8'b00000000;//counter清零
t1<=t1 + 1;//t1取反
end
else
begin
counter1<=counter1 + 1;
t1<=t1;
end
end
else
begin
counter1<=8'b00000000;
t1<=0;
end
endmodule
3.6.13UART波特发生器程序仿真图
如图3-11;
图3-11UART波特发生器程序仿真图
由图判读:
1. 当clk_enable为0时,时钟不计时;
2. 当clk_enable为1时,时钟计时
译文
专业文档供参考,如有帮助请下载。
展开阅读全文