实例十二 UART的发送与接收模块设计

6.1 实例十二 UART的发送与接收模块设计

6.1.1. 本章导读

设计目的
(1)学习UART的工作原理,并用verilog设计编写UART的发送/接收模块。
(2)熟练运用Robei软件进行调试模拟仿真。
设计原理
UART的帧格式  
异步串行数据的一般格式是:起始位+数据位+结束位,其中起始位是1位,数据位是8位数据或7位数据加1位奇偶校验位,停止位是2位。如图6-1-1所示:
实例十二 UART的发送与接收模块设计_第1张图片
(1)接收原理:
由于UART是异步传输,没有传输同步时钟。为了能保证数据传输的正确性,采样模块利用16倍数据波特率的时钟进行采样,假设波特率为115200,则采样时钟为clk16x=115200×16。每个数据占据16个采样时钟周期,1bit起始位+8bit数据位+1bit停止位=10bit,因此一帧共占据16×10=160个采样时钟,考虑到每个数据位可能有1-2个采样时钟周期的偏移,因此将各个数据位的中间时刻作为采样点,以保证采样不会滑码或误码。一般UART一帧的数据位数为8,这样即使每个数据有一个时钟的误差,接收端也能正确地采样到数据。因此,采样时刻为24(跳过起始位的16个时钟)、40、56、72、88、104、120、136、152(停止位),如下图6-1-2所示:
实例十二 UART的发送与接收模块设计_第2张图片
其中,RX为接收引脚,CNT为对采样时钟进行计数的计数器。
(2)发送原理:
当并行数据准备好后,如果得到发送指令,则将数据按UART协议输出,先输出一个低电平的起始位,然后从低到高输出8个数据位,接着是可选的奇偶校验位,最后是高电平的停止位;
由于发送时钟clk16x为波特率的16倍,因此对clk16x计数到16时,发送D0;计数到32时,发送D1……依此类推,如图6-1-3所示;
实例十二 UART的发送与接收模块设计_第3张图片

6.1.2. 设计流程

1. 接收模块的设计
(1)新建一个模型,名为UART,类型为module,具备 3 输入 2 输出,每个引脚的属性和名称如下图6-1-4所示。
实例十二 UART的发送与接收模块设计_第4张图片
实例十二 UART的发送与接收模块设计_第5张图片
(2)添加代码。点击模型下方的Code添加代码。
reg[7:0] cnt;
reg trigger_r0;
reg [3:0] count;
wire neg_tri;

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
begin
trigger_r0<=1’b0;
end
else
begin
trigger_r0<=rx;
end
end

assign neg_tri=trigger_r0&~rx;
reg cnt_en;

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
cnt_en<=1’b0;
else if(neg_tri1’b1)
cnt_en<=1’b1;
else if(cnt
8’d152)
cnt_en<=1’b0;
end

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
cnt<=8’d0;
else if(cnt_en)
cnt<=cnt+1;
else
cnt<=8’d0;
end

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
begin
DataReceived<=8’b0;
count<=0;
end
else if(cnt_en)
case(cnt)
8’d24:begin DataReceived[0]<=rx;count<=count+1;end
8’d40:begin DataReceived[1]<=rx;count<=count+1;end
8’d56:begin DataReceived[2]<=rx;count<=count+1;end
8’d72:begin DataReceived[3]<=rx;count<=count+1;end
8’d88:begin DataReceived[4]<=rx;count<=count+1;end
8’d104:begin DataReceived[5]<=rx;count<=count+1;end
8’d120:begin DataReceived[6]<=rx;count<=count+1;end
8’d136:begin DataReceived[7]<=rx;count<=count+1;end
endcase
end
always@(posedge clk16x or negedge rst_n)
begin
if(!rst_n)
DataReady<=1’b0;
else if(cnt==8’d152)
DataReady<=1’b1;
else
DataReady<=1’b0;
end
(3)保存模型(存储文件夹路径不能有空格和中文),运行并检查有无错误输出。
2. UARTTEST测试文件的设计
(1)新建一个3输入2 输出的uarttest测试文件,记得将Module Type设置为 “testbench”,各个引脚配置如图6-1-6所示。
实例十二 UART的发送与接收模块设计_第6张图片
(2)另存为测试文件。将测试文件保存到上面创建的模型所在的文件夹下。
(3)添加模型。在Toolbox工具箱的Current栏里会出现模型,单击该模型并在 uarttest上添加,并连接引脚,如下图6-1-7所示:
实例十二 UART的发送与接收模块设计_第7张图片
(4)输入激励。点击测试模块下方的“Code”,输入激励算法。激励代码用 $finish 结束。
测试代码:
initial begin
clk16x=0;
rst_n=0;
rx=0;
#2
rst_n=1;
#2
rst_n=0;
#2
rst_n=1;
#2
rx=1;
#32
rx=0;
#64
rx=1;
#128
rx=0;
#64
rx=1;
#32
rx=0;
#32
rx=1;
#100
$finish;
end
always #1 clk16x=~clk16x;

(5)执行仿真并查看波形。查看输出信息。
检查没有错误之后查看波形。点击右侧 Workspace 中的信号,进行添加并查看分析仿真结果。如图6-1-8所示:
实例十二 UART的发送与接收模块设计_第8张图片
3. 发送模块设计
(1)新建一个模型,名为uartsend,类型为module,具备4 输入2 输出,每个引脚的属性和名称如下图6-1-9所示。
实例十二 UART的发送与接收模块设计_第9张图片
实例十二 UART的发送与接收模块设计_第10张图片
(2)添加代码。点击模型下方的 Code添加代码。
reg [7:0] cnt;
reg TransEn_r;
wire pos_tri;
reg cnt_en;

always@(posedge clk16x or negedge rst_n)
begin
if(!rst_n)
TransEn_r <= 1’b0;
else
TransEn_r <= TransEn;
end

assign pos_tri = ~TransEn_r & TransEn;
reg [7:0] ShiftReg;

always @ (posedge pos_tri or negedge rst_n)
begin
if(!rst_n)
ShiftReg <= 8’b0;
else
ShiftReg <= DataToTrans;
end

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
begin
cnt_en <= 1’b0;
BufFull <= 1’b0;
end
else if(pos_tri1’b1)
begin
cnt_en <=1’b1;
BufFull <= 1’b1;
end
else if(cnt
8’d160)
begin
cnt_en<=1’b0;
BufFull <= 1’b0;
end
end

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
cnt<=8’d0;
else if(cnt_en)
cnt<=cnt+1;
else
cnt<=8’d0;
end

always @ (posedge clk16x or negedge rst_n)
begin
if(!rst_n)
begin
tx <= 1’b1;
end
else if(cnt_en)
case(cnt)
8’d0 : tx <= 1’b0;
8’d16 : tx <= ShiftReg[0];
8’d32 : tx <= ShiftReg[1];
8’d48 : tx <= ShiftReg[2];
8’d64 : tx <= ShiftReg[3];
8’d80 : tx <= ShiftReg[4];
8’d96 : tx <= ShiftReg[5];
8’d112 : tx <= ShiftReg[6];
8’d128 : tx <= ShiftReg[7];
8’d144 : tx <= 1’b1;
endcase
else
tx <= 1’b1;
end

(3)运行并检查有无错误输出,将文件保存到上面创建的模型所在的文件夹下。
4. UARTsendtest测试文件的设计
(1)新建一个 4输入2 输出的UARTsendtest测试文件,记得将Module Type设置为 “testbench”,各个引脚配置如图6-1-11所示。
实例十二 UART的发送与接收模块设计_第11张图片
(2)另存为测试文件。将测试文件保存到上面创建的模型所在的文件夹下。
(3)添加模型。在Toolbox工具箱的Current栏里会出现模型,单击该模型并在 uartsendtest上添加,并连接引脚,如下图6-1-12所示:
实例十二 UART的发送与接收模块设计_第12张图片
(4)输入激励。点击测试模块下方的“Code”,输入激励算法。激励代码用 $finish 结束。
测试代码:
initial begin
clk16x=0;
rst_n=1;
TransEn=0;
DataToTrans=0;
#2
rst_n=0;
#2
DataToTrans=8’b10110010;
#2
rst_n=1;
#2
TransEn=1;
#1000
$finish;
end

always #1 clk16x=~clk16x;

(5)执行仿真并查看波形。查看输出信息。
检查没有错误之后查看波形。点击右侧 Workspace 中的信号,进行添加并查看分析仿真结果。如图6-1-13所示:
实例十二 UART的发送与接收模块设计_第13张图片

6.1.3. 问题与思考

1、采样时钟clk16x必须是波特率的16倍,波特率任意设置如57600、9600等皆可,只要满足16倍关系。
2、在本设计模块的基础上,尝试在接收模块中添加校验位,尽可能提高传输精度,降低出错率。

你可能感兴趣的:(Robei案例,高校,Robei,FPGA,教育)