1.设计一个简单的十字路口交通灯控制系统, 实现如下3个功能:
➢ 1.十字路分为横向路H_road和纵向路V_road。
➢ 2.Hroad和Vroad交替通行,每条路的绿灯保持一段时间 (30秒)才通过黄灯(3秒)变为红灯,同时另一条路的 交通灯从红灯变为绿灯。
➢ 3.使用板载的LED灯代表交通灯上的红、黄、绿灯, 两块数码管分别显示两条路上的绿灯和红灯最后15秒倒计时和黄灯3秒倒计时。
2.交通灯状态提取:
➢ 抽象出6种状态:H_red、H_green、H_yellow、V_green、V_yellow、V_red
➢ 注意到 H_red、V_red 包含在 H_green、H_yellow、V_green、V_yellow四个状态里 ➢ 我们提取以下四种状态:
H_green(横向路绿灯状态)、H_yellow(横向路黄灯状态)
V_green(纵向路绿灯状态)、V_yellow(纵向路黄灯状态)
➢ 交通灯输出既和现状态有关,又和输入(计数值)有关,为 Melay状态机。
3.交通灯状态转换表
状态转换图:
4.交通灯代码实现(verilog)
module traffic(
input clk_1,
input reset,
input[7:0] counter_33, //33秒计数器
output reg Start_timer_33, //开始计数信号
output reg [1:0] H_display_en, //横向道路倒计时显示使能
output reg [7:0] H_count, //横向道路倒计时数值
output reg [1:0] V_display_en, //纵向道路倒计时显示使能
output reg [7:0] V_count, //纵向道路倒计时数值
output reg H_light_green, //横向绿灯
output reg H_light_yellow, //横向黄灯
output reg H_light_red, //横向红灯
output reg V_light_green, //纵向绿灯
output reg V_light_yellow, //纵向黄灯
output reg V_light_red //纵向红灯
);
parameter H_green = 4'b0001;
parameter H_yellow = 4'b0010;
parameter V_green = 4'b0100;
parameter V_yellow = 4'b1000;
parameter YES = 1'b1;
parameter NO = 1'b0;
parameter ON = 1'b1;
parameter OFF = 1'b0;
parameter DISPLAY_ON = 2'b00;
parameter DISPLAY_OFF = 2'b11;
reg [3:0] state;
reg [3:0] next_state;
//第一个进程,同步时序always模块,格式化描述次态寄存器转移到现态寄存器;
always@(posedge clk_1 ,negedge reset)
begin
if(!reset)
state <= H_green;
else
state <= next_state;
end
//第二个进程,同步时序always模块,描述次态寄存器的状态转移条件
always@ (posedge clk_1 ,negedge reset)
if(!reset)
next_state <= H_green;
else
begin
case(next_state)
H_green:
if(counter_33 == 4)
next_state <= H_yellow;
else
next_state <= H_green;
H_yellow:
if(counter_33 == 1)
next_state <= V_green;
else
next_state <= H_yellow;
V_green:
if(counter_33 == 4)
next_state <= V_yellow;
else
next_state <= V_green;
V_yellow:
if(counter_33 == 1)
next_state <= H_green;
else
next_state <= V_yellow;
default:
next_state <= H_green;
endcase
end
//第三个进程,同步时序always块,格式化描述次态寄存器的输出
always@(posedge clk_1 ,negedge reset)
if(!reset)
begin
H_light_green <= ON;
H_light_yellow <= OFF;
H_light_red <= OFF;
V_light_green <= OFF;
V_light_yellow <= OFF;
V_light_red <= ON;
H_count <= 4'b0000;
V_count <= 4'b0000;
H_display_en <= DISPLAY_OFF;
V_display_en <= DISPLAY_OFF;
Start_timer_33 <= YES;
end
else
begin
case(next_state)
H_green:
begin
H_light_green <= ON;
H_light_yellow <= OFF;
H_light_red <= OFF;
V_light_green <= OFF;
V_light_yellow <= OFF;
V_light_red <= ON;
Start_timer_33 <= NO;
if(counter_33 <= 18 && counter_33 >= 4)
begin
H_count <= counter_33 - 3;
H_display_en <= DISPLAY_ON;
end
else
H_display_en <= DISPLAY_OFF;
if(counter_33 <= 15 && counter_33 >= 1)
begin
V_count <= counter_33;
V_display_en <= DISPLAY_ON;
end
else
V_display_en <= DISPLAY_OFF;
end
H_yellow:
begin
H_light_green <= OFF;
H_light_yellow <= ON;
H_light_red <= OFF;
V_light_green <= OFF;
V_light_yellow <= OFF;
V_light_red <= ON;
if(counter_33 <= 3 && counter_33 >= 1)
begin
H_count <= counter_33;
H_display_en <= DISPLAY_ON;
end
else
H_display_en <= DISPLAY_OFF;
if(counter_33 <= 15 && counter_33 >= 1)
begin
V_count <= counter_33;
V_display_en <= DISPLAY_ON;
end
else
V_display_en <= DISPLAY_OFF;
if(counter_33 == 1)
Start_timer_33 <= YES;
else
Start_timer_33 <= NO;
end
V_green:
begin
H_light_green <= OFF;
H_light_yellow <= OFF;
H_light_red <= ON;
V_light_green <= ON;
V_light_yellow <= OFF;
V_light_red <= OFF;
Start_timer_33 <= NO;
if(counter_33 <= 18 && counter_33 >= 4)
begin
V_count <= counter_33 - 3;
V_display_en <= DISPLAY_ON;
end
else
V_display_en <= DISPLAY_OFF;
if(counter_33 <= 15 && counter_33 >= 1)
begin
H_count <= counter_33;
H_display_en <= DISPLAY_ON;
end
else
H_display_en <= DISPLAY_OFF;
end
V_yellow:
begin
H_light_green <= OFF;
H_light_yellow <= OFF;
H_light_red <= ON;
V_light_green <= OFF;
V_light_yellow <= ON;
V_light_red <= OFF;
if(counter_33 <= 3 && counter_33 >= 1)
begin
V_count <= counter_33;
V_display_en <= DISPLAY_ON;
end
else
V_display_en <= DISPLAY_OFF;
if(counter_33 <= 15 && counter_33 >= 1)
begin
H_count <= counter_33;
H_display_en <= DISPLAY_ON;
end
else
H_display_en <= DISPLAY_OFF;
if(counter_33 == 1)
Start_timer_33 <= YES;
else
Start_timer_33 <= NO;
end
default:
begin
H_light_green <= ON;
H_light_yellow <= OFF;
H_light_red <= OFF;
V_light_green <= OFF;
V_light_yellow <= OFF;
V_light_red <= ON;
H_count <= 4'b0000;
V_count <= 4'b0000;
H_display_en <= DISPLAY_OFF;
V_display_en <= DISPLAY_OFF;
Start_timer_33 <= YES;
end
endcase
end
endmodule
5.模块框图
➢ 分频器模块
➢ 计数器模块
➢ 有限状态机模块
➢ 逻辑译码及显示模块
6.交通灯代码实现:分频器
module clk_div(
input clk_100M,
input reset,
output clk_200,
output clk_1
);
reg[15:0] cnt_2khz;
reg[7:0] cnt_200hz;
reg[7:0] cnt_1hz;
reg clk_2k;
reg clk_200_reg;
reg clk_1_reg;
//2KHz 分频代码:
always @ (posedge clk_100M,negedge reset)
begin
if(!reset)
begin
cnt_2khz <= 1'b0;
clk_2k <= 1'b0;
end
else
begin
if(cnt_2khz==16'h61A7)//24999
begin
clk_2k<=~clk_2k;// 1*108/5*104=2000
cnt_2khz <= 0;
end
else
cnt_2khz<=cnt_2khz+1;
end
end
//200Hz 分频代码:
always@(posedge clk_2k,negedge reset)
begin
if(!reset)
begin
cnt_200hz<=1'b0;
clk_200_reg<=1'b0;
end
else
begin
if(cnt_200hz == 4) //计数5次
begin
clk_200_reg<=~clk_200_reg;
cnt_200hz <= 0;
end
else
cnt_200hz<=cnt_200hz+1;
end
end
//1Hz 分频代码:
always@(posedge clk_200_reg,negedge reset)
begin
if(!reset)
begin
cnt_1hz<=1'b0;
clk_1_reg<=1'b0;
end
else
begin
if(cnt_1hz == 99)
begin
clk_1_reg<=~clk_1_reg;
cnt_1hz <= 0;
end
else
cnt_1hz<=cnt_1hz+1;
end
end
assign clk_200=clk_200_reg;
assign clk_1=clk_1_reg;
endmodul
7.交通灯代码实现:计数器
module counter(
input clk_1,
input reset,
input Start_timer_33,
output reg[7:0] counter_33
);
always@(posedge clk_1, negedge reset)
if(!reset)
counter_33 <= 32;
else if(Start_timer_33)
counter_33 <= 32;
else
counter_33 <= counter_33 -1;
endmodule
8.交通灯代码实现 :14位二进制-BCD码转换器
module bin2bcd(
input [7:0] data_bin,
output reg[7:0] data_bcd
);
reg[17:0] z; //中间变量,z的位数根据待转换的数字确定
integer i;
always@(*)
begin
for(i=0;i<=17;i=i+1) //赋初值0
z[i]=0;
z[10:3]=data_bin; //shift 3 places(3次后才判断是否需要+3
repeat(5) //此处填入重复的次数
begin
if(z[11:8]>4) //个位>4则+3
z[11:8]=z[11:8]+3;
if(z[15:12]>4) //十位>4则+3
z[15:12]=z[15:12]+3;
z[17:1]=z[16:0];
end
data_bcd=z[15:8];
end
endmodule
9.交通灯代码实现:显示display
module display(
input clk_200,
input [3:0] hex3,
input [3:0] hex2,
input [3:0] hex1,
input [3:0] hex0,
input [3:0]display_en, //用两个信号H_display_en和V_display_en拼接成输入{H_display_en,V_display_en}
output reg [3:0] an,
output reg [7:0] sseg
);
reg [1:0] regN;
reg [3:0] hex_in;
reg dp;
initial
begin
regN = 0;
end
always@(posedge clk_200)
regN <= regN + 1;
always@*
begin
dp = 1'b0;
case(regN)
2'b00:
begin
an=4'b1110 | display_en;
hex_in=hex0;
end
2'b01:
begin
an=4'b1101 | display_en;
hex_in=hex1;
end
2'b10:
begin
an=4'b1011 | display_en;
hex_in=hex2;
end
2'b11:
begin
an=4'b0111 | display_en;
hex_in=hex3;
end
default:
begin
an = 4'b1111;
hex_in = 4'b0000;
end
endcase
end
always @ *
begin
case(hex_in)
4'h0: sseg[7:1] = 7'b1111110;
4'h1: sseg[7:1] = 7'b0110000;
4'h2: sseg[7:1] = 7'b1101101;
4'h3: sseg[7:1] = 7'b1111001;
4'h4: sseg[7:1] = 7'b0110011;
4'h5: sseg[7:1] = 7'b1011011;
4'h6: sseg[7:1] = 7'b1011111;
4'h7: sseg[7:1] = 7'b1110000;
4'h8: sseg[7:1] = 7'b1111111;
4'h9: sseg[7:1] = 7'b1111011;
4'ha: sseg[7:1] = 7'b1110111;
4'hb: sseg[7:1] = 7'b0011111;
4'hc: sseg[7:1] = 7'b1001110;
4'hd: sseg[7:1] = 7'b0111101;
4'he: sseg[7:1] = 7'b1001111;
default: sseg[7:1] = 7'b1000111; //4'hf
endcase
sseg[0]=dp;
end
endmodule
到这里所有所需模块已经搭建完成,现在需要一个顶层模块来集成上面的所有模块,以及定义外部接口,以实现与外部的交互。
10.交通灯顶层代码
module traffic_top(
input clk,
input reset,
output H_light_green,
output H_light_yellow,
output H_light_red,
output V_light_green,
output V_light_yellow,
output V_light_red,
output [3:0] an,
output [7:0] sseg
);
wire clk_200;
wire clk_1;
clk_div U1(
.clk_100M(clk),
.reset(reset),
.clk_200(clk_200),
.clk_1(clk_1)
);
wire Start_timer_33;
wire [7:0] counter_33;
counter U2(
.clk_1(clk_1),
.reset(reset),
.Start_timer_33(Start_timer_33),
.counter_33(counter_33)
);
wire [3:0] H_count;
wire [3:0] V_count;
wire [1:0] H_display_en;
wire [1:0] V_display_en;
traffic U3(
.clk_1(clk_1),
.reset(reset),
.counter_33(counter_33),
.Start_timer_33(Start_timer_33),
.H_count(H_count),
.V_count(V_count),
.H_light_green(H_light_green),
.H_light_yellow(H_light_yellow),
.H_light_red(H_light_red),
.V_light_green(V_light_green),
.V_light_yellow(V_light_yellow),
.V_light_red(V_light_red)
);
wire [7:0] H_bcd;
wire [7:0] V_bcd;
bin2bcd U4(
.data_bin(H_count),
.data_bcd(H_bcd)
);
bin2bcd U5(
.data_bin(V_count),
.data_bcd(V_bcd)
);
bin2bcd U6(
.data_bin(counter_33),
.data_bcd(counter)
);
display U7(
.clk_200(clk_200),
.hex3(H_bcd[7:4]),
.hex2(H_bcd[3:0]),
.hex1(V_bcd[7:4]),
.hex0(V_bcd[3:0]),
.display_en({H_display_en,V_display_en}),
.an(an),
.sseg(sseg)
);
endmodule
11.硬件配置
到此整个实验的主要内容已经是完成了,接下来是硬件的配置,此次实验使用的开发板为硬木课堂提供的ACE—7A75T,(可根据板子的型号而选定相适合的接口配置)因为上面只有红色LED灯,所以用红灯来代替绿黄,如下:
1.根据数据手册,进行红绿灯管脚分配
H_Light_green U21
H_Light_red R19
H_Light_yellow P19
V_Light_green W22
V_light_red AA21
V_light_yellow AA20
2.再进行红绿灯倒计时管脚的配置
an[3] R14
an[2] R18
an[1] T18
an[0] N17
3.对计数器进行配置
将counter计数器接入右上角的两个带译码的数码管DIG2,来显示counter33的值
最后再将时钟等其他接口接上,便完成了。
4.成品
交通灯