当前位置: 首页 > news >正文

小梅哥Xilinx FPGA学习笔记16——FSM(状态机)的学习

目录

一、 状态机导读

1.1 理论学习   

1.2 状态机的表示

1.3 状态机编码

1.4 状态机描述方式

二 、实战演练一(来自野火)

2.1 实验目标

2.2 模块框图

2.3 状态转移图绘制

2.4 设计文件

2.5 仿真测试文件

2.6 仿真结果

三、 实战演练二(来自野火)

3.1 实验目标

3.2 模块框图

3.3 状态转移图绘制

3.4 设计文件

3.5 仿真测试文件

3.6 仿真结果

四、 实战演练三(来自小梅哥)

4.1 实验目标

4.2 模块框图

4.3 端口功能描述

4.4 设计文件

4.5 仿真测试文件

4.6 仿真结果

五、 实战演练四(来自小梅哥)

5.1 实验目标

5.2 设计文件

5.2.1 顶层文件

5.2.2 串口接收文件

5.2.3 字符检测模块

5.3 引脚约束文件

5.4 板上验证


一、 状态机导读

       状态机大家一定都听说过,为什么需要状态机呢?通过前面的学习我们都知道FPGA 是并行执行的,如果我们想要处理具有前后顺序的事件该怎么办呢?这时就需要引入状态机了。本文将从原理、实例、应用为大家总结了状态机设计和实现的方法。

1.1 理论学习   

       状态机简写为 FSM Finite State Machine),也称为同步有限状态机,我们一般简称为状态机,之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的,而“有限”则是说状态的个数是有限的。状态机根据影响输出的原因分为两大类,即 Moore 型状态机Mealy 型状态机, Moore 型状态机的输出只和当前状态有关而与输入无关 ;Mealy 型状态机的输出不仅和当前状态有关还和输入有关。

1.2 状态机的表示

        那么状态机该如何表示呢?我们会在一些数据手册中经常看到如下图 所示的图,这种图就是用于表达状态机的状态转移图。有了状态转移图,我们就可以对状态机想要表达的东西一清二楚,包括用代码去实现都会变得很容易,所以说如何根据实际需求设计抽象出符合要求的状态机是非常关键的。

1.3 状态机编码

       状态机可根据控制信号按照预先设定的状态进行状态转移,这就出现了如何对状态进行有效编码的问题。编码方式,最简单的就是直接使用 二进制编码 进行表示,除此之外还有使用 格雷码、独热码 。假设有八个状态从 A H ,利 用不同的编码格式分别如下表所示。

       从上表中可以发现:独热码,每一个状态均使用一个寄存器, 在与状态比较时仅仅需要比较一位, 相比其他译码电路简单;格雷码,所需寄存器数与二 进制码一样,译码复杂,但相邻位只跳动一位,一般用于异步多时钟域多 bit 的转换,如异步 FIFO ;二进制码,最为常见的编码方式,所用寄存器少,译码 较复杂。
       按照 FPGA 厂商给的建议,选择哪一种编码格式是要根据状态机的复杂度、 器件类型以及从非法状态中恢复出来的要求来确定。在使用不同的编码格式生 成出来的 RTL 视图中可以看出二进制比独热码使用更少的寄存器。二进制用 7 个寄存器就可以实现 100 个状态的状态机,但是独热码就需要 100 个寄存器。 但是另一方面,虽然独热码使用更多的寄存器但是其组合逻辑相对简单。一般 CPLD 中,由于提供较多的组合逻辑资源而推荐使用前者,而在 FPGA 中提 供较多的时序逻辑而推荐使用后者。

1.4 状态机描述方式

状态机描述方式,可分为一段式两段式以及三段式
       一段式,整个状态机写到一个 always 模块里面。在该模块中既描述状态转 移,又描述状态的输入和输出。
       两段式,用两个 always 模块来描述状态机。其中一个 always 模块采用同步 时序描述状态转移,另一个模块采用组合逻辑判断状态转移条件(若也使用时序逻辑就称为新二段式),描述状态转 移规律及其输出。
       三段式,在两个 always 模块描述方法基础上,使用三个 always 模块。一个 always 模块采用同步时序描述状态转移,一个 always 采用组合逻辑判断状态转 移条件,描述状态转移规律,另一个 always 模块描述状态输出 ( 可以用组合电路 输出,也可以时序电路输出 )

二 、实战演练一(来自野火)

2.1 实验目标

       我们都在大街见过自动售卖饮料的可乐机,殊不知整个可乐机系统的售卖过程就可以很好的用状态机来实现,为了学习我们先来实现一个简单的可乐机系统。可乐机每次只能投入 1 枚 1 元硬币,且每瓶可乐卖 3 元钱,即投入 3 个硬币就可以让可乐机出可乐,如果投币不够 3 元想放弃投币需要按复位键,否则之前投入的钱不能退回。

2.2 模块框图

       首先必不可少的是时钟和复位信号;其次是投币 1 元的输入信号,我们取名为 pi_money ;可乐机输出我们购买的可乐,取名为 po_cola 。根据上面的分析设计出的 框图如下图 所示。
端口列表与功能总结如下面表格 所示。

2.3 状态转移图绘制

       斜杠左边表达的是状态的输入,斜杠右边表达的是状态的输出,结构非常的简单,各状态之间的功能、跳转的条件、输入输出都能够在状态转移图中非常清楚的表达出来。
1 、输入: 投入 1 元硬币;
2 、输出: 出可乐、不出可乐;
3 、状态: 可乐机中有 0 元、可乐机中有 1 元、可乐机中有 2 元、可乐机中有 3 元。

2.4 设计文件

module simple_fsm(input sys_clk,input sys_rst_n,input pi_money,output reg po_cola);parameter IDLE = 0;//记住独热码,二进制码,格雷码的区别。parameter ONE = 1;parameter TWO = 2;reg [1:0]state;always@(posedge sys_clk or negedge sys_rst_n)if(!sys_rst_n)beginstate <= IDLE; po_cola <= 0;endelse begin    case(state)    IDLE: beginif(pi_money)beginstate <= ONE;po_cola <= 0; //可以使用两个时序逻辑分别描述状态转换和输出。endelsestate <= IDLE;                      endONE:if(pi_money)beginstate <= TWO;po_cola <= 0; endelsestate <= ONE; TWO:if(pi_money)beginstate <= IDLE;po_cola <= 1; endelsestate <= TWO;        default:begin state <= IDLE;po_cola <= 0;endendcaseend   
endmodule

2.5 仿真测试文件

`timescale 1ns / 1ps
module simple_fsm_test();reg sys_clk ;
reg sys_rst_n;
reg pi_money;
wire po_cola;simple_fsm simple_fsm_inst(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.pi_money(pi_money),.po_cola(po_cola));initial   sys_clk = 1;always #10  sys_clk = ~sys_clk;initial beginsys_rst_n = 0;pi_money = 0;#201;sys_rst_n = 1;#20000;pi_money = 1;#20;pi_money = 0;#20000;pi_money = 1;#20;pi_money = 0;#20000;pi_money = 1;#20;pi_money = 0;#20000;$stop;end
endmodule

2.6 仿真结果

三、 实战演练二(来自野火)

3.1 实验目标

      上一部分中的可乐机比较简单,只能投 1 元的硬币,但是我们生活中还有 0.5 元的硬币,所以我们在本章中将可乐机设计的稍微复杂一些,做成既可以投 1 元的硬币也可以投0.5 元的硬币,然后我们把可乐的定价改为 2.5 元一瓶。我们增加了可乐机的复杂度而引入了新的问题: 可乐定价为 2.5 元一瓶,可投入 0.5 元、1 元硬币,投币不够 2.5 元需要按复位键退回钱款,投币超过 2.5 元需找零。

3.2 模块框图

首先时钟和复位信号依然是必不可少的输入信号;输入信号还有投币,除了可以投 1 元外,还可以投 0.5元,所以我们将投币 1 元的输入信号取名为 pi_money_one ,将投币 0.5 元的输入信号取名
pi_money_half;可乐机的输出除了可乐还可能会有找零(找零的结果只有一种即找回0.5元)我们将可乐机输出购买可乐的信号取名为 po_cola,找零的信号取名为po_money。根据上面的分析设计出的框图如下图所示。

端口列表与功能总结如下面表格所示。

3.3 状态转移图绘制

1 、输入: 投入 0.5 元硬币、投入 1 元硬币;
2 、输出: 不出可乐 / 不找零、出可乐 / 不找零、出可乐 / 找零;
3 、状态: 可乐机中有 0 元、可乐机中有 0.5 元、可乐机中有 1 元、可乐机中有 1.5 元、可
乐机中有 2 元、可乐机中有 2.5 元、可乐机中有 3 元。

3.4 设计文件

module hard_fsm(input sys_clk,input sys_rst_n,input pi_money_half,input pi_money_one,output reg po_cola,output reg po_money);parameter IDLE  = 0,//使用二进制码HALF = 1,ONE = 2,ONE_HALF = 3,TWO = 4,TWO_HALF = 5;reg [2:0]state;always@(posedge sys_clk or negedge sys_rst_n)if(!sys_rst_n)beginstate <= IDLE;    endelse begin case(state)IDLE:if(pi_money_half)beginstate <= HALF;endelse if(pi_money_one)beginstate <= ONE;endelse beginstate <= IDLE;endHALF:if(pi_money_half)beginstate <= ONE;endelse if(pi_money_one)beginstate <= ONE_HALF;endelse beginstate <= HALF;endONE:if(pi_money_half)beginstate <= ONE_HALF;endelse if(pi_money_one)beginstate <= TWO;endelse beginstate <= ONE;endONE_HALF:if(pi_money_half)beginstate <= TWO;endelse if(pi_money_one)beginstate <= IDLE;endelse beginstate <= ONE_HALF;end   TWO:if(pi_money_half || pi_money_one)beginstate <= IDLE;endelse beginstate <= TWO;end    default:state <= IDLE;endcaseendalways@(posedge sys_clk or negedge sys_rst_n)//使用两段式状态机写法if(!sys_rst_n)po_cola <= 0;  else if(((state == TWO) && (pi_money_half == 1))||((state ==ONE_HALF) &&(pi_money_one == 1))||((state ==TWO) &&(pi_money_one == 1)))po_cola <= 1;elsepo_cola <= 0;always@(posedge sys_clk or negedge sys_rst_n)if(!sys_rst_n)po_money <= 0;      else if((state == TWO) && (pi_money_one == 1))po_money <= 1;    elsepo_money <= 0;
endmodule

3.5 仿真测试文件

`timescale 1ns/1ns
module hard_fsm_tb();//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************////reg definereg sys_clk;reg sys_rst_n;reg pi_money_one;reg pi_money_half;reg random_data_gen;//wire definewire po_cola;wire po_money;//********************************************************************////***************************** Main Code ****************************////********************************************************************////初始化系统时钟、全局复位initial beginsys_clk = 1'b1;sys_rst_n <= 1'b0;#20sys_rst_n <= 1'b1;end//sys_clk:模拟系统时钟,每 10ns 电平翻转一次,周期为 20ns,频率为 50MHzalways #10 sys_clk = ~sys_clk;//random_data_gen:产生非负随机数 0、1always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)random_data_gen <= 1'b0;elserandom_data_gen <= {$random} % 2;//pi_money_one:模拟投入 1 元的情况always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)pi_money_one <= 1'b0;elsepi_money_one <= random_data_gen;//pi_money_half:模拟投入 0.5 元的情况always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)pi_money_half <= 1'b0;else
//取反是因为一次只能投一个币,即 pi_money_one 和 pi_money_half 不能同时为 1pi_money_half <= ~random_data_gen;//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************////------------------------complex_fsm_inst------------------------hard_fsm hard_fsm_inst(.sys_clk (sys_clk ), //input sys_clk.sys_rst_n (sys_rst_n ), //input sys_rst_n.pi_money_one (pi_money_one ), //input pi_money_one.pi_money_half (pi_money_half ), //input pi_money_half.po_cola (po_cola ), //output po_money.po_money (po_money ) //output po_cola
); endmodule

3.6 仿真结果

四、 实战演练三(来自小梅哥)

4.1 实验目标

实现字符串检测状态机: 为了实现对字符串“ hello ”的检测,首先画出其状态转移图,如下图所示。

由上图可以看出,如果在状态不符合转换条件,那么状态机要么回到初态检测 h 出现,要么回到状态 e (不满足向后转移条件,但是输入字符为‘ h ’), 且每一个状态都有特定的方向,其输出仅由当前状态决定,因此这是一个摩尔型状态机。

4.2 模块框图

4.3 端口功能描述

4.4 设计文件

module hello(input sys_clk,input sys_rst_n,input [7:0]data_in,//输入数据input data_in_valid,//有效数据输入output reg check_ok//检测出来一个hello就出现一个高脉冲
);//定义5个状态localparam CHECK_h = 0,CHECK_e = 1,CHECK_l1 = 2,CHECK_l2 = 3, CHECK_o = 4;reg [2:0]state;//我使用的是新二段式状态机,小梅哥用的是一段式状态机。always@(posedge sys_clk or posedge sys_rst_n)   if(!sys_rst_n)   state <= CHECK_h;    else begincase(state)CHECK_h:beginif(data_in_valid && data_in == "h")state <= CHECK_e;else state <= CHECK_h;                 end    CHECK_e:beginif(data_in_valid && data_in == "e")//千万注意if还有else if的顺序问题,不然可能会造成检测不成功的现象出现。比如出现hhello就无法检测出来。state <= CHECK_l1;else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h;   elsestate <= CHECK_e;      endCHECK_l1:if(data_in_valid && data_in == "l")state <= CHECK_l2;else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h; elsestate <= CHECK_l1;   CHECK_l2:if(data_in_valid && data_in == "l")state <= CHECK_o;else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h; elsestate <= CHECK_l2;  CHECK_o:if(data_in_valid && data_in == "o")state <= CHECK_h;//检测完毕回到起始状态else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h;              elsestate <= CHECK_o;  endcaseend   //输出单独控制逻辑  
always@(posedge sys_clk or posedge sys_rst_n)   if(!sys_rst_n)   check_ok <= 0; else if((state == CHECK_o) && data_in_valid && (data_in == "o"))check_ok <= 1;   else if(state == CHECK_h)check_ok <= 0;  elsecheck_ok <= check_ok;     
endmodule

4.5 仿真测试文件

`timescale 1ns / 1ps
`define CLK_PERIOD 20
module hello_tb();reg sys_clk;
reg sys_rst_n;
reg data_valid;
reg [7:0]data_in;
wire check_ok;hello hello(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.data_in(data_in),.data_in_valid(data_valid),.check_ok(check_ok));initial sys_clk = 1;
always#(`CLK_PERIOD/2) sys_clk = ~sys_clk;initial beginsys_rst_n = 0;data_valid = 0;data_in = 0;#(`CLK_PERIOD*20);sys_rst_n = 1;#(`CLK_PERIOD*20 + 1);repeat(2)begingen_char("I");#(`CLK_PERIOD);gen_char("A");#(`CLK_PERIOD);gen_char("h");#(`CLK_PERIOD);gen_char("e");#(`CLK_PERIOD);gen_char("l");#(`CLK_PERIOD);gen_char("l");#(`CLK_PERIOD); gen_char("h");#(`CLK_PERIOD);gen_char("h");#(`CLK_PERIOD);gen_char("e");#(`CLK_PERIOD);gen_char("l");#(`CLK_PERIOD);gen_char("l");#(`CLK_PERIOD);gen_char("o");#(`CLK_PERIOD);gen_char("e");#(`CLK_PERIOD);gen_char("h");#(`CLK_PERIOD);gen_char("h");#(`CLK_PERIOD);gen_char("o");#(`CLK_PERIOD); end#200;$stop;endtask gen_char;input [7:0]char; begindata_in = char;data_valid = 1'b1;#(`CLK_PERIOD);data_valid = 1'b0;endendtask
endmodule

4.6 仿真结果

五、 实战演练四(来自小梅哥)

5.1 实验目标

       通过上面字符串检测状态机的学习,结合前面章节学习的串口接收模块可以设计一个串口接收字符串检测系统。整个系统的结构框图如下图所示。系 统功能为 FPGA 通过串口接收模块接收 PC 通过串口发送的字符串数据流,然后通过字符串检测模块对字符串进行检测,每次完整接收到“ hello ”字符串就让 LED 灯翻转。

5.2 设计文件

5.2.1 顶层文件

module fsm_hello_test(input sys_clk,input sys_rst_n,input uart_rxd,output reg Led
);wire [7:0]data_in;wire data_in_valid;wire check_ok;zdyz_rs232_rx #(.CLK_FREQ (5000_0000),//波特率设置.UART_BPS (115200))zdyz_rs232_rx(.sys_clk(sys_clk) , //系统时钟.sys_rst_n(sys_rst_n) , //系统复位,低有效.uart_rxd(uart_rxd) , //UART 接收端口.uart_rx_done(data_in_valid), //UART 接收完成信号,接收完成后就代表数据有效.uart_rx_data(data_in) //UART 接收到的数据送给字符检测模块作为输入
);hello hello(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.data_in(data_in),.data_in_valid(data_in_valid),.check_ok(check_ok)
);//每检测一次,LED就要翻转一次
always@(posedge sys_clk or posedge sys_rst_n)if(!sys_rst_n)Led <= 0;else if(check_ok)Led <= ~Led;else Led <= Led;endmodule

5.2.2 串口接收文件

(个人觉得正点原子的串口接收模块比小梅哥的简单易懂,实用)


module zdyz_rs232_rx(input sys_clk , //系统时钟input sys_rst_n , //系统复位,低有效input uart_rxd , //UART 接收端口output reg uart_rx_done, //UART 接收完成信号output reg [7:0] uart_rx_data //UART 接收到的数据
);parameter CLK_FREQ = 5000_0000; //系统时钟频率
parameter UART_BPS = 115200 ; //串口波特率
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //为得到指定波特率,对系统时钟计数 BPS_CNT 次reg uart_rxd_d0;
reg uart_rxd_d1;
reg rx_flag ; //接收过程标志信号
reg [3:0] rx_cnt ; //接收数据位计数器    
reg [15:0] baud_cnt ; //波特率计数器(位宽为16,防止溢出)
reg [7:0 ] rx_data_t ; //接收数据寄存器wire start_flag;//开始接收的标志,下降沿到来。//打两拍:波特率时钟和系统时钟不同步,为异步信号,所以要进行打拍处理,防止产生亚稳态  
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginuart_rxd_d0 <= 1'b0;uart_rxd_d1 <= 1'b0;endelse beginuart_rxd_d0 <= uart_rxd;uart_rxd_d1 <= uart_rxd_d0;end
end  assign start_flag = (uart_rxd_d0 == 0)&&(uart_rxd_d1 == 1);//下降沿到来的表示方法
// rx_flag接收信号的拉高与拉低   
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)rx_flag <= 1'b0;else if(start_flag) //检测到起始位rx_flag <= 1'b1; //接收过程中,标志信号 rx_flag 拉高//在停止位一半的时候,即接收过程结束,标志信号 rx_flag 拉低else if((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX/2 - 1))//rx_flag 要提前拉低,防止其影响下一帧数据的接收rx_flag <= 1'b0;elserx_flag <= rx_flag;end 
//波特率的计数器计数逻辑 
always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n) baud_cnt <= 0;      else if(rx_flag)beginif(baud_cnt == BAUD_CNT_MAX - 1)baud_cnt <= 0;elsebaud_cnt <= baud_cnt + 1;       endelsebaud_cnt <= 0;
end 
//位计数实现逻辑
always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)rx_cnt <= 0;   else if(rx_flag)beginif(baud_cnt == BAUD_CNT_MAX - 1)rx_cnt <= rx_cnt + 1;        elserx_cnt <= rx_cnt;endelserx_cnt <= 0;//其他情况下都为0,所以不用担心计数超过9,且其计数也不会超过9,当rx_flag为0时就不计数了
end
//根据 rx_cnt 来寄存 rxd 端口的数据
always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)rx_data_t <= 0;    else if(rx_flag)begin   //系统处于接收过程时if(baud_cnt == BAUD_CNT_MAX/2 - 1)begin//判断 baud_cnt 是否计数到数据位的中间 case(rx_cnt)1:rx_data_t[0] <= uart_rxd_d1; //寄存数据的最低位2:rx_data_t[1] <= uart_rxd_d1;3:rx_data_t[2] <= uart_rxd_d1;4:rx_data_t[3] <= uart_rxd_d1;5:rx_data_t[4] <= uart_rxd_d1;6:rx_data_t[5] <= uart_rxd_d1;7:rx_data_t[6] <= uart_rxd_d1;8:rx_data_t[7] <= uart_rxd_d1;//寄存数据的高低位default:rx_data_t <= rx_data_t; endcaseendelse rx_data_t <= rx_data_t;endelserx_data_t <= 0; 
end
//给接收完成信号和接收到的数据赋值    
always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin    uart_rx_done <= 0;   uart_rx_data <= 0;end//当接收数据计数器计数到停止位,且 baud_cnt 计数到停止位的中间时else if((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX/2 - 1))beginuart_rx_done <= 1; //拉高接收完成信号uart_rx_data <= rx_data_t;//并对 UART 接收到的数据进行赋值end    else beginuart_rx_done <= 0; uart_rx_data <= uart_rx_data;     end
end    
endmodule

5.2.3 字符检测模块

module hello(input sys_clk,input sys_rst_n,input [7:0]data_in,//输入数据input data_in_valid,//有效数据输入output reg check_ok//检测出来一个hello就出现一个高脉冲
);//定义5个状态localparam CHECK_h = 0,CHECK_e = 1,CHECK_l1 = 2,CHECK_l2 = 3, CHECK_o = 4;reg [2:0]state;//我使用的是新二段式状态机,小梅哥用的是一段式状态机。always@(posedge sys_clk or posedge sys_rst_n)   if(!sys_rst_n)   state <= CHECK_h;    else begincase(state)CHECK_h:beginif(data_in_valid && data_in == "h")state <= CHECK_e;else state <= CHECK_h;                 end    CHECK_e:beginif(data_in_valid && data_in == "e")//千万注意if还有else if的顺序问题,不然可能会造成检测不成功的现象出现。比如出现hhello就无法检测出来。state <= CHECK_l1;else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h;   elsestate <= CHECK_e;      endCHECK_l1:if(data_in_valid && data_in == "l")state <= CHECK_l2;else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h; elsestate <= CHECK_l1;   CHECK_l2:if(data_in_valid && data_in == "l")state <= CHECK_o;else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h; elsestate <= CHECK_l2;  CHECK_o:if(data_in_valid && data_in == "o")state <= CHECK_h;//检测完毕回到起始状态else if(data_in_valid && data_in == "h")state <= CHECK_e; else if(data_in_valid)state <= CHECK_h;              elsestate <= CHECK_o;  endcaseend   //输出单独控制逻辑  
always@(posedge sys_clk or posedge sys_rst_n)   if(!sys_rst_n)   check_ok <= 0; else if((state == CHECK_o) && data_in_valid && (data_in == "o"))check_ok <= 1;   else if(state == CHECK_h)check_ok <= 0;  elsecheck_ok <= check_ok;     
endmodule

5.3 引脚约束文件

set_property PACKAGE_PIN U18 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports Led]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports uart_rxd]
set_property PACKAGE_PIN F20 [get_ports sys_rst_n]
set_property PACKAGE_PIN K16 [get_ports uart_rxd]
set_property PACKAGE_PIN G17 [get_ports Led]

5.4 板上验证

本文所有程序均经过板上验证过,均正常,放心使用参考。

相关文章:

小梅哥Xilinx FPGA学习笔记16——FSM(状态机)的学习

目录 一、 状态机导读 1.1 理论学习 1.2 状态机的表示 1.3 状态机编码 1.4 状态机描述方式 二 、实战演练一&#xff08;来自野火&#xff09; 2.1 实验目标 2.2 模块框图 2.3 状态转移图绘制 2.4 设计文件 2.5 仿真测试文件 2.6 仿真结果 三、 实战演练二&…...

vol----学习随记!!!

目录 一、代码生成1.先新建一个功能的对应的代码配置各项解释&#xff1a; 2.后设置配置菜单3.再点保存&#xff0c;生成vue页面&#xff0c;生成model&#xff0c;生成业务类4.再通过菜单设置编写系统菜单 一、代码生成 1.先新建一个功能的对应的代码配置 各项解释&#xff…...

HarmonyOS4.0系统性深入开发10卡片事件能力说明

卡片事件能力说明 ArkTS卡片中提供了postCardAction()接口用于卡片内部和提供方应用间的交互&#xff0c;当前支持router、message和call三种类型的事件&#xff0c;仅在卡片中可以调用。 接口定义&#xff1a;postCardAction(component: Object, action: Object): void 接口…...

openGauss学习笔记-181 openGauss 数据库运维-升级-升级流程

文章目录 openGauss学习笔记-181 openGauss 数据库运维-升级-升级流程 openGauss学习笔记-181 openGauss 数据库运维-升级-升级流程 本章介绍升级到该版本的主要升级过程。 图 1 升级流程图 说明&#xff1a; 本文档中描述的时间仅供参考&#xff0c;实际操作时间以现场情况…...

提前应对威胁

通过新的《2023-2028 年荷兰国际网络安全战略》&#xff0c;荷兰政府在面对国家和犯罪分子持续构成的网络威胁时展现了责任和机构。它渴望将民主、人权和规范放在首位&#xff0c;并寻求维护全球开放、自由和安全的互联网。该战略明确了政府在国内实施打击的意愿和能力&#xf…...

C语言与人生:数组交换和二分查找

少年们&#xff0c;大家好。我是博主那一脸阳光&#xff0c;今天和分享数组交换和二分查找。 前言&#xff1a;探索C语言中的数组交换操作与二分查找算法 在计算机编程领域&#xff0c;特别是以C语言为代表的低级编程语言中&#xff0c;对数据结构的理解和熟练运用是至关重要的…...

Python实现【亚马逊商品】数据采集

前言 亚马逊公司&#xff0c;是美国最大的一家网络电子商务公司&#xff0c;位于华盛顿州的西雅图 是网络上最早开始经营电子商务的公司之一&#xff0c;亚马逊成立于1994年 今天教大家用Python批量采集亚马逊平台商品数据&#xff08;完整代码放在文末&#xff09; 地址&#…...

Git使用教程 gittutorial

该教程对该文章的翻译&#xff1a;https://git-scm.com/docs/gittutorial 本文介绍怎用使用 Git 导入新的工程、修改文件及如何其他人同步开发。 首先&#xff0c; 可以使用以下指令获取文档帮助 git help log笔者注&#xff1a;不建议看这个文档&#xff0c;标准的语法介绍…...

有了向量数据库,我们还需 SQL 数据库吗?

“除了向量数据库外&#xff0c;我是否还需要一个普通的 SQL 数据库&#xff1f;” 这是我们经常被问到的一个问题。如果除了向量数据以外&#xff0c;用户还有其他标量数据信息&#xff0c;那么其业务可能需要在进行语义相似性搜索前先根据某种条件过滤数据&#xff0c;例如&a…...

信息网络协议基础-IPv6协议

文章目录 概述为什么引入IP服务模型IPv4的可扩展性问题解决方法***CIDR(Classless Inter-Domain Routing, 无类别域间寻路)前缀汇聚***前缀最长匹配***NAT(网络地址转换)存在的问题解决方案路由表配置***局限性IPv6协议头标IPv6地址表示前缀类型单播地址链路局部地址(Link-Loca…...

VC++ ado 实现单表CURD

继续修改前文的资产管理源码; 新建一个数据库sds;把代码中的数据库连接改为连接此库; 新建下图一个表; 把之前的资产类别管理对话框改为下图所示;对话框ID也改为下图; 资产类别管理菜单和ID改为下图; 直接修改资产类别管理对话框类不太方便,新建一个对话框类,没有关联…...

C#使用switch多路选择语句判断何为季节

目录 一、 switch语句 二、示例 三、生成 一、 switch语句 switch语句是多路选择语句&#xff0c;它通过一个表达式的值来使程序从多个分支中选取一个用于执行的分支。 switch表达式的值只可以是整型、字符串、枚举和布尔类型。 switch语句中多个case可以使用一个break。 在…...

可爱的魔法曲线 Lovely Magical Curves(12年开始只有5个人AC)

一起来交流编程吧&#xff01;【CSDN app】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&k3svdDJTlkD76TRRShbxYCYK1zK1c8cyF&authKeyv1pxp6rS8AA4SRy7bflJl9LIwp8d5v0HOudw%2BDxHiWDRqZ1LzjeoBJH1Z1EXnl35&noverify0&group_code546881376 可爱的魔法…...

通过C++程序实现光驱的自动化刻录和读取

文章目录 ISO文件格式光盘的基本概念光盘种类特点DVDR光盘使用windows调用Linux调用Linux平台下用到的C库:读取设备驱动列表向光驱中写文件 数字存储媒体快速发展的今天&#xff0c;光驱的使用已经不像以前那样普及了。但是在数据备份、安装软件和操作系统、旧设备兼容等领域还…...

【电商项目实战】商品详情显示与Redis存储购物车信息

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《电商项目实战》。&#x1f3af;&#x1f3af; &am…...

概率论基础

1.概率论 1.1 随机事件与概率 1.1.1 基本概念 ​ 样本点(sample point)&#xff1a; 称为试验 S S S的可能结果为样本点&#xff0c;用 ω \omega ω表示。 ​ 样本空间(sample space)&#xff1a;称试验 S S S的样本点构成的集合为样本空间&#xff0c;用 Ω \Omega Ω表示…...

Mac电脑CMake安装和配置

1.从CMake官网下载dmg文件并且安装 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a43f1462b5f743b4ba0bf5302ee76066.png)...

FormData传送复杂数据

FormData 是一个用于创建表单数据对象的 JavaScript 类。它通常用于通过 JavaScript 发送表单数据&#xff0c;尤其是用于发送 AJAX 请求时非常有用。 使用 FormData 可以方便地构建一个以 multipart/form-data 格式提交的表单数据&#xff0c;这允许你在发送 XMLHttpRequest …...

力扣回溯算法-电话号码的字母组合

力扣第17题&#xff0c;电话号码的字母组合 题目 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 .电话号码的字母组合 示例: 输入&#xff1a;“2…...

运维面试笔试题

目录 shell脚本 nginx 数据库mysql k8s(kubernetes) 安全与防护 网络TCP/IP shell脚本 1 通过正则表达式匹配文本...

Oracle database 静默安装 oracle12c 一键安装 12.1.0.2

基于oracle安装包中应答文件实现一键安装 注意此安装脚本基于12.1.0.2 安装包 原始安装包结构为两个压缩包 此脚本使用安装包为原始压缩包解压后、 重新封装为一个.zip压缩包 建议在linux 环境下解压重新压缩后 使用该脚本 支持环境: Linux :centerOS 7 oracle :12.1.0.…...

【Java EE初阶三 】线程的状态与安全(上)

1. join方法与多线程 1.1 初识多线程 为了提高cpu得利用率&#xff0c;因此就引入了多个线程的概念&#xff1b;即每个线程负责完成整个程序的一部分工作即可。 写一个代码&#xff0c;让主线程&#xff0c;创建一个新的线程&#xff0c;由新线程负责完成运算&#xff08;12。…...

英飞凌TC3xx之一起认识GTM系列(五)如何实现GTM与DSADC关联的配置

英飞凌TC3xx之一起认识GTM系列(五)如何实现GTM与DSADC关联的配置 1 GTM与DSADC的连接1.1 EDSADC 到 GTM 的连接1.1.1 工作原理说明1.1.2 应用举例1.2 GTM 到 EDSADC 的连接1.2.1 工作原理说明1.2.2 应用举例2 总结编者按:笔者在从事这部分开发工作的时候,看着手册上的各种通…...

小兔鲜儿 uniapp - 购物车模块

目录 加入购物车​ 接口相关​ 购物车列表​ 静态结构​ 登录状态​ 列表渲染​ 删除购物车 接口相关​ 参考代码 修改商品信息​ 接口相关​ ​修改商品数量​ 修改商品选中/全选​ 底部结算信息​ 计算总钱数(总金额)​ 带返回按钮的购物车​ 完成加入购物车…...

Python使用PyMySql增删改查Mysql数据库

PyMysql简介 PyMysql是Python中用于连接MySQL数据库的一个第三方库&#xff0c;它实现了MySQL客户端/服务器协议&#xff0c;使得Python程序能够与MySQL服务器进行交互。由于Python 2的mysql-python&#xff08;又称mysqldb&#xff09;模块在Python 3上支持不够完善&#xff0…...

前端实现websocket类封装

随着Web应用程序的发展&#xff0c;越来越多的人开始利用Websocket技术来构建实时应用程序。Websocket是一种在客户端和服务器之间建立持久连接的协议。这种协议可以在一个单独的连接上实现双向通信。与HTTP请求-响应模型不同&#xff0c;Websocket允许服务器自主地向客户端发送…...

鸿蒙开发中的一些小问题

这是我在学习鸿蒙开发中遇见的小问题 Q1&#xff1a;This custom component must have a build function. <etsLint>Q2&#xff1a;page_title is not translated into en_US(American English)Q3&#xff1a;Module "../CustomComponent/CustomButton" declar…...

OpenCV-12绘制图像

OpenCV提供了许多绘制图像的API&#xff0c;可以在图像上绘制各种图形&#xff0c;例如直线&#xff0c;矩形&#xff0c;圆&#xff0c;椭圆等图形。 一、画直线 利用API line&#xff08;img, pt1, pt2, color, thickness, lineType, shift&#xff09;可以绘制直线。 其中…...

“2023年的技术发展与个人成长:回顾与展望“

文章目录 每日一句正能量前言工作生活未来展望后记 每日一句正能量 凡事顺其自然&#xff0c;遇事处于泰然&#xff0c;得意之时淡然&#xff0c;失意之时坦然&#xff0c;艰辛曲折必然&#xff0c;历尽沧桑悟然。 前言 在这快速发展的信息时代&#xff0c;技术的进步和创新不…...

算法逆袭之路(1)

11.29 开始跟进算法题进度! 每天刷4题左右 ,一周之内一定要是统一类型 而且一定稍作总结, 了解他们的内在思路究竟是怎样的!! 12.24 一定要每天早中晚都要复习一下 早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义 12.26/27&#xff1a; 斐波那契数 爬…...

2023.12.31每日一题

LeetCode每日一题 2023年的最后一题 1154.一年中的第几天 1154. 一年中的第几天 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个字符串 date &#xff0c;按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1&#xff1a; 输入&a…...

Flink实时电商数仓(八)

用户域登录各窗口汇总表 主要任务&#xff1a;从kafka页面日志主题读取数据&#xff0c;统计 七日回流用户&#xff1a;之前活跃的用户&#xff0c;有一段时间不活跃了&#xff0c;之后又开始活跃&#xff0c;称为回流用户当日独立用户数&#xff1a;同一个用户当天重复登录&a…...

Python Pymysql实现数据存储

什么是 PyMySQL&#xff1f; PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库&#xff0c;Python2 中则使用mysqldb。 PyMySQL 遵循 Python 数据库 API v2.0 规范&#xff0c;并包含了 pure-Python MySQL 客户端库。 PyMySQL 安装 在使用 PyMySQL 之前&#xf…...

软件测试/测试开发丨Python 常用第三方库 pymysql

pymysql 概述 Python 的数据库接口标准是 Python DB-APIPyMySQL 是从 Python 连接到 MySQL 数据库服务器的接口PyMySQL 的目标是成为 MySQLdb 的替代品官方文档&#xff1a;pymysql.readthedocs.io/ pymysql 安装 使用 pip 安装使用 Pycharm 界面安装 pip install pymysqlp…...

第二节 linux操作系统安装与配置

一&#xff1a;Vmware虚拟机安装与使用   ①VMware是一个虚拟PC的软件&#xff0c;可以在现有的操作系统上虚拟出一个新的硬件环境&#xff0c;相当于模拟出一台新的PC &#xff0c;以此来实现在一台机器上真正同时运行多个独立的操作系统。   ②VMware主要特点&#xff1a…...

ChatGPT 对SEO的影响

ChatGPT 的兴起是否预示着 SEO 的终结&#xff1f; 一点也不。事实上&#xff0c;如果使用得当&#xff0c;它可以让你的 SEO 工作变得更加容易。 强调“正确使用时”。 你可以使用ChatGPT来帮助进行关键字研究的头脑风暴部分、重新措辞你的内容、生成架构标记等等。 但你不…...

光伏逆变器MPPT的作用、原理及算法

MPPT是逆变器非常核心的技术&#xff0c;MPPT电压在进行光伏电站设计时一项非常关键的参数。 一、什么是MPPT&#xff1f; &#xff08;单块光伏组件的I-V、P-V曲线&#xff09; 上图中&#xff0c;光伏组件的输出电压和电流遵循I-V曲线(绿色)、P-V曲线(蓝色)&#xff0c;如果…...

一文详解pyspark常用算子与API

rdd.glom() 对rdd的数据进行嵌套&#xff0c;嵌套按照分区来进行 rdd sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9], 2)print(rdd.glom().collect()) 输出&#xff1a;[[1,2,3,4],[5,6,7,8,9]] 参考 PySpark基础入门&#xff08;2&#xff09;&#xff1a;RDD及其常用算子…...

使用Rollup 搭建开发环境

1 什么是Rollup Rollup 是一个用于 JavaScript 的模块打包工具&#xff0c;它将小的代码片段编译成更大、更复杂的代码&#xff0c;例如库或应用程序。它使用 JavaScript 的 ES6 版本中包含的新标准化代码模块格式&#xff0c;而不是以前的 CommonJS 和 AMD 等特殊解决方案。(开…...

ubuntu:beyond compare 4 This license key has been revoked 解决办法

https://www.cnblogs.com/zhibei/p/12095431.html 错误如图所示&#xff1a; 解决办法&#xff1a; &#xff08;1&#xff09;先用find命令找到bcompare所在位置&#xff1a;sudo find /home/ -name *bcompare &#xff08;2&#xff09;进入 /home/whf/.config,删除/bco…...

华为交换机生成树STP配置案例

企业内部网络怎么防止网络出现环路&#xff1f;学会STP生成树技术就可以解决啦。 STP简介 在二层交换网络中&#xff0c;一旦存在环路就会造成报文在环路内不断循环和增生&#xff0c;产生广播风暴&#xff0c;从而占用所有的有效带宽&#xff0c;使网络变得无法正常通信。 在…...

Avalonia框架下实现热更新

在Avalonia框架下实现热更新&#xff08;也称为动态加载或模块化更新&#xff09;&#xff0c;通常涉及程序集的动态加载与卸载&#xff0c;以及UI元素、视图模型或其他应用程序逻辑部分的实时替换。由于Avalonia本身是一个跨平台的GUI框架&#xff0c;并没有直接内置热更新机制…...

适用于各种危险区域的火焰识别摄像机,实时监测、火灾预防、安全监控,为安全保驾护航

火灾是一种极具破坏力的灾难&#xff0c;对人们的生命和财产造成了严重的威胁。为了更好地预防和防范火灾&#xff0c;火焰识别摄像机作为一种先进的监控设备&#xff0c;正逐渐受到人们的重视和应用。本文将介绍火焰识别摄像机在安全监控和火灾预防方面的全面应用方案。 一、火…...

react-router-dom5升级到6

前言 升级前版本为5.1.2 下载与运行 下载 npm install react-router-dom6运行 运行发现报错: 将node_modules删除&#xff0c;重新执行npm i即可 运行发现如下报错 这是因为之前有引用react-router-dom.min&#xff0c;v6中取消了该文件&#xff0c;所以未找到文件导致报错。…...

Linux调试工具—gdb

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;HEART BEAT—YOASOBI 2:20━━━━━━️&#x1f49f;──────── 5:35 &#x1f504; ◀️ ⏸ ▶️ ☰ …...

SpringCloud(H版alibaba)框架开发教程之nacos做配置中心——附源码(2)

上篇主要讲了使用eureka&#xff0c;zk&#xff0c;nacos当注册中心 这篇内容是nacos配置中心 代码改动部分mysql驱动更新到8.0&#xff0c;数据库版本升级到了8.0&#xff0c;nacos版本更新到了2.x nacos2.x链接 链接&#xff1a;https://pan.baidu.com/s/11nObzgTjWisAfOp…...

网络摄像头爆破实战

*** 重要说明&#xff1a;仅用于交流网络安全测试技术&#xff0c;并唤起大家对网络安全的重视&#xff0c;如用本文的技术干违法的事情&#xff0c;博主概不负责。*** 文章目录 前言1. 发现摄像头2. 发现端口3. 确定品牌信息4. 确定RTSP地址5. 获取视频流6. 获取密码7. 再次获…...

亚信安慧AntDB数据并行加载工具的实现(二)

3.功能性说明 本节对并行加载工具的部分支持的功能进行简要说明。 1) 支持表类型 并行加载工具支持普通表、分区表。 2) 支持指定导入字段 文件中并不是必须包含表中所有的字段&#xff0c;用户可以指定导入某些字段&#xff0c;但是指定的字段数要和文件中的字段数保持一…...

【Java进阶篇】JDK新版本中的新特性都有哪些

JDK新版本中的新特性都有哪些 ✔️经典解析✔️拓展知识仓✔️本地变量类型推断✔️Switch 表达式✔️Text Blocks✔️Records✔️封装类✔️instanceof 模式匹配✔️switch 模式匹配 ✅✔️虚拟线程 ✔️经典解析 JDK 8中推出了Lambda表达式、Stream、Optional、新的日期API等…...

力扣labuladong一刷day49天迪杰斯特拉

力扣labuladong一刷day49天迪杰斯特拉 文章目录 力扣labuladong一刷day49天迪杰斯特拉一、743. 网络延迟时间二、1631. 最小体力消耗路径三、1514. 概率最大的路径 一、743. 网络延迟时间 题目链接&#xff1a;https://leetcode.cn/problems/network-delay-time/ 使用迪杰斯特…...