Verilog学习脚印4-状态机(串口)
Verilog学习脚印4-状态机(串口)
附:verilog语法笔记(持续更新ing)
目录
- bash命令
- 串口协议简介(来自B站-北交李金城老师的PPT,侵删)
- 实例1:串口数据接收
- 电路原理(来自B站-北交李金城老师的PPT,侵删)
- 代码实现与验证
- 实例2:串口数据发送
- 电路原理(来自B站-北交李金城老师的PPT,侵删)
- 代码实现与验证
- 实例3:串口指令处理器
- 电路原理(来自B站-北交李金城老师的PPT,侵删)
- 代码实现
- 实例综合:顶层模块封装与验证
- 电路原理(来自B站-北交李金城老师的PPT,侵删)
- makefile
- 代码实现与验证
bash命令
bash调用dve和vcs的命令:
dve & // 启用VDE
vcs *.v -R -timescale=1ns/10ps +v2k +define+RTL_SAIF // 编译
串口协议简介(来自B站-北交李金城老师的PPT,侵删)
实例1:串口数据接收
电路原理(来自B站-北交李金城老师的PPT,侵删)
代码实现与验证
完整代码:
// 串口数据接收
`timescale 1ns/10ps
// ----- 定义 -----
module serial_rec(clk,res,RX,data_out,en_data_out
);input clk;
input res;
input RX;
output[7:0] data_out; //接收字节输出
output en_data_out; //输出使能reg[7:0] data_out;
reg en_data_out;
reg[3:0] state; //主状态机
reg[12:0] count; //用于计算bit宽度,24M/4800=5000,1.5bit_wide=7500
reg[3:0] count_bits;//用于bit数的计数reg RX_delay; //RX的延时always@(posedge clk or negedge res)
if(~res)beginstate<=0;count<=0;count_bits<=0;RX_delay<=0;data_out<=0;en_data_out<=0;
end
else beginRX_delay<=RX;case(state)0:begin //等空闲if(count==5000-1)begin //5000-1 !!!count<=0;endelse begincount<=count+1;endif(count==0)beginif(RX) begin //处于空闲状态时,对bit计数count_bits<=count_bits+1;endelse begincount_bits<=0;endendif(count_bits===12)begin // 保证处于空闲状态count_bits<=0;state<=1; // 进入state 1 ,等起始位endend1:begin //等起始位en_data_out<=0; //接收使能清零!if((~RX)&(RX_delay))begin //等到了脉冲尖!即RX开始拉低!state<=2;endend2:begin //经过1.5bit后开始接收数据,收最低位b0if(count==7500-1)begincount<=0;data_out[0]<=RX;state<=3;endelse begincount<=count+1;endend3:begin //接收b1if(count==5000-1)begincount<=0;data_out[1]<=RX;state<=4;endelse begincount<=count+1;endend4:begin //接收b2if(count==5000-1)begincount<=0;data_out[2]<=RX;state<=5;endelse begincount<=count+1;endend5:begin //接收b3if(count==5000-1)begincount<=0;data_out[3]<=RX;state<=6;endelse begincount<=count+1;endend6:begin //接收b4if(count==5000-1)begincount<=0;data_out[4]<=RX;state<=7;endelse begincount<=count+1;endend7:begin //接收b5if(count==5000-1)begincount<=0;data_out[5]<=RX;state<=8;endelse begincount<=count+1;endend8:begin //接收b6if(count==5000-1)begincount<=0;data_out[6]<=RX;state<=9;endelse begincount<=count+1;endend9:begin //接收b7if(count==5000-1)begincount<=0;data_out[7]<=RX;state<=10;endelse begincount<=count+1;endend10:begin //产生使能脉冲en_data_out<=1;state<=1;enddefault:beginstate<=0;count<=0;count_bits<=0;data_out<=0;endendcase
endendmodule// ----- testbench -----
module serial_rec_tb;
reg clk,res;
wire RX;
wire[7:0] data_out;
wire en_data_out;reg[25:0] RX_send; //!!!里面装有串口字节发送数据 16个1+起始位+数据+结束位,即16+1+8+1=26!!!
reg[12:0] count; //对系统时钟计数,以满足波特率assign RX=RX_send; //连接RX!serial_rec serial_rec(.clk(clk),.res(res),.RX(RX),.data_out(data_out),.en_data_out(en_data_out)
);initial begin$dumpfile("serial_rec_tb.vcd"); // save wave file$dumpvars(0,serial_rec);
endinitial beginclk<=0;res<=0;RX_send<={1'b1,8'haa,1'b0,16'hffff};count<=0;#17 res<=1;#4000000 $stop;
endalways #5 clk<=~clk;//注意!testbench中串口发送数据的写法!!!让RX_send以波特率节奏不断右移!always@(posedge clk)beginif(count==5000-1)begincount<=0;endelse begincount<=count+1;endif(count==0)begin //循环右移!RX_send[24:0]<=RX_send[25:1];RX_send[25]<=RX_send[0];end
endendmodule
波形输出:
实例2:串口数据发送
电路原理(来自B站-北交李金城老师的PPT,侵删)
代码实现与验证
代码如下:
// 串口数据发送
`timescale 1ns/1ps
module serial_send(clk,res,data_in,en_data_in,TX,rdy
);input clk;
input res;
input[7:0] data_in; //准备发送的数据
input en_data_in; //发送使能
output TX;
output rdy; //空闲标志,0表示空闲reg[3:0] state; //主状态机
reg[9:0] send_buf; //发送寄存器,存储需要发送的数据
assign TX=send_buf[0]; //连接TX,使sned_buf不断右移,相当于TX发送reg[9:0] send_flag; //用于判断右移结束!10'b10_0000_0000!!!reg[12:0] count; //用于计数波特率reg rdy; //表示空闲,防止数据发送冲突always@(posedge clk or negedge res)
if(~res)beginstate<=0;send_buf<=1;count<=0;send_flag<=10'b10_0000_0000;rdy<=0;
end
else begincase(state)0:begin //等使能信号if(en_data_in)beginsend_buf={1'b1,data_in,1'b0}; //结束位+数据+起始位send_flag<=10'b10_0000_0000;rdy<=1;state<=1;endend1:begin //串口发送,寄存器按照波特率右移if(count==5000-1)begincount<=0;endelse begincount<=count+1;endif(count==5000-1)beginsend_buf[8:0]<=send_buf[9:1];send_flag[8:0]<=send_flag[9:1];endif(send_flag[0])beginrdy<=0;state<=0;endenddefault:beginstate<=0;count<=0;rdy<=0;endendcase
end
endmodule// ----- testbench -----
module serial_send_tb;
reg clk,res;
reg[7:0] data_in;
reg en_data_in;
wire TX;
wire rdy;serial_send serial_send(.clk(clk),.res(res),.data_in(data_in),.en_data_in(en_data_in),.TX(TX),.rdy(rdy)
);initial begin$dumpfile("serial_send_tb.vcd"); // save wave file$dumpvars(0,serial_send);
endinitial beginclk<=0;res<=0;data_in<=8'h0a;en_data_in<=0;#17 res<=1;#30 en_data_in<=1;#10 en_data_in<=0;#9000000 $stop;
endalways #5 clk=~clk;endmodule
验证结果如下:
实例3:串口指令处理器
电路原理(来自B站-北交李金城老师的PPT,侵删)
代码实现
完整代码:
serial_amd_pro.v
// 串口指令处理器
`timescale 1ns/10ps
// ----- 定义 -----
module cmd_pro(clk,res,din_pro,en_din_pro,dout_pro,en_dout_pro,rdy
);input clk;
input res;
input[7:0] din_pro; //指令和数据输入端口
input en_din_pro; //输入使能
output[7:0] dout_pro; //指令执行结果
output en_dout_pro; //指令输出使能
output rdy; //串口发送模块空闲标志,0表示空闲parameter add_AB=8'h0a; //指令集!
parameter sub_AB=8'h0b;
parameter and_AB=8'h0c;
parameter or_AB=8'h0d;reg[3:0] state; //主状态机
reg[7:0] cmd_reg,A_reg,B_reg; //存放指令、数据A、数据B
reg[7:0] dout_pro;reg en_dout_pro;always@(posedge clk or negedge res)
if(~res)beginstate<=0;cmd_reg<=0;A_reg<=0;B_reg<=0;dout_pro<=0;en_dout_pro<=0;
end
else begincase(state)0:begin //等指令en_dout_pro<=0;if(en_din_pro)begincmd_reg<=din_pro;state<=1;endend1:begin //收数据Aif(en_din_pro)beginA_reg<=din_pro;state<=2;endend2:begin //收数据Bif(en_din_pro)beginB_reg<=din_pro;state<=3;endend3:begin //根据指令进行处理,即指令译码和执行state<=4;case(cmd_reg)add_AB:begin dout_pro<=A_reg+B_reg;endsub_AB:begin dout_pro<=A_reg-B_reg;endand_AB:begin dout_pro<=A_reg&B_reg;endor_AB:begin dout_pro<=A_reg|B_reg;endendcaseend4:begin //发送指令执行结果if(~rdy)beginen_dout_pro<=1;state<=0;endenddefault:beginstate<=0;endendcase
endendmodule
实例综合:顶层模块封装与验证
电路原理(来自B站-北交李金城老师的PPT,侵删)
makefile
makefile
(在cmd中输入make compile
即可执行命令)
compile:vcs *.v ../04_Serial_Amd_Pro/*.v ../03_Serial_Send/*.v ../02_Serial_Receive/*.v -R -timescale=1ns/10ps +v2k +define+RTL_SAIF
代码实现与验证
完整代码:
UART_top.v
//串口指令处理器
module UART_top(clk,res,RX,TX
);input clk;
input res;
input RX;
output TX;wire[7:0] din_pro; // 定义5个中间信号以连接子模块(从顶层看,一定是wire)
wire en_din_pro;
wire[7:0] dout_pro;
wire en_dout_pro;
wire rdy;serial_send serial_send( //实例化3个子模块,并进行连接,注意!top层只进行连接,不进行逻辑操作.clk(clk),.res(res),.data_in(dout_pro),.en_data_in(en_dout_pro),.TX(TX),.rdy(rdy)
);serial_rec serial_rec(.clk(clk),.res(res),.RX(RX),.data_out(din_pro),.en_data_out(en_din_pro)
);cmd_pro cmd_pro(.clk(clk),.res(res),.din_pro(din_pro),.en_din_pro(en_din_pro),.dout_pro(dout_pro),.en_dout_pro(en_dout_pro),.rdy(rdy)
);endmodule// ----- testbench -----
module UART_top_tb;
reg clk,res;
wire RX;
wire TX;reg[45:0] RX_send; //!!!里面装有串口字节发送数据 16个1+起始位+数据+结束位,即16+1+8+1=26!!!当有3个字节数据时,为16+10+10+10=46bit位宽
assign RX=RX_send; //连接RX
reg[12:0] count; //对系统时钟计数,以满足波特率UART_top UART_top( //同名例化clk,res,RX,TX
);initial begin$dumpfile("UART_top_tb.vcd"); // save wave file$dumpvars(0,UART_top);
endinitial beginclk<=0;res<=0;RX_send<={1'b1,8'h09,1'b0,1'b1,8'h06,1'b0,1'b1,8'h0a,1'b0,16'hffff};count<=0;#17 res<=1;#4000000 $stop;
endalways #5 clk<=~clk;//注意!testbench中串口发送数据的写法!!!让RX_send以波特率节奏不断右移!always@(posedge clk)beginif(count==5000-1)begincount<=0;endelse begincount<=count+1;endif(count==0)begin //循环右移!RX_send[44:0]<=RX_send[45:1];RX_send[45]<=RX_send[0];end
endendmodule
验证如下:
Verilog学习脚印4-状态机(串口)相关推荐
- Verilog学习脚印3-简单状态机(三角波)
Verilog学习脚印3-简单状态机(三角波) 附:verilog语法笔记(持续更新ing) 目录 bash命令 实例1:三角波发生器 电路原理(来自B站-北交李金城老师的PPT,侵删) 代码实现与验 ...
- Verilog学习脚印2-时序逻辑
Verilog学习脚印2-时序逻辑 附:verilog语法笔记(持续更新ing) 目录 触发器基础 bash命令 实例1:计数器 电路原理(来自B站-北交李金城老师的PPT,侵删) 代码实现与验证 实 ...
- Verilog学习脚印1-组合逻辑-反相器
目录 反相器的Verilog实现及仿真验证 VCS+DVE VCS+Verdi 参考致谢 反相器的Verilog实现及仿真验证 inv.v // inv design module inv(A,Y); ...
- Verilog学习笔记——入门
Verilog学习笔记 01 基本逻辑门代码设计与仿真 Veriog基本逻辑门代码结构--以一位反相器为例 ModelSim仿真基本流程 02 组合逻辑代码设计与仿真--多路选择器 二选一逻辑--as ...
- Verilog学习之路(8)— 时序电路的设计
Verilog学习之路(8)- 时序电路的设计 一.前言 时序逻辑电路的输出不仅与当前时刻输入变量的取值有关,而且与电路的原状态,即与过去的输入情况有关. 时序逻辑电路的两个特点: 时序逻辑电路包括组 ...
- Verilog学习手筏(一)
⭐️0. 前言 ⭐️1. 环境准备 本次使用微软的 VS Code进行学习,下面介绍开发环境搭建过程. 安装Verilog HDL和WaveTrace插件即可进行仿真和追波形,具体搭建过程请参照[Li ...
- Verilog学习笔记
Verilog学习笔记 本文根据学习菜鸟教程下Verilog教程总结得到,主要记载一些硬件语言描述下的骚操作,仅供学习. 归约操作符 归约操作符包括:归约与(&),归约与非( ~ &) ...
- python绘制如下图形、小三角形边长20_OpenGL学习脚印_ 绘制移动三角形 - 王定桥的专栏.pdf...
OpenGL学习脚印_ 绘制移动三角形 - 王定桥的专栏 2015/7/20 OpenGL学习脚印: 绘制移动三角形 王定桥的专栏 博客频道 CSDN.NET 登录 | 注册 王定桥的专栏 ...
- Verilog学习笔记-——Verilog模块例化
Verilog学习笔记---Verilog模块例化 在一个模块中引用另一个模块,对其端口进行相关连接,叫做模块例化.模块例化建立了描述的层次.信号端口可以通过位置或名称关联,端口连接也必须遵循一些规则 ...
最新文章
- PPDE英雄帖!广邀全球开发者执开源之桨,汇百川成海
- python3中的一些小改动
- 51Nod 1105 第K大的数 二分答案
- ftp同一主机的多个子进程使用同一个套接字_linux进程通信方式对比
- bootstrapV4.6.0 - 导航栏开发 (案例篇)
- QT 008 UI Add action 的方法
- 在改善人类生活的路上,CV能做的还有很多!
- 高光谱和图像特征相融合的生菜病害识别
- mysql搭建及数据迁移教程
- 合肥师范学院计算机组成原理实验,计算机组成原理实验教学探索
- 超级搜索术3-吸收应用/一键直达
- ActivityManager的作用
- 智能家居系统--KNX现场实施图片01
- pmp中项目经理如何进行目标设定
- Springboot异常--Identify and stop the process that‘s listening on port 9090 or configure this applicat
- Android应用上架国内各大应用市场对应用Logo、应用截图要求整理
- ue4 FString 中文乱码问题
- 嘉兴 机器人仓库 菜鸟_菜鸟物流展示机器人仓库 提高物流运送效率
- java框架要求合同_java毕业设计_springboot框架的合同管理
- hadoop基础----hadoop理论(四)-----hadoop分布式并行计算模型MapReduce详解
热门文章
- hⅰgh怎么读音发音英语_【h_i_gh】什么意思_英语h_i_gh的翻译_音标_读音_用法_例句_在线翻译_有道词典...
- 使用Bosh在OpenStack上部署CloudFoundry碰到的问题
- 2.28 不撞南墙不回头
- 解决三菱MR-J3伺服放大器的AL E6报警,CN1接线问题
- vue3 watch 和watchEffect()
- vivado生成ltx文件命令_Vivado生成及使用edf文件
- 用Jupyter notebook规划旅行路线
- 白鹭引擎能用java吗_白鹭引擎开发3D项目(一)
- 制造企业转型为数字化工厂有哪些挑战
- Matepad pro键盘组合键