2025寒假练 - 基于小脚丫FPGA实现交通灯控制系统
该项目使用了WebIDE的图形化编程,diamond软件,Verilog语言,实现了交通灯控制系统的设计,它的主要功能为:在数码管上显示计时信息,蜂鸣器报警,接近传感器检测人员走近,环境光感知,自动点亮路灯(小脚丫核心板上的单色LED)。
标签
FPGA
数字逻辑
开发板
交通灯
2025寒假在家一起练
樱花咕咕
更新2025-03-19
北京理工大学
15

项目总结报告

北京理工大学 刘宇轩



1. 项目介绍:

本项目旨在使用FPGA板子,结合图形化编程与Verilog硬件描述语言,构建一个完整的交通灯控制系统。该系统将集成数码管显示、蜂鸣器报警、接近传感器检测以及环境光感知等功能,以实现智能化的交通灯控制。

交通灯控制:使用74系列元器件搭建交通灯控制逻辑,通过设置不同的状态来控制交通灯的显示。将利用时序逻辑电路来实现状态的切换,以模拟现实中的交通灯工作周期。

数码管显示:通过WebIDE的图形化编程,配置数码管驱动电路,实现计时信息的显示。数码管将显示剩余时间等关键信息,以便行人和车辆了解交通灯状态。

蜂鸣器报警:同样采用图形化编程配置蜂鸣器驱动电路,在特定情况下(黄灯)发出警报声,提醒行人和车辆注意交通灯的变化。

接近传感器检测:利用Verilog编写接近传感器的控制逻辑,检测人员是否走近。当传感器检测到有人靠近时,将触发交通灯控制逻辑,使灯进入相应的状态。

环境光感知:通过Verilog实现环境光传感器的控制逻辑,根据环境光的强度自动点亮路灯(使用小脚丫核心板上的单色LED模拟)。当环境光较暗时,路灯将自动点亮,提高夜间交通安全性。


2. 硬件介绍:

 

FPGA板子:选用小脚丫核心板,其具有丰富的外设接口和强大的处理能力,能够满足项目的需求。

74系列元器件:用于构建交通灯控制逻辑电路。

LED灯:点亮或熄灭

数码管:用于显示计时信息,采用共阳极数码管,通过74系列元器件驱动。

蜂鸣器:用于发出报警声,通过FPGA的GPIO口直接控制。

接近和环境光传感器(RPR0521RS)是一款结合了环境光(ALS,Ambient Light Sensing)和接近检测(Proximity Detection)功能的传感器。它通过测量反射红外光的强度来判断附近是否有物体(接近检测),并通过测量环境光强度来提供照度数据(ALS)。

通过74HC595 移位寄存器驱动数码管,用于显示传感器数据(如环境光强度)。


3. 方案框图和项目设计思路介绍

任务1数码管显示计时信息设计思路:

 时钟分频:系统需要一个较低频率的时钟信号来驱动计时功能。通过使用任意整数分频器,将输入的主时钟信号(CLK)分频为所需的低频时钟信号。

计数器模块:使用74HC290计数器模块来实现计时功能。74HC290是一个2*5的计数器,可以用于实现从0到9的计数,它被用来对分频后的时钟信号进行计数,从而实现定时功能。

译码器模块:将计数器的输出通过译码器转换为数码管可以显示的段码信号。译码器根据计数器的输出值,选择对应的字符在数码管上显示。例如,当计数器输出为0时,译码器将输出对应的段码,使数码管显示“0”。

颜色变化:通过对计数器的输出值全部取反并按位与,得到只有在0000时为1的颜色变化信号,驱动RGB灯的颜色变化。

任务2蜂鸣器报警

 时钟分频:同样,这里也需要一个较低频率的时钟信号来驱动蜂鸣器的报警功能。通过使用任意整数分频器,驱动蜂鸣器的报警声。

黄灯报警控制:使用一个简单的逻辑门组合,将分频后的时钟信号和黄灯时的控制信号进行逻辑运算(只有黄灯该信号为1,其它颜色为0),以产生蜂鸣器的驱动信号。将逻辑门的输出连接到蜂鸣器的驱动端,使蜂鸣器能够根据控制逻辑发出报警声。

任务3接近传感器检测

 阈值设定:定义了一个接近检测的阈值,用于判断是否有物体靠近传感器。

数据采样:在每个dat_valid信号的上升沿,对prox_dat信号进行采样,并将采样值存储在prox_dat0和prox_dat1寄存器中。

差分检测:通过比较prox_dat1和prox_dat0的差值,判断传感器信号的变化是否超过一定阈值(0x800)。如果变化超过阈值,则认为传感器信号发生了显著变化,可能是有物体靠近或远离。

状态更新:根据差分检测的结果,更新prox_dat2的值。如果差值超过阈值,则保持prox_dat2的值不变;否则,将prox_dat2更新为prox_dat0的值。

输出控制:根据prox_dat2的值与阈值的比较结果,控制Y_out低四位的输出。当prox_dat2大于等于THR

 任务4环境光感知

 1环境光计算逻辑

参数校准:根据传感器手册,定义了多个校准参数,用于将传感器的原始数据转换为实际的环境光强度。

分段计算:根据date0和date1的比值,将环境光强度分为四个不同的区间。在每个区间内,使用对应的系数进行环境光强度的计算。

线性组合:在每个区间内,通过线性组合date0和date1的值,计算出最终的环境光强度lux。计算公式为:lux = date0 * A -date1 * B.

特殊情况处理:如果date1的值超出了所有定义的区间,则将lux设置为0,表示环境光强度无法准确测量。

2 BCD转码

调用子模块:实例化了一个bin_to_bcd模块,用于将滤波后的环境光强度数据(lux_filtered)转换为BCD格式。这样可以方便后续在数码管上显示环境光强度。

输出连接:将bin_to_bcd模块的输出bcd_code连接到模块的lux_data输出端口,使得最终的环境光强度数据以BCD格式输出。


4. 软件流程图和关键代码介绍

任务一任务二

webide图形化项目链接:https://www.stepfpga.com/project/17772/code

Seg_decoder:

wire [3:0] code;
reg [6:0] q;
reg ch;
 
assign code[0] = A0;
assign code[1] = A1;
assign code[2] = A2;
assign code[3] = A3;
assign Y[0] = q[0];
assign Y[1] = q[1];
assign Y[2] = q[2];
assign Y[3] = q[3];
assign Y[4] = q[4];
assign Y[5] = q[5];
assign Y[6] = q[6];
 
always@(code) begin
    case(code)
        4'b0000: q = 7'b110_1111; //9
        4'b0001: q = 7'b110_0110; //4
        4'b0010: q = 7'b100_1111; //3
        4'b0011: q = 7'b111_1111; //8
        4'b0100: q = 7'b000_0111; //7
        4'b0101: q = 7'b101_1011; //2
        4'b0110: q = 7'b000_0110; //1
        4'b0111: q = 7'b111_1101; //6
        4'b1000: q = 7'b110_1101; //5
        4'b1001: q = 7'b011_1111; //0
    endcase
    ch <= & (~code);
end

主要功能是实现一个4位二进制编码到7段数码管显示信号的转换。通过case语句,根据输入的4位二进制编码,选择对应的7段数码管显示信号,并将其赋值给q寄存器。Y输出信号直接连接到q寄存器的各位,用于驱动数码管的7个段。ch信号则用于数码管的选通控制。

Color_change:

// Module Function: 交通灯状态机颜色计数器
wire ch;
reg [1:0] count;
 
assign ch = Color_change;
assign RGB0 = count[0];
assign RGB1 = count[1];
 
always @(posedge ch) begin
    if (count == 2'b10)
        count <= 2'b00;
    else
        count <= count + 2'b01;
end

输入信号:

color_change:颜色变化信号,用于触发计数器的递增。

输出信号:

RGB0和RGB1:用于控制交通灯颜色的输出信号,它们的值由计数器count的当前值决定,同时RGB1由于只会在黄灯时为1,也用来控制蜂鸣器的报警。

每当color_change信号的上升沿到来时,计数器count的值会加1。如果count的值达到2'b10(即十进制的2),它会在下一次加1时被重置为0,从而实现循环计数。

RGB:

// Module Function 颜色控制
wire [1:0] RGB2;
reg [5:0] RGB;
 
assign RGB2[0] = RGB0;
assign RGB2[1] = RGB1;
 
always @(*) begin
    case (RGB2) // 拼接成2位控制信号
        2'b00: RGB = 6'b00_11_11;  // 红色:R满,G/B关闭
        2'b01: RGB = 6'b11_00_11;  // 绿色:G满,R/B关闭
        2'b10: RGB = 6'b00_00_11;  // 黄色:R/G满,B关闭
        default: RGB = 6'b11_11_11; // 其他情况:全关闭(黑色)
    endcase
end

RGB2:将RGB0和RGB1拼接成一个2位的信号,用于控制RGB灯的颜色。

RGB:6位的寄存器,用于存储RGB灯的颜色值。每个颜色通道(红、绿、)由两位表示。

case语句:根据RGB2的值,设置RGB灯的颜色。每个case分支对应一种颜色配置。

 

任务三任务四:

module decoder(
input rst_n, // 异步复位信号(低电平有效)
input dat_valid, // 数据有效时钟信号(上升沿触发)
input [15:0] prox_dat, // 接近传感器原始数据输入
input [15:0] ch0_dat, // 光传感器通道0原始数据
input [15:0] ch1_dat, // 光传感器通道1原始数据
output [31:0] lux_data, // 转换后的32位BCD格式光照数据
output reg [7:0] Y_out // 8位状态编码输出(用于LED控制等)
);
/*------------------------------------------
接近传感器数据处理模块
------------------------------------------*/
reg [15:0] prox_dat0, prox_dat1, prox_dat2;
always @(posedge dat_valid) begin
prox_dat0 <= prox_dat; // 第1级数据缓冲
prox_dat1 <= prox_dat0; // 第2级数据缓冲
// 数据变化阈值检测(可能存在条件重复的BUG)
// 当相邻两次采样值变化超过0x800时保持原值,否则更新
if(((prox_dat1-prox_dat0) >= 16'h800) || ((prox_dat1-prox_dat0) >= 16'h800))
prox_dat2 <= prox_dat2; // 超过阈值时保持旧值
else
prox_dat2 <= prox_dat0; // 正常更新数据
end
/*------------------------------------------
光照强度计算模块
------------------------------------------*/
wire [31:0] data0, data1;
reg [31:0] lux;
assign data0 = ch0_dat;
assign data1 = ch1_dat;
// 根据两个通道数据的比例关系选择不同计算公式
always@(data0 or data1) begin
if(data1 < data0*595)
lux = data0*1682 - data1*1877;
else if(data1 < data0*1015)
lux = data0*644 - data1* 132;
else if(data1 < data0*1352)
lux = data0*756 - data1*243;
else if((data1 < data0*3053))
lux = data0*766 - data1*25;
else
lux = 0; // 超出量程时归零
end
/*------------------------------------------
LED状态编码模块
------------------------------------------*/
always@(prox_dat2[11:9] or lux) begin
// 将高3位[11:9]映射到单色LED低四位
case (prox_dat2[11:9])
3'b000: Y_out[3:0] = 4'b11111; // 低四位全灭,无人靠近
default:Y_out[3:0] = 4'b0000; // 低四位全亮,有人接近
endcase
if(lux>=32'd30000)
Y_out[7:4] = 4'b11111; // 高四位全灭,环境很亮
else
Y_out[7:4] = 4'b0000; // 高四位全亮,环境较暗
end
/*------------------------------------------
BCD转换模块实例化
------------------------------------------*/
wire [31:0] T_data_bcd;
bin_to_bcd u1(
.rst_n (rst_n), // 系统复位
.bin_code (lux), // 二进制光照强度输入
.bcd_code (T_data_bcd) // BCD格式输出
);
assign lux_data = T_data_bcd; // 输出最终结果
endmodule

5. 功能展示图及说明

任务一、二:

倒计时设置为每个灯10秒(从9到0),颜色变化顺序为(红->绿->黄->红)循环。数码管示数为0时,下一秒重新从9开始倒计时,并且三色RGB灯的颜色变化一次,在黄灯期间蜂鸣器持续报警。

 

任务三、四:

单色LED高四位感光,环境亮时灭,环境暗时亮;

单色LED低四位由接近传感器控制,有人靠近时亮,无人靠近时灭。

 

资源占用:

WebIDE:

Diamond:


6. 项目中遇到的难题和解决方法

难题1:蜂鸣器声音很小,数码管亮度也低

问题描述:

蜂鸣器虽然响了但声音很小,数码管示数正常但亮度低。

解决方法:

给数码管的管脚seg_dig赋值为恒0.

难题2:任务一二中LED异常发光

问题描述:

在没有给8个单色LED赋值的情况下恒亮。

解决方法:

由于LED为低电频有效,赋值为恒1.

难题3RGB灯变色错误

问题描述:

在控制RGB灯的颜色变化时,由于组合逻辑的延迟性导致灯在倒计时为3秒时变色。

解决方法:

简化控制逻辑:删去复杂的组合逻辑,在自定义模块中使用&(~code)的简单逻辑运算来控制颜色变化。


7.心得体会和意见
心得体会:

在项目开发过程中,我遇到了许多技术难题,例如数码管的亮度、蜂鸣器的响度、单色LED异常发光和RGB灯颜色变化不受控等问题。通过定位异常位置、修改代码和优化设计,我逐渐克服了这些问题。这不仅让我在代码编写上有了很大的提升,也让我学会了如何在面对复杂问题时保持冷静和耐心。

意见和建议:

WebIDE编程很使用体验很差,无法直接对当前的图形化编程进行编译,只能重新建一个项目打开保存的图形化项目的main.v文件来进行后续的编译,非常的麻烦。并且图形化编程的缩放逻辑非常反直觉,并且不能直接移动。并且在保存自定义模块时会导致已经连接好的电路消失(部分人没这个问题,非常折磨),只能重新来过。

建议增加自动保存功能,避免因意外断开连接或网页卡顿导致的代码丢失。可以设置定时保存或在用户进行操作时自动保存,以确保劳动成果得到保护。

通过这次项目开发,我不仅在技术上有了显著的提升,也在时间管理方面积累了宝贵的经验。希望未来能够有更多的机会参与类似的项目,进一步提升自己的能力。

附件下载
34_Traffic.zip
任务34的项目文件压缩包
prox_detect_impl1.jed
任务34的JED文件
implement .jed
任务12图形化编程的JED文件
archive.zip
任务12图形化编程的项目文件压缩包
团队介绍
大学生个人作品 webide图形化项目链接:https://www.stepfpga.com/project/17772/code
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号