赞
踩
首先,简要阐述一下本次设计所实现的基本功能。
系统输入两组时钟,一个是50M时钟,一个是1HZ时钟,另外,系统还有一个复位信号,一个拨码开关信号。输出两组LED灯,分别表示东西方向、南北方向的红绿灯。每组灯为6位宽,表示各个方向的红、黄、绿灯。示意图如下所示:
要实现:
东西方向红灯亮,南北方向绿灯亮,保持35S;
东西方向红灯亮,南北方向黄灯亮,保持5S;
东西方向绿灯亮,南北方向红灯亮,维持35S;
东西方向黄灯亮,南北方向红灯亮,维持5S。
如此反复循环。
交通灯的自动工作受到拨码开关的控制,开关拨上时,系统正常工作,否则,全部亮红灯。各个状态的时间倒计时会通过数码管显示出来,数码管的高两位显示的是倒计时的时间,后六位可以显示任意指定的数字(可以是日期,可以是学号,等等)
下面讲解一下verilog实现的过程:
还是采用自顶层向下的设计思想,整体的原理图如下:
分为交通灯控制模块,和数码管显示模块。数码管显示模块的内容之前已经介绍过,这里不再详细介绍。但是这次使用的数码管,在硬件上和之前有所不同,但是大致的原理一样。所以这里只给出代码:
- module segshow(
- input sys_clk,sys_rest,
- input [26:0] shu,
- output reg [2:0] sel,
- output reg [6:0] seg_led
- );
-
- //parameter MSNUM=14'd50000; //实物使用这个参数
- parameter MSNUM=14'd2; //仿真使用这个参数
-
- reg [12:0] MSCNT;
- reg MS_flag;
- reg [3:0] num_display;
-
- reg [2:0] sel_num; //选择哪一位数码管被点亮
- //wire define
- wire [3:0] shu0 ; // 个位数
- wire [3:0] shu1 ; // 十位数
- wire [3:0] shu2 ; // 百位数
- wire [3:0] shu3 ; // 千位数
- wire [3:0] shu4 ; // 万位数
- wire [3:0] shu5 ; // 十万位数
- wire [3:0] shu6 ; // 百万位数
- wire [3:0] shu7 ; // 千万位数
-
-
- //提取显示数值所对应的十进制数的各个位
- assign shu0 = shu % 4'd10; // 个位数
- assign shu1 = shu / 4'd10 % 4'd10 ; // 十位数
- assign shu2 = shu / 7'd100 % 4'd10 ; // 百位数
- assign shu3 = shu / 10'd1000 % 4'd10 ; // 千位数
- assign shu4 = shu / 14'd10000 % 4'd10; // 万位数
- assign shu5 = shu / 17'd100000%4'd10; // 十万位数
- assign shu6 = shu / 20'd1000000%4'd10; // 百万位数
- assign shu7 = shu / 23'd10000000; // 千万位数
-
-
- always @(posedge sys_clk or negedge sys_rest) begin //产生1ms脉冲
- if(!sys_rest)
- begin
- MSCNT<=13'd0;
- MS_flag<=1'b0;
- end
- else if(MSCNT==MSNUM-1)
- begin
- MSCNT<=13'd0;
- MS_flag<=1'b1;
- end
- else
- begin
- MSCNT<=MSCNT+1;
- MS_flag<=1'b0;
- end
- end
- always @(posedge sys_clk or negedge sys_rest) begin
- if(!sys_rest)
- sel_num<=0;
- else if(MS_flag)
- begin
- if(sel_num<3'd7)
- sel_num<=sel_num+1;
- else
- sel_num<=0;
- end
- else
- sel_num<=sel_num;
- end
-
- always @(posedge sys_clk or negedge sys_rest) begin
- if(!sys_rest)
- sel<=3'b000;
- else
- begin
- case(sel_num)
- 3'd0: begin
- sel<= 3'b000; //显示数码管最低位
- num_display<=shu0;
- end
- 3'd1: begin
- sel<= 3'b001; //显示数码管第1位
- num_display<=shu1;
- end
- 3'd2: begin
- sel<= 3'b010; //显示数码管第2位
- num_display<=shu2;
- end
- 3'd3: begin
- sel<= 3'b011; //显示数码管第3位
- num_display<=shu3;
- end
- 3'd4: begin
- sel<= 3'b100; //显示数码管第4位
- num_display<=shu4;
- end
- 3'd5: begin
- sel<= 3'b101; //显示数码管第5位
- num_display<=shu5;
- end
- 3'd6: begin
- sel<= 3'b110;
- num_display<=shu6;
- end
- 3'd7: begin
- sel<= 3'b111; //显示数码管最高位
- num_display<=shu7;
- end
- default sel<= 3'b000;
- endcase
- end
- end
-
- always @(posedge sys_clk or negedge sys_rest) begin
- if(!sys_rest)
- seg_led<=7'b0111111;
- else
- begin
- case(num_display)
- 4'h0 : seg_led <= 7'b0111111;//0
- 4'h1 : seg_led <= 7'b0000110;//1
- 4'h2 : seg_led <= 7'b1011011;//2
- 4'h3 : seg_led <= 7'b1001111;//3
- 4'h4 : seg_led <= 7'b1100110;//4
- 4'h5 : seg_led <= 7'b1101101;//5
- 4'h6 : seg_led <= 7'b1111101;//6
- 4'h7 : seg_led <= 7'b0000111;//7
- 4'h8 : seg_led <= 7'b1111111;//8
- 4'h9 : seg_led <= 7'b1101111;//9
- default : seg_led <= 7'b0111111;//0
- endcase
- end
- end
-
- endmodule
那么重点是LED的控制逻辑。这里的控制,主要用到了状态机,我用的是二段式状态机,先给出代码,再根据代码讲解。
- module jtd_led(
- clk_50m,clk_1hz,rst,k,light1,light2,data
- );
- input clk_50m;
- input clk_1hz;
- input rst;
- input k; //手动控制信号
- output [5:0] light1; //东西方向的灯 绿 黄 红 绿 黄 红
- output [5:0] light2; //南北方向的灯 绿 黄 红 绿 黄 红
- output [26:0] data;
-
- reg [5:0] light1; //定义信号类型
- reg [5:0] light2;
-
- reg [3:0] state ;
- reg [3:0] next_state ;
-
- reg [5:0] jishu;
- wire [3:0] jishu_ge;
- wire [3:0] jishu_shi;
- reg [5:0] jishu_num;
-
- parameter S0 = 4'b0000 ;
- parameter S1 = 4'b0001 ;
- parameter S2 = 4'b0010 ;
- parameter S3 = 4'b0100 ;
- parameter S4 = 4'b1000 ;
- //二段式状态机
- always @(posedge clk_50m or negedge rst) begin
- if(!rst)
- state <= S0;
- else
- state <= next_state;
- end
- always @(posedge clk_1hz) begin
- if(k==0) begin
- case (state)
- S0: if (!rst) begin
- next_state <= S1;
- jishu_num<=6'd35; //状态维持35S
- light1 = 6'b001_001; //红灯
- light2 = 6'b100_100; //绿灯
- end
- S1: if (jishu == 6'd0) begin
- next_state <= S2;
- jishu_num<=6'd5; //维持5S
- light1 = 6'b001_001; //红灯
- light2 = 6'b010_010; //黄灯
- end
- S2: if (jishu == 6'd0) begin
- next_state <= S3;
- jishu_num<=6'd35; //维持35S
- light1 = 6'b100_001; //绿灯
- light2 = 6'b001_001; //红灯
- end
- S3: if (jishu == 6'd0) begin
- next_state <= S4;
- jishu_num<=6'd5; //维持5S
- light1 = 6'b010_010; //黄灯
- light2 = 6'b001_001; //红灯
- end
- S4: if (jishu == 6'd0) begin
- next_state <= S1;
- jishu_num<=6'd35; //状态维持35S
- light1 = 6'b001_001; //红灯
- light2 = 6'b100_100; //绿灯
- end
- endcase
- end
- else //如果K1拨上去了
- begin
- light1 = 6'b001_001;
- light2 = 6'b001_001; //全部亮红灯
- end
- end
-
-
- //时钟控制模块 输入1HZ
- always @(posedge clk_1hz or negedge rst) begin
- if (!rst) begin
- jishu <= 6'd0;
- end
- else if(k==0) begin // 工作在自动模式
- if (jishu == 6'd0)
- jishu <= jishu_num;
- else
- jishu <= jishu-1;
- end
- else
- jishu<=jishu; //如果K1拨上去了 时间不变
- end
-
-
- assign jishu_ge=jishu%10;
- assign jishu_shi=jishu/10;
- assign data=jishu_ge*10000000+jishu_shi*1000000+030616;
-
-
- endmodule
重点在于状态机的运转流程,以及状态的切换。程序一开始会从S0状态,一直运行到S4状态,但随后只会在 S1 S2 S3 S4里面循环。S0是给上电复位设置的初始状态。
在时钟控制模块里面,让jishu这个变量一直减一,在状态机里面,给jishu赋值,当jishu变量减到0时,就进行状态的切换。切换之后,到了下一个状态,又重新对jishu进行赋值。这样就实现的LED灯在不同的状态亮不同的时间了!
然后时间又被传递后显示模块进行了显示。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。