差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
10._交通灯 [2017/03/23 03:13] zhijun 创建 |
10._交通灯 [2021/10/05 23:40] gongyu |
||
---|---|---|---|
行 1: | 行 1: | ||
- | =====简易交通灯===== | + | ## 简易交通灯 |
本节将向您介绍Verilog语法之中的精髓内容——状态机,并且将利用状态机实现十字路口的交通灯。 | 本节将向您介绍Verilog语法之中的精髓内容——状态机,并且将利用状态机实现十字路口的交通灯。 | ||
\\ | \\ | ||
- | ====硬件说明与实现项目框图==== | + | ### 1. 硬件说明与实现项目框图 |
- | ------- | + | |
+ | // | ||
+ | {{ ::jiaotongdeng.png?300 |}} | ||
+ | // | ||
上图为十字路口交通示意图分之路与主路,要求如下: | 上图为十字路口交通示意图分之路与主路,要求如下: | ||
- | * 交通灯主路上绿灯持续15s的时间,黄灯3s的时间,红灯10s的时间; | + | * 交通灯主路上绿灯持续15s的时间,黄灯3s的时间,红灯10s的时间; |
- | * 交通灯支路上绿灯持续7s的时间, 黄灯持续3秒的时间,红灯18秒的时间; | + | * 交通灯支路上绿灯持续7s的时间, 黄灯持续3秒的时间,红灯18秒的时间; |
+ | |||
+ | // | ||
+ | {{ ::状态机框架.png?300 |}} | ||
+ | // | ||
根据上述要求,状态机设计框架分析如下: | 根据上述要求,状态机设计框架分析如下: | ||
- | * S1:主路绿灯点亮,支路红灯点亮,持续15s的时间; | + | * S1:主路绿灯点亮,支路红灯点亮,持续15s的时间; |
- | * S2:主路黄灯点亮,支路红灯点亮,持续3s的时间; | + | * S2:主路黄灯点亮,支路红灯点亮,持续3s的时间; |
- | * S3:主路红灯点亮,支路绿灯点亮,持续10s的时间; | + | * S3:主路红灯点亮,支路绿灯点亮,持续10s的时间; |
- | * S4:主路红灯点亮,支路黄灯点亮,持续3s的时间; | + | * S4:主路红灯点亮,支路黄灯点亮,持续3s的时间; |
+ | // | ||
+ | {{ ::状态示意图.png?500 |}} | ||
+ | // | ||
+ | |||
+ | ### 2. Verilog代码 | ||
- | ====Verilog代码==== | + | 首先是时钟分频部分: |
- | ------ | + | |
- | 首先是时钟分频部分 | + | |
<code verilog> | <code verilog> | ||
行 53: | 行 63: | ||
//DEFINE PARAMETER | //DEFINE PARAMETER | ||
//******************* | //******************* | ||
- | parameter WIDTH = 3; | + | parameter WIDTH = 3; |
- | parameter N = 5; | + | parameter N = 5; |
//******************* | //******************* | ||
行 70: | 行 80: | ||
//******************** | //******************** | ||
//REGS | //REGS | ||
- | reg [WIDTH-1:0] cnt_p,cnt_n; | + | reg [WIDTH-1:0] cnt_p,cnt_n; |
- | reg clk_p,clk_n; | + | reg clk_p,clk_n; |
assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; | assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; | ||
行 115: | 行 125: | ||
endmodule | endmodule | ||
</code> | </code> | ||
+ | \\ | ||
+ | 接下来就是利用三段式状态机实现的交通灯部分: | ||
+ | <code verilog> | ||
+ | // ******************************************************************** | ||
+ | // >>>>>>>>>>>>>>>>>>>>>>>>> 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 | ||
+ | </code> | ||
\\ | \\ | ||
\\ | \\ | ||
- | ====引脚分配==== | + | |
- | ------- | + | ### 3. 引脚分配 |
小脚丫上正好有4路按键和4路开关,可以用来作为输入信号分别控制数码管的输出。按照下面表格定义输入输出信号 | 小脚丫上正好有4路按键和4路开关,可以用来作为输入信号分别控制数码管的输出。按照下面表格定义输入输出信号 | ||
\\ | \\ | ||
- | ^信号 ^引脚 ^信号 ^引脚 ^ | + | ^信号 ^引脚 ^信号 ^引脚 ^ |
- | |seg_data_1(0) |M7 |seg_data_2(0) |L14 ^ | + | |clk |C1 |rst |L14 ^ |
- | |seg_data_1(1) |M8 |seg_data_2(1) |M13 ^ | + | |out[0] |P2 |out[1] |N2 ^ |
- | |seg_data_1(2) |M9 |seg_data_2(2) |M14 ^ | + | |out[2] |M2 |out[3] |P4 ^ |
- | |seg_data_1(3) |M10 |seg_data_2(3) |N14 ^ | + | |out[4] |N3 |out[5] |M3 ^ |
\\ | \\ | ||
\\ | \\ | ||
- | ^信号 ^引脚 ^信号 ^引脚 ^ | ||
- | |seg_led_1(0) |A10 |seg_led_2(0) |C12 ^ | ||
- | |seg_led_1(1) |C11 |seg_led_2(1) |B14 ^ | ||
- | |seg_led_1(2) |F2 |seg_led_2(2) |J1 ^ | ||
- | |seg_led_1(3) |E1 |seg_led_2(3) |H1 ^ | ||
- | |seg_led_1(4) |E2 |seg_led_2(4) |H2 ^ | ||
- | |seg_led_1(5) |A9 |seg_led_2(5) |B12 ^ | ||
- | |seg_led_1(6) |B9 |seg_led_2(6) |A11 ^ | ||
- | |seg_led_1(7) |F1 |seg_led_2(7) |K1 ^ | ||
- | |seg_led_1(8) |C9 |seg_led_2(8) |A12 ^ | ||
- | \\ | ||
- | 配置好以后编译下载程序。这样可以通过按键或者开关来控制相应的数码管显示数字。如果你想显示16进制的AbCDeF在数码管,可以试试修改程序。这时候一定要定义一个16*9的存储器来初始化。 | ||
- | \\ | ||
- | ====小结==== | + | 配置好以后编译下载程序。您也可以试试修改程序,观察修改代码对于FPGA内部电路所造成的影响。\\ |
- | ------ | + | |
- | 了解了小脚丫数码管的工作原理,在下个实验我们将进行到有趣的时序逻辑。首先是如何控制[[5. 时钟分频|时钟分频]]。 | + | ### 4. 小结 |
+ | |||
+ | 状态机是一类很重要的时序逻辑电路,是许多数字系统的核心部件,掌握状态机的使用是利用FPGA与CPLD进行开发的一项必会技能,本小节的交通灯程序即是利用三段式状态机描述方法实现的,希望读者能够快速掌握这项技能。 | ||