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-状态机(串口)相关推荐

  1. Verilog学习脚印3-简单状态机(三角波)

    Verilog学习脚印3-简单状态机(三角波) 附:verilog语法笔记(持续更新ing) 目录 bash命令 实例1:三角波发生器 电路原理(来自B站-北交李金城老师的PPT,侵删) 代码实现与验 ...

  2. Verilog学习脚印2-时序逻辑

    Verilog学习脚印2-时序逻辑 附:verilog语法笔记(持续更新ing) 目录 触发器基础 bash命令 实例1:计数器 电路原理(来自B站-北交李金城老师的PPT,侵删) 代码实现与验证 实 ...

  3. Verilog学习脚印1-组合逻辑-反相器

    目录 反相器的Verilog实现及仿真验证 VCS+DVE VCS+Verdi 参考致谢 反相器的Verilog实现及仿真验证 inv.v // inv design module inv(A,Y); ...

  4. Verilog学习笔记——入门

    Verilog学习笔记 01 基本逻辑门代码设计与仿真 Veriog基本逻辑门代码结构--以一位反相器为例 ModelSim仿真基本流程 02 组合逻辑代码设计与仿真--多路选择器 二选一逻辑--as ...

  5. Verilog学习之路(8)— 时序电路的设计

    Verilog学习之路(8)- 时序电路的设计 一.前言 时序逻辑电路的输出不仅与当前时刻输入变量的取值有关,而且与电路的原状态,即与过去的输入情况有关. 时序逻辑电路的两个特点: 时序逻辑电路包括组 ...

  6. Verilog学习手筏(一)

    ⭐️0. 前言 ⭐️1. 环境准备 本次使用微软的 VS Code进行学习,下面介绍开发环境搭建过程. 安装Verilog HDL和WaveTrace插件即可进行仿真和追波形,具体搭建过程请参照[Li ...

  7. Verilog学习笔记

    Verilog学习笔记 本文根据学习菜鸟教程下Verilog教程总结得到,主要记载一些硬件语言描述下的骚操作,仅供学习. 归约操作符 归约操作符包括:归约与(&),归约与非( ~ &) ...

  8. python绘制如下图形、小三角形边长20_OpenGL学习脚印_ 绘制移动三角形 - 王定桥的专栏.pdf...

    OpenGL学习脚印_ 绘制移动三角形 - 王定桥的专栏 2015/7/20 OpenGL学习脚印: 绘制移动三角形 ­ 王定桥的专栏 ­ 博客频道 ­ CSDN.NET 登录 | 注册 王定桥的专栏 ...

  9. Verilog学习笔记-——Verilog模块例化

    Verilog学习笔记---Verilog模块例化 在一个模块中引用另一个模块,对其端口进行相关连接,叫做模块例化.模块例化建立了描述的层次.信号端口可以通过位置或名称关联,端口连接也必须遵循一些规则 ...

最新文章

  1. PPDE英雄帖!广邀全球开发者执开源之桨,汇百川成海
  2. python3中的一些小改动
  3. 51Nod 1105 第K大的数 二分答案
  4. ftp同一主机的多个子进程使用同一个套接字_linux进程通信方式对比
  5. bootstrapV4.6.0 - 导航栏开发 (案例篇)
  6. QT 008 UI Add action 的方法
  7. 在改善人类生活的路上,CV能做的还有很多!
  8. 高光谱和图像特征相融合的生菜病害识别
  9. mysql搭建及数据迁移教程
  10. 合肥师范学院计算机组成原理实验,计算机组成原理实验教学探索
  11. 超级搜索术3-吸收应用/一键直达
  12. ActivityManager的作用
  13. 智能家居系统--KNX现场实施图片01
  14. pmp中项目经理如何进行目标设定
  15. Springboot异常--Identify and stop the process that‘s listening on port 9090 or configure this applicat
  16. Android应用上架国内各大应用市场对应用Logo、应用截图要求整理
  17. ue4 FString 中文乱码问题
  18. 嘉兴 机器人仓库 菜鸟_菜鸟物流展示机器人仓库 提高物流运送效率
  19. java框架要求合同_java毕业设计_springboot框架的合同管理
  20. hadoop基础----hadoop理论(四)-----hadoop分布式并行计算模型MapReduce详解

热门文章

  1. hⅰgh怎么读音发音英语_【h_i_gh】什么意思_英语h_i_gh的翻译_音标_读音_用法_例句_在线翻译_有道词典...
  2. 使用Bosh在OpenStack上部署CloudFoundry碰到的问题
  3. 2.28 不撞南墙不回头
  4. 解决三菱MR-J3伺服放大器的AL E6报警,CN1接线问题
  5. vue3 watch 和watchEffect()
  6. vivado生成ltx文件命令_Vivado生成及使用edf文件
  7. 用Jupyter notebook规划旅行路线
  8. 白鹭引擎能用java吗_白鹭引擎开发3D项目(一)
  9. 制造企业转型为数字化工厂有哪些挑战
  10. Matepad pro键盘组合键