赞
踩
目录
- 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)begin
- state <= IDLE;
- po_cola <= 0;
- end
- else begin
- case(state)
- IDLE: begin
- if(pi_money)begin
- state <= ONE;
- po_cola <= 0; //可以使用两个时序逻辑分别描述状态转换和输出。
- end
- else
- state <= IDLE;
- end
- ONE:
- if(pi_money)begin
- state <= TWO;
- po_cola <= 0;
- end
- else
- state <= ONE;
- TWO:
- if(pi_money)begin
- state <= IDLE;
- po_cola <= 1;
- end
- else
- state <= TWO;
- default:begin state <= IDLE;po_cola <= 0;end
- endcase
- end
- endmodule
- `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
- begin
- sys_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
端口列表与功能总结如下面表格所示。
- 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)begin
- state <= IDLE;
- end
- else begin
- case(state)
- IDLE:if(pi_money_half)begin
- state <= HALF;
- end
- else if(pi_money_one)begin
- state <= ONE;
- end
- else begin
- state <= IDLE;
- end
- HALF:if(pi_money_half)begin
- state <= ONE;
- end
- else if(pi_money_one)begin
- state <= ONE_HALF;
- end
- else begin
- state <= HALF;
- end
- ONE:if(pi_money_half)begin
- state <= ONE_HALF;
- end
- else if(pi_money_one)begin
- state <= TWO;
- end
- else begin
- state <= ONE;
- end
- ONE_HALF:if(pi_money_half)begin
- state <= TWO;
- end
- else if(pi_money_one)begin
- state <= IDLE;
- end
- else begin
- state <= ONE_HALF;
- end
- TWO:if(pi_money_half || pi_money_one)begin
- state <= IDLE;
- end
- else begin
- state <= TWO;
- end
- default:state <= IDLE;
- endcase
- end
-
- always@(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;
- else
- po_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;
- else
- po_money <= 0;
- endmodule
- `timescale 1ns/1ns
- module hard_fsm_tb();
-
- //********************************************************************//
- //****************** Parameter and Internal Signal *******************//
- //********************************************************************//
-
- //reg define
- reg sys_clk;
- reg sys_rst_n;
- reg pi_money_one;
- reg pi_money_half;
- reg random_data_gen;
-
- //wire define
- wire po_cola;
- wire po_money;
-
- //********************************************************************//
- //***************************** Main Code ****************************//
- //********************************************************************//
-
- //初始化系统时钟、全局复位
- initial begin
- sys_clk = 1'b1;
- sys_rst_n <= 1'b0;
- #20
- sys_rst_n <= 1'b1;
- end
-
- //sys_clk:模拟系统时钟,每 10ns 电平翻转一次,周期为 20ns,频率为 50MHz
- always #10 sys_clk = ~sys_clk;
-
- //random_data_gen:产生非负随机数 0、1
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- random_data_gen <= 1'b0;
- else
- random_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;
- else
- pi_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 不能同时为 1
- pi_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
- 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 begin
- case(state)
- CHECK_h:begin
- if(data_in_valid && data_in == "h")
- state <= CHECK_e;
- else
- state <= CHECK_h;
- end
- CHECK_e:begin
- if(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;
- else
- state <= CHECK_e;
- end
- CHECK_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;
- else
- state <= 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;
- else
- state <= 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;
- else
- state <= CHECK_o;
- endcase
- end
- //输出单独控制逻辑
- 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;
- else
- check_ok <= check_ok;
- endmodule
-
- `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
- begin
- sys_rst_n = 0;
- data_valid = 0;
- data_in = 0;
- #(`CLK_PERIOD*20);
- sys_rst_n = 1;
- #(`CLK_PERIOD*20 + 1);
- repeat(2)
- begin
- gen_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;
- end
- task gen_char;
- input [7:0]char;
- begin
- data_in = char;
- data_valid = 1'b1;
- #(`CLK_PERIOD);
- data_valid = 1'b0;
- end
- endtask
- endmodule
- 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
(个人觉得正点原子的串口接收模块比小梅哥的简单易懂,实用)
-
- 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) begin
- if(!sys_rst_n) begin
- uart_rxd_d0 <= 1'b0;
- uart_rxd_d1 <= 1'b0;
- end
- else begin
- uart_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) begin
- if(!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;
- else
- rx_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)begin
- if(baud_cnt == BAUD_CNT_MAX - 1)
- baud_cnt <= 0;
- else
- baud_cnt <= baud_cnt + 1;
- end
- else
- baud_cnt <= 0;
- end
- //位计数实现逻辑
- always @(posedge sys_clk or negedge sys_rst_n)begin
- if(!sys_rst_n)
- rx_cnt <= 0;
- else if(rx_flag)begin
- if(baud_cnt == BAUD_CNT_MAX - 1)
- rx_cnt <= rx_cnt + 1;
- else
- rx_cnt <= rx_cnt;
- end
- else
- rx_cnt <= 0;//其他情况下都为0,所以不用担心计数超过9,且其计数也不会超过9,当rx_flag为0时就不计数了
- end
- //根据 rx_cnt 来寄存 rxd 端口的数据
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(!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;
- endcase
- end
- else
- rx_data_t <= rx_data_t;
- end
- else
- rx_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))begin
- uart_rx_done <= 1; //拉高接收完成信号
- uart_rx_data <= rx_data_t;//并对 UART 接收到的数据进行赋值
- end
- else begin
- uart_rx_done <= 0;
- uart_rx_data <= uart_rx_data;
- end
- end
- endmodule
- 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 begin
- case(state)
- CHECK_h:begin
- if(data_in_valid && data_in == "h")
- state <= CHECK_e;
- else
- state <= CHECK_h;
- end
- CHECK_e:begin
- if(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;
- else
- state <= CHECK_e;
- end
- CHECK_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;
- else
- state <= 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;
- else
- state <= 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;
- else
- state <= CHECK_o;
- endcase
- end
- //输出单独控制逻辑
- 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;
- else
- check_ok <= check_ok;
- endmodule
-
- 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]
本文所有程序均经过板上验证过,均正常,放心使用参考。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。