基于FPGA含倒计时功能的交通灯设计(附完整源码)
时间:2025-11-16 22:57:32
手机看文章
扫描二维码
随时随地手机看文章
一、实验任务要求
1)实现一交通十字路口处红绿灯的基本定时控制功能,要求东西方向灯色循环为绿灯45秒,黄灯5秒,左拐灯15秒,黄灯5秒,红灯40秒,黄灯5秒;南北方向灯色循环为红灯65秒,黄灯5秒,绿灯20秒,黄灯5秒,左拐灯15秒,黄灯5秒。2)实现东西方向和南北方向各种灯的倒计时数码显示功能。二、LED分模块设计(用于调用使用)module LED (seg_data_1,seg_data_2,seg_led_1,seg_led_2); input [3:0] seg_data_1;//数码管需要显示0~9十个数字,所以最少需要4位输入做译码 input [3:0] seg_data_2;//小脚丫上第二个数码管 output [8:0] seg_led_1;//在小脚丫上控制一个数码管需要9个信号 MSB~LSB=DIG、DP、G、F、E、D、C、B、A output [8:0] seg_led_2;//在小脚丫上第二个数码管的控制信号 MSB~LSB=DIG、DP、G、F、E、D、C、B、A reg [8:0] seg [9:0]; //定义了一个reg型的数组变量,相当于一个10*9的存储器,存储器一共有10个数,每个数有9位宽 initial //在过程块中只能给reg型变量赋值,Verilog中有两种过程块always和initial //initial和always不同,其中语句只执行一次 begin seg[0] = 9'h3f; //对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮,7段显示数字 0 seg[1] = 9'h06; //7段显示数字 1 seg[2] = 9'h5b; //7段显示数字 2 seg[3] = 9'h4f; //7段显示数字 3 seg[4] = 9'h66; //7段显示数字 4 seg[5] = 9'h6d; //7段显示数字 5 seg[6] = 9'h7d; //7段显示数字 6 seg[7] = 9'h07; //7段显示数字 7 seg[8] = 9'h7f; //7段显示数字 8 seg[9] = 9'h6f; //7段显示数字 9 end assign seg_led_1 = seg[seg_data_1]; //连续赋值,这样输入不同四位数,就能输出对于译码的9位输出 assign seg_led_2 = seg[seg_data_2]; endmodule三、主程序代码
module traffic1(Clk_12M,Rst,LedR_1,LedG_1,LedB_1,LedR_2,LedG_2,LedB_2,Seg7_VH,Seg7_VL,led15,led16,led17,ledCntDis); parameter S0 = 0; //主路绿灯,支路红灯 parameter S1 = 1; //主路黄灯,支路红灯 parameter S2 = 2; //主路蓝灯,支路红灯 parameter S3 = 3; //主路黄灯,支路黄灯 parameter S4 = 4; //主路红灯,支路绿灯 parameter S5 = 5; //主路红灯,支路黄灯 parameter S6 = 6; //主路红灯,支路蓝灯 parameter S7 = 7; //主路黄灯,支路黄灯 input Clk_12M,Rst; output LedR_1,LedG_1,LedB_1,LedR_2,LedG_2,LedB_2; output [8:0]Seg7_VH,Seg7_VL; output led15,led16,led17; reg LedR_1,LedG_1,LedB_1,LedR_2,LedG_2,LedB_2; reg Clk_1Hz;//分频器 reg [31:0]Cnt_1Hz;//计数器 output reg[3:0] ledCntDis;该模块是一个交通信号灯的Verilog描述,通过控制LED灯和数码管来显示不同的交通信号状态。以下是对该模块的解释:输入:
- Clk_12M:12MHz的时钟信号- Rst:复位信号输出:- LedR_1, LedG_1, LedB_1:控制第一个交通信号灯的红、绿、蓝LED灯- LedR_2, LedG_2, LedB_2:控制第二个交通信号灯的红、绿、蓝LED灯- Seg7_VH, Seg7_VL:控制数码管显示的高位和低位数码- led15, led16, led17:辅助LED灯输出- ledCntDis:控制数码管显示的计数器输出内部变量:
- Clk_1Hz:1Hz的时钟信号,通过分频器实现- Cnt_1Hz:1Hz的计数器,用于控制信号灯状态的切换参数:
- S0-S7:交通信号灯的不同状态,例如S0表示主路绿灯,支路红灯该模块通过时钟信号进行节拍控制,通过状态机的方式实现交通信号灯的循环切换。通过适时改变LED灯和数码管的输出,实现不同状态下的交通信号显示。具体的状态与信号灯显示对应关系是根据参数定义的。
在每个时钟周期,计数器Cnt_1Hz会自增,并根据计数器的值切换交通信号灯的状态和LED灯的输出。同时,数码管和辅助LED灯也会根据需要进行相应的显示。
需要注意的是,该模块中的LedR_1, LedG_1等输出信号使用reg声明,表示它们是可寄存器的输出信号。
/*分频器模块*/ always@(posedge Clk_12M or negedge Rst) begin if(!Rst) begin Cnt_1Hz<=1; Clk_1Hz<=1; //分频器和计数器全部设置为初值1 end else begin if(Cnt_1Hz>=6000000)//当计数器大于等于25的10的六次方 begin Cnt_1Hz<=1;//计数器置一 Clk_1Hz<=~Clk_1Hz;//分频器取反 end else Cnt_1Hz<=Cnt_1Hz+1; end end这部分代码描述了一个分频器模块,用于将输入的12MHz时钟信号分频为1Hz的信号。以下是对代码的解释:
在`always @(posedge Clk_12M or negedge Rst)`的敏感列表中,当输入的时钟信号Clk_12M上升沿或复位信号Rst的下降沿发生时,会执行下面的代码块。
根据复位信号Rst的状态,通过if-else语句进行条件判断和处理:
- 如果复位信号Rst为低电平(即复位有效),则在分频器和计数器的初值都设置为1,表示初始状态。- 如果复位信号Rst为高电平(即复位无效),则执行下面的逻辑。在非复位状态下,判断计数器Cnt_1Hz是否大于等于6000000(即25 * 10^6),如果是,则表示达到了1Hz的分频要求:
- 将计数器Cnt_1Hz重新置为1。- 将分频器Clk_1Hz取反,实现1Hz的方波输出。如果计数器Cnt_1Hz未达到指定值,则将计数器的值加1。
通过这段代码,实现了将12MHz时钟信号分频为1Hz的功能,并且保持了分频器和计数器的状态在复位前后的一致性。分频器的输出Clk_1Hz可以作为其他模块中需要1Hz时钟信号的输入。
/*计数器模块*/ reg[7:0]Cnt70;//用于控制灯的变换 always@(posedge Clk_1Hz or negedge Rst) begin if(!Rst) begin Cnt70<=0; end else begin if(Cnt70>=115) begin Cnt70<=0;//复位 end else Cnt70<=Cnt70+1; end end /*计数器模块*/ reg[7:0]Cnt10;//用于控制数码管的变换 always@(posedge Clk_1Hz or negedge Rst) begin if(!Rst) begin Cnt10<=115; end else begin if(Cnt10<=0) begin Cnt10<=115;//复位 end else Cnt10<=Cnt10-1; end end这部分代码描述了两个计数器模块,分别用于计数到特定的值并进行复位操作。以下是对这两个代码块的解释:第一个计数器模块:- 声明了一个8位的寄存器变量Cnt70用于计数。- 在`always @(posedge Clk_1Hz or negedge Rst)`的敏感列表中,当输入的时钟信号Clk_1Hz上升沿或复位信号Rst的下降沿发生时,会执行下面的代码块。- 如果复位信号Rst为低电平(即复位有效),则将计数器Cnt70置为0。- 如果复位信号Rst为高电平(即复位无效),则判断计数器Cnt70是否大于等于115。如果是,表示计数器已经达到了指定的值,将计数器Cnt70复位为0。- 如果计数器Cnt70未达到指定值,则将计数器的值加1。第二个计数器模块:
- 同样,声明了一个8位的寄存器变量Cnt10用于计数。- 在`always @(posedge Clk_1Hz or negedge Rst)`的敏感列表中,当输入的时钟信号Clk_1Hz上升沿或复位信号Rst的下降沿发生时,会执行下面的代码块。- 如果复位信号Rst为低电平(即复位有效),则将计数器Cnt10置为115。- 如果复位信号Rst为高电平(即复位无效),则判断计数器Cnt10是否小于等于0。如果是,表示计数器已经减到了指定的值,将计数器Cnt10复位为115。- 如果计数器Cnt10未减到指定值,则将计数器的值减1。通过这两个计数器模块,可以实现对计数值的控制和复位操作。这些计数器可用于控制特定时间、时序或事件需要的计数和复位功能。
/*数码管模块*/ reg[7:0]CntDis; reg[7:0]Cnt71; reg [7:0] Cnt61; always@(posedge Clk_12M)//BCD码转换 begin if(Cnt10>70) begin Cnt71[7:0]<=(Cnt10-70)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-70)/10)*10-70; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>65) begin Cnt71[7:0]<=(Cnt10-65)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-65)/10)*10-65; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>50) begin Cnt71[7:0]<=(Cnt10-50)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-50)/10)*10-50; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>45) begin Cnt71[7:0]<=(Cnt10-45)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-45)/10)*10-45; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>25) begin Cnt71[7:0]<=(Cnt10-25)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-25)/10)*10-25; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>20) begin Cnt71[7:0]<=(Cnt10-20)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-20)/10)*10-20; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>5) begin Cnt71[7:0]<=(Cnt10-5)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-5)/10)*10-5; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>0) begin Cnt71[7:0]<=Cnt10/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10; CntDis[3:0]<=Cnt61[3:0]; end end always@(posedge Clk_12M) begin ledCntDis<=CntDis[3:0]; end //数码管调用实例 LED hex(CntDis[3:0],CntDis[7:4],Seg7_VL,Seg7_VH);这部分代码描述了一个数码管模块,它用于将计数器的值转换为BCD码,并将BCD码通过数码管进行显示。以下是对代码的解释:在第一个always块中,通过对12MHz时钟信号Clk_12M的上升沿进行敏感监听,实现对计数器Cnt10值的转换和BCD码的生成。
- 根据不同的计数范围,将Cnt10的值减去一个基准并除以10,得到一个高位数。- 通过减法、除法和取余运算,计算得到一个低位数。- 通过赋值操作,将高位数和低位数分别存储到CntDis的7:4位和3:0位。在第二个always块中,对12MHz时钟信号Clk_12M的上升沿进行敏感监听,将CntDis的低4位赋值给ledCntDis。这样,ledCntDis可以作为控制数码管显示的信号,通过连接到相应的LED显示模块。最后,通过实例化一个名为hex的LED模块,将CntDis的3:0位和7:4位分别连接到Seg7_VL和Seg7_VH输入,从而实现数码管的显示。
通过这段代码,可以将计数器的值转换为BCD码,并通过数码管进行显示,实现实时的数值显示功能。
//状态转换 reg [2:0] state; always@(posedge Clk_12M or negedge Rst) begin if(!Rst) begin LedR_1<=0; LedG_1<=0; LedB_1<=0; LedR_2<=0; LedG_2<=0; LedB_2<=0; end else begin case(state) S0://主路绿灯45s begin if(Cnt70<=45) begin LedR_1<=1; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=1; LedB_2<=1; end else state<=S1; end S1://主路黄灯5s begin if(Cnt70<=50) begin LedR_1<=0; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=1; LedB_2<=1; end else state<=S2; end S2://主路蓝灯15s begin if(Cnt70<=65) begin LedR_1<=1; LedG_1<=1; LedB_1<=0; LedR_2<=0; LedG_2<=1; LedB_2<=1; end else state<=S3; end S3://主辅均5s黄 begin if(Cnt70<=70) begin LedR_1<=0; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=0; LedB_2<=1; end else state<=S4; end S4://辅路绿20s begin if(Cnt70<=90) begin LedR_1<=0; LedG_1<=1; LedB_1<=1; LedR_2<=1; LedG_2<=0; LedB_2<=1; end else state<=S5; end S5://辅路黄灯5s begin if(Cnt70<=95) begin LedR_1<=0; LedG_1<=1; LedB_1<=1; LedR_2<=0; LedG_2<=0; LedB_2<=1; end else state<=S6; end S6://辅路蓝灯15s begin if(Cnt70<=110) begin LedR_1<=0; LedG_1<=1; LedB_1<=1; LedR_2<=1; LedG_2<=1; LedB_2<=0; end else state<=S7; end S7://主辅路均黄灯5s begin if(Cnt70>=111) begin LedR_1<=0; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=0; LedB_2<=1; end else state<=S0; end default begin LedR_1<=0; LedG_1<=0; LedB_1<=0; LedR_2<=0; LedG_2<=0; LedB_2<=0; end endcase end end assign {led17,led16,led15}=state; endmodule这段代码是一个用Verilog描述的状态转换逻辑。它根据时钟信号和复位信号来控制LED灯的状态。具体逻辑如下:1. 如果复位信号(Rst)为低电平,则将所有LED灯的状态置为0。
2. 如果复位信号为高电平,则根据当前的状态(state)执行相应的操作。3. 当前有三种状态(S0、S1、S2),对应不同的灯光控制逻辑。 - S0状态:主路绿灯亮,持续45s。 - S1状态:主路黄灯亮,持续5s。 - S2状态:其他状态,可以在代码中后续定义。 如此下去直到进行循环。具体的操作是根据一个计数器(Cnt70)来控制。当计数器的值小于等于给定的时间时,对应的LED灯亮起;否则,切换到下一个状态。
这段代码中只给出了S0和S1两个状态的逻辑,你可以继续补充其他状态的实现。另外,根据你的具体需求,你可能还需要定义和使用一些其他变量和逻辑来实现完整的状态转换控制。
module traffic1(Clk_12M,Rst,LedR_1,LedG_1,LedB_1,LedR_2,LedG_2,LedB_2,Seg7_VH,Seg7_VL,led15,led16,led17,ledCntDis); parameter S0 = 0; //主路绿灯,支路红灯 parameter S1 = 1; //主路黄灯,支路红灯 parameter S2 = 2; //主路蓝灯,支路红灯 parameter S3 = 3; //主路黄灯,支路黄灯 parameter S4 = 4; //主路红灯,支路绿灯 parameter S5 = 5; //主路红灯,支路黄灯 parameter S6 = 6; //主路红灯,支路蓝灯 parameter S7 = 7; //主路黄灯,支路黄灯 input Clk_12M,Rst; output LedR_1,LedG_1,LedB_1,LedR_2,LedG_2,LedB_2; output [8:0]Seg7_VH,Seg7_VL; output led15,led16,led17; reg LedR_1,LedG_1,LedB_1,LedR_2,LedG_2,LedB_2; reg Clk_1Hz;//分频器 reg [31:0]Cnt_1Hz;//计数器 output reg[3:0] ledCntDis; /*分频器模块*/ always@(posedge Clk_12M or negedge Rst) begin if(!Rst) begin Cnt_1Hz<=1; Clk_1Hz<=1; //分频器和计数器全部设置为初值1 end else begin if(Cnt_1Hz>=6000000)//当计数器大于等于25的10的六次方 begin Cnt_1Hz<=1;//计数器置一 Clk_1Hz<=~Clk_1Hz;//分频器取反 end else Cnt_1Hz<=Cnt_1Hz+1; end end /*计数器模块*/ reg[7:0]Cnt70; always@(posedge Clk_1Hz or negedge Rst) begin if(!Rst) begin Cnt70<=0; end else begin if(Cnt70>=115) begin Cnt70<=0;//复位 end else Cnt70<=Cnt70+1; end end /*计数器模块*/ reg[7:0]Cnt10; always@(posedge Clk_1Hz or negedge Rst) begin if(!Rst) begin Cnt10<=115; end else begin if(Cnt10<=0) begin Cnt10<=115;//复位 end else Cnt10<=Cnt10-1; end end /*数码管模块*/ reg[7:0]CntDis; reg[7:0]Cnt71; reg [7:0] Cnt61; always@(posedge Clk_12M)//BCD码转换 begin if(Cnt10>70) begin Cnt71[7:0]<=(Cnt10-70)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-70)/10)*10-70; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>65) begin Cnt71[7:0]<=(Cnt10-65)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-65)/10)*10-65; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>50) begin Cnt71[7:0]<=(Cnt10-50)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-50)/10)*10-50; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>45) begin Cnt71[7:0]<=(Cnt10-45)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-45)/10)*10-45; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>25) begin Cnt71[7:0]<=(Cnt10-25)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-25)/10)*10-25; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>20) begin Cnt71[7:0]<=(Cnt10-20)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-20)/10)*10-20; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>5) begin Cnt71[7:0]<=(Cnt10-5)/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10-((Cnt10-5)/10)*10-5; CntDis[3:0]<=Cnt61[3:0]; end else if (Cnt10>0) begin Cnt71[7:0]<=Cnt10/10; CntDis[7:4]<=Cnt71[3:0]; Cnt61[7:0]<=Cnt10; CntDis[3:0]<=Cnt61[3:0]; end end always@(posedge Clk_12M) begin ledCntDis<=CntDis[3:0]; end //数码管调用实例 LED hex(CntDis[3:0],CntDis[7:4],Seg7_VL,Seg7_VH); //状态转换 reg [2:0] state; always@(posedge Clk_12M or negedge Rst) begin if(!Rst) begin LedR_1<=0; LedG_1<=0; LedB_1<=0; LedR_2<=0; LedG_2<=0; LedB_2<=0; end else begin case(state) S0://主路绿灯45s begin if(Cnt70<=45) begin LedR_1<=1; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=1; LedB_2<=1; end else state<=S1; end S1://主路黄灯5s begin if(Cnt70<=50) begin LedR_1<=0; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=1; LedB_2<=1; end else state<=S2; end S2://主路蓝灯15s begin if(Cnt70<=65) begin LedR_1<=1; LedG_1<=1; LedB_1<=0; LedR_2<=0; LedG_2<=1; LedB_2<=1; end else state<=S3; end S3://主辅均5s黄 begin if(Cnt70<=70) begin LedR_1<=0; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=0; LedB_2<=1; end else state<=S4; end S4://辅路绿20s begin if(Cnt70<=90) begin LedR_1<=0; LedG_1<=1; LedB_1<=1; LedR_2<=1; LedG_2<=0; LedB_2<=1; end else state<=S5; end S5://辅路黄灯5s begin if(Cnt70<=95) begin LedR_1<=0; LedG_1<=1; LedB_1<=1; LedR_2<=0; LedG_2<=0; LedB_2<=1; end else state<=S6; end S6://辅路蓝灯15s begin if(Cnt70<=110) begin LedR_1<=0; LedG_1<=1; LedB_1<=1; LedR_2<=1; LedG_2<=1; LedB_2<=0; end else state<=S7; end S7://主辅路均黄灯5s begin if(Cnt70>=111) begin LedR_1<=0; LedG_1<=0; LedB_1<=1; LedR_2<=0; LedG_2<=0; LedB_2<=1; end else state<=S0; end default begin LedR_1<=0; LedG_1<=0; LedB_1<=0; LedR_2<=0; LedG_2<=0; LedB_2<=0; end endcase end end assign {led17,led16,led15}=state; endmodule以上是程序总代码。





