## 简易交通灯 本节将向您介绍Verilog语法之中的精髓内容——状态机,并且将利用状态机实现十字路口的交通灯。 \\ ### 1. 硬件说明与实现项目框图 // {{ ::jiaotongdeng.png?300 |}} // 上图为十字路口交通示意图分之路与主路,要求如下: * 交通灯主路上绿灯持续15s的时间,黄灯3s的时间,红灯10s的时间; * 交通灯支路上绿灯持续7s的时间, 黄灯持续3秒的时间,红灯18秒的时间; // {{ ::状态机框架.png?300 |}} // 根据上述要求,状态机设计框架分析如下: * S1:主路绿灯点亮,支路红灯点亮,持续15s的时间; * S2:主路黄灯点亮,支路红灯点亮,持续3s的时间; * S3:主路红灯点亮,支路绿灯点亮,持续10s的时间; * S4:主路红灯点亮,支路黄灯点亮,持续3s的时间; // {{ ::状态示意图.png?500 |}} // ### 2. Verilog代码 首先是时钟分频部分: //******************************************************** // Copyright(c)2016, STEP FPGA // All rights reserved // File name : divide.v // Module name : divide // Author : STEP // Email : info@stepfpga.com // Data : 2016/08/01 // Version : V1.0 // Description : // // Modification history // ---------------------------------------------------------------------------- // Version // Description // //******************************************************** //******************* //DEFINE MODULE PORT //******************* module divide ( //INPUT clk , rst_n , //OUTPUT clkout ); //******************* //DEFINE PARAMETER //******************* parameter WIDTH = 3; parameter N = 5; //******************* //DEFINE INPUT //******************* input clk,rst_n; //******************* //DEFINE OUTPUT //******************* output clkout; //******************** //OUTPUT ATTRIBUTE //******************** //REGS reg [WIDTH-1:0] cnt_p,cnt_n; reg clk_p,clk_n; assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; //Sequential logic style always @ (posedge clk) begin if(!rst_n) cnt_p<=0; else if (cnt_p==(N-1)) cnt_p<=0; else cnt_p<=cnt_p+1; end always @ (negedge clk) begin if(!rst_n) cnt_n<=0; else if (cnt_n==(N-1)) cnt_n<=0; else cnt_n<=cnt_n+1; end always @ (posedge clk) begin if(!rst_n) clk_p<=0; else if (cnt_p<(N>>1)) clk_p<=0; else clk_p<=1; end always @ (negedge clk) begin if(!rst_n) clk_n<=0; else if (cnt_n<(N>>1)) clk_n<=0; else clk_n<=1; end endmodule \\ 接下来就是利用三段式状态机实现的交通灯部分: // ******************************************************************** // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< // ******************************************************************** // File name : traffic.v // Module name : traffic // Author : STEP // Description : // Web : www.stepfpga.com // // -------------------------------------------------------------------- // Code Revision History : // -------------------------------------------------------------------- // Version: |Mod. Date: |Changes Made: // V1.0 |2017/03/02 |Initial ver // -------------------------------------------------------------------- // Module Function:简易交通灯 module traffic ( clk , //时钟 rst_n , //复位 out //三色led代表交通灯 ); input clk,rst_n; output reg[5:0] out; parameter S1 = 4'b00, //状态机状态编码 S2 = 4'b01, S3 = 4'b10, S4 = 4'b11; parameter time_s1 = 4'd15, //计时参数 time_s2 = 4'd3, time_s3 = 4'd7, time_s4 = 4'd3; //交通灯的控制 parameter led_s1 = 6'b101011, // LED2 绿色 LED1 红色 led_s2 = 6'b110011, // LED2 蓝色 LED1 红色 led_s3 = 6'b011101, // LED2 红色 LED1 绿色 led_s4 = 6'b011110; // LED2 红色 LED1 蓝色 reg [3:0] timecont; reg [1:0] cur_state,next_state; //现态、次态 wire clk1h; //1Hz时钟 //产生1秒的时钟周期 divide #(.WIDTH(32),.N(12000000)) CLK1H ( .clk(clk), .rst_n(rst_n), .clkout(clk1h)); //第一段 同步逻辑 描述次态到现态的转移 always @ (posedge clk1h or negedge rst_n) begin if(!rst_n) cur_state <= S1; else cur_state <= next_state; end //第二段 组合逻辑描述状态转移的判断 always @ (cur_state or rst_n or timecont) begin if(!rst_n) begin next_state = S1; end else begin case(cur_state) S1:begin if(timecont==1) next_state = S2; else next_state = S1; end S2:begin if(timecont==1) next_state = S3; else next_state = S2; end S3:begin if(timecont==1) next_state = S4; else next_state = S3; end S4:begin if(timecont==1) next_state = S1; else next_state = S4; end default: next_state = S1; endcase end end //第三段 同步逻辑 描述次态的输出动作 always @ (posedge clk1h or negedge rst_n) begin if(!rst_n==1) begin out <= led_s1; timecont <= time_s1; end else begin case(next_state) S1:begin out <= led_s1; if(timecont == 1) timecont <= time_s1; else timecont <= timecont - 1; end S2:begin out <= led_s2; if(timecont == 1) timecont <= time_s2; else timecont <= timecont - 1; end S3:begin out <= led_s3; if(timecont == 1) timecont <= time_s3; else timecont <= timecont - 1; end S4:begin out <= led_s4; if(timecont == 1) timecont <= time_s4; else timecont <= timecont - 1; end default:begin out <= led_s1; end endcase end end endmodule \\ \\ ### 3. 引脚分配 小脚丫上正好有4路按键和4路开关,可以用来作为输入信号分别控制数码管的输出。按照下面表格定义输入输出信号 \\ ^信号 ^引脚 ^信号 ^引脚 ^ |clk |C1 |rst |L14 ^ |out[0] |P2 |out[1] |N2 ^ |out[2] |M2 |out[3] |P4 ^ |out[4] |N3 |out[5] |M3 ^ \\ \\ 配置好以后编译下载程序。您也可以试试修改程序,观察修改代码对于FPGA内部电路所造成的影响。\\ ### 4. 小结 状态机是一类很重要的时序逻辑电路,是许多数字系统的核心部件,掌握状态机的使用是利用FPGA与CPLD进行开发的一项必会技能,本小节的交通灯程序即是利用三段式状态机描述方法实现的,希望读者能够快速掌握这项技能。