一.项目介绍
本项目设计并实现了一个基于74系列逻辑门和WebIDE图形化编程的交通灯控制系统,该系统能够模拟真实的交通灯工作流程,并加入了行人检测和环境光感应功能。
其中,交通灯部分使用了WebIDE的方式进行了编程,实现了在数码管上显示交通灯倒数信息,并在交通灯为绿灯时进行蜂鸣器报警,提醒行人可以通过。
行人检测和环境光感应功能采用了Diamond软件,根据所给例程进行了修改,加入了蜂鸣器模块与亮度检测模块,实现了当距离传感器过近时自动报警与光照过低时自动点亮LED灯
二.简短的使用到的硬件介绍
STEPBaseboard4.0底板:
尺寸兼容标准的DIP40封装,尺寸只有52mmx18mm,可以直接插在面包板上或以模块的方式放置在其它电路板上以即插即用的方式,大大简化系统的设计。
提供电源、USB接口和扩展接口,方便连接PC进行程序下载调试,以及连接其他外设进行功能扩展。通过PMOD接口可以连接各种外设模块进行功能扩展。
集成了E2PROM芯片AT24C02、温湿度传感器SHT-20、加速度计、光敏传感器(RPR-0521RS)、气压计、4×4矩阵键盘、旋转编码器、电位计、HDMI接口、RGBLCD液晶屏、8位7段数码管、蜂鸣器模块、UART通信模块CH340C、ADC功能模块ADC081S101、DAC功能模块DAC081S101、WIFI功能模块ESP8266-12F等常用的外设。
STEP-MXO2-LPC小脚丫FPGA核心板:
作为整个系统的控制核心,负责运行程序,控制各个外设,协调各个模块之间的工作。
核心器件:LatticeLCMXO2-4000HC-4MG132,132脚BGA封装,4320个LUT资源,96Kbit用户闪存,92KbitRAM,瞬时上电启动,启动时间<1ms
板载资源:两位7段数码管、两个RGB三色LED、8路用户LED、4路拨码开关、4路按键、36个用户可扩展I/O(其中包括一路SPI硬核接口和一路I2C硬核接口)。
支持MICO32/8软核处理器以及RISC-V软核。板上集成FPGA编程器,采用U盘的模式,使用USBTypeC接口提供板上+5V供电、FPGA的配置,并新增了UART通信的功能。
主要应用的板载资源:
数码管:包括位于STEP-MXO2-LPC核心板上的以及Baseboard4.0上的,其中STEP-MXO2-LPC核心板上板载两位7段数码管,用于显示交通灯的倒计时时间,方便行人和车辆了解剩余时间。
LED灯:板载LED灯,位于STEP-MXO2-LPC核心板,用于模拟交通灯的红绿黄灯,并模拟路灯,直观地展示交通灯的工作状态。
传感器(RPR-0521RS):该传感器集成了照度传感器和光学式接近传感器。RPR-0521RS位于STEPBaseboard4.0底板上。RPR-0521RS是一款照度、接近一体型传感器。它将光学式接近传感器和红外LED(IrLED)、数字照度传感器整合在1chip中。接近传感器(PS)通过对IrLED发射光线的接近物产生的反射光,检测出人及物体的接近。照度传感器(ALS)可测量从昏暗光线到直射日光的广泛照度。在本项目中,我们利用ALS测量环境光强度,根据照度数据调整LED亮度,模拟路灯的自动点亮,同时利用接近传感器实现自动报警。
三.方案框图和项目设计思路介绍
(一)系统框图说明
系统框图清晰地展示了各个模块之间的关系和数据流向。STEP开发板提供的12MHz时钟信号(clk)首先分别输入到两个时钟分频器,生成1Hz与1000Hz的时钟信号。1000Hz的信号连接到蜂鸣器模块,作为其驱动信号。1Hz的时钟信号连接到倒计时模块,用于控制倒计时速度。倒计时模块接收红、绿灯时长和黄灯时长作为constant(最大值15秒),根据红灯-黄灯-绿灯-黄灯的顺序循环倒数。当前倒计时数字连接到数码管信号生成模块,用于驱动数码管显示。当前倒计时阶段,取值范围00-红灯,01/11-黄灯,10-绿灯,连接到LED灯颜色判断模块。LED灯颜色判断模块的输出信号以及1000Hz信号输入到蜂鸣器模块,控制蜂鸣器的启停。此外,mark信号直接连接到恒定高电平用于调试。
(二)总体设计思路
该系统是一个基于时序控制和状态转移的交通灯控制系统。系统通过时钟分频、倒计时、数码管显示、LED灯颜色控制和蜂鸣器报警等模块,模拟真实的交通灯工作流程,并且各个模块协同工作,实现交通灯的自动切换和报警提示。
①模块划分与功能描述:
时钟分频器:将输入的系统时钟信号(clk)分别转换为1Hz和1000Hz的时钟信号。1Hz时钟信号用于驱动倒计时模块,实现每秒递减的倒计时功能。1000Hz时钟信号用于驱动蜂鸣器模块,产生可听见的报警声音。
倒计时模块:实现交通灯的倒计时功能,并根据红灯、黄灯、绿灯的顺序循环倒计时。输入1Hz时钟信号、红绿灯倒计时时长(最大16秒)、黄灯倒计时时长(最大16秒)。输出倒计时数字(用于数码管显示)、当前倒计时阶段(红灯、黄灯、绿灯)。
数码管信号生成模块:将倒计时模块输出的倒计时数字转换为数码管可以显示的信号。输入倒计时数字,输出数码管段码信号。
LED灯颜色判断模块:根据倒计时模块输出的当前倒计时阶段,控制红、绿、黄LED灯的亮灭。输入当前倒计时阶段(红灯、黄灯、绿灯),输出红、绿、黄LED灯的控制信号。
使用组合逻辑与时序逻辑来实现LED灯的颜色控制,根据当前倒计时阶段,直接输出对应的LED灯控制信号。
蜂鸣器模块:当LED灯颜色为特定颜色时(例如黄灯),发出报警声音。输入LED灯颜色控制信号,1000Hz时钟信号。输出蜂鸣器控制信号。使用与门将LED灯颜色控制信号和1000Hz时钟信号进行与运算,结果作为蜂鸣器的控制信号。这样,只有当LED灯颜色为特定颜色且1000Hz时钟信号为高电平时,蜂鸣器才会发出声音。
②状态转移流程:
初始状态:红灯亮,倒计时16秒(从15到0)。
倒计时:数码管显示剩余时间,每秒递减。
红灯倒计时结束:状态转移到黄灯。
黄灯亮,倒计时6秒(从5到0)。
倒计时:数码管显示剩余时间,每秒递减。
黄灯倒计时结束:状态转移到绿灯。
绿灯亮,倒计时16秒(从15到0,蜂鸣器响起,提示行人可以通过。
倒计时:数码管显示剩余时间,每秒递减。
绿灯倒计时结束:状态转移到黄灯。
黄灯亮,倒计时6秒(从5到0。
倒计时:数码管显示剩余时间,每秒递减。
黄灯倒计时结束:状态转移到红灯,返回步骤1。
③代码实现思路:
时钟分频器:调用模块实现。
倒计时模块:使用简单的判断语句实现。
数码管信号生成模块:使用74hc154与简单的判断语句实现。
LED灯颜色判断模块:因为代码细节原因,需要74hc74延时一个时钟,同时使用简单的判断语句实现。
蜂鸣器模块:使用与门实现。
(一)系统框图说明
系统框图清晰地展示了各个模块之间的关系和数据流向。STEP开发板提供的12MHz时钟信号(clk)和复位信号(rst_n)是整个系统的基础。clk和rst_n首先进入rpr0521rs_driver模块,该模块负责驱动RPR0521RS传感器,并通过I2C总线读取环境光和接近程度数据,并输出有效数据和各种传感器数据。环境光强度数据和接近程度数据以及相关控制信号输入到decoder模块。decoder模块负责根据光强计算照度值,并将该二进制值转换为BCD码;根据接近程度数据控制LED灯的显示样式和蜂鸣器是否鸣叫。照度BCD码被拆分为多个数据,并与时钟、复位和使能信号一起输入到segment_scan模块,该模块使用74HC595芯片的控制时序驱动数码管显示,并控制板载RGBLED灯的颜色。bin_to_bcd模块作为辅助功能,没有直接在顶层模块体现,而是在decoder模块中被调用,负责将二进制的照度值转换为BCD码。
(二)总体设计思路
本系统旨在利用STEP开发板,设计一个集环境光检测、接近感应和数据显示于一体的智能控制系统。 设计重点在于如何在资源有限的FPGA上高效实现I2C通信、数据转换、显示驱动和报警功能。
① 模块划分与功能描述:
本系统主要由以下几个核心模块构成,它们协同工作,实现环境光检测、接近感应、数据处理与显示以及报警等功能:
rpr0521rs_driver (传感器驱动模块): 负责与 RPR0521RS 传感器进行 I2C 通信,读取环境光强度 (ALS) 和接近程度 (Prox) 数据。 该模块输出原始传感器数据和数据有效信号。
decoder (数据解码与处理模块): 对 rpr0521rs_driver 模块输出的原始数据进行处理,将 ALS 数据转换为照度值 (lux)。将照度值进行 BCD 编码,用于数码管显示。根据接近程度数据控制 LED 灯的显示样式和蜂鸣器的启停。
segment_scan (数码管显示驱动模块): 接收来自 decoder 模块的 BCD 码, 通过 74HC595 芯片驱动数码管显示对应的照度值。 该模块还控制板载 RGB LED 灯的颜色。
bin_to_bcd (BCD转换模块): 将decoder模块计算的照度原始数值转换为BCD编码,方便数码管显示
② 状态转移流程: (由于本系统主要侧重于数据采集和显示, 状态转移流程相对简单。 这里主要描述 I2C 通信的时序控制。)
rpr0521rs_driver 模块初始化: 系统复位后, rpr0521rs_driver 模块进入 IDLE 状态。
I2C 通信状态转移: rpr0521rs_driver 模块通过内部状态机控制 I2C 通信时序, 依次进行 START、 WRITE (发送设备地址、寄存器地址和配置数据)、 READ (读取传感器数据)、 STOP 等操作。
数据有效:当rpr0521rs_driver 模块成功读取到传感器数据后, 产生 dat_valid 信号, 通知 decoder 模块进行数据处理。
循环执行:rpr0521rs_driver 模块循环执行 I2C 通信, 不断更新传感器数据。
显示更新:segment_scan 模块在每个扫描周期内, 不断更新数码管的显示内容, 将最新的照度值显示出来。
③ 代码实现思路:
rpr0521rs_driver 模块: 使用状态机实现 I2C 通信协议, 包括 START、 WRITE、 READ、 ACK/NACK、 STOP 等状态。 在每个状态下, 控制 I2C 总线的 SCL 和 SDA 信号, 并根据协议要求进行延时。
decoder 模块: 使用组合逻辑实现照度计算和 LED 灯颜色控制。 使用 "double dabble" 算法实现 BCD 转换。
bin_to_bcd 模块: 使用移位寄存器和加 3 操作实现 "double dabble" 算法。
segment_scan 模块: 使用状态机实现数码管的动态扫描和 74HC595 芯片的时序控制。 通过移位操作将 16 位数据串行发送到 74HC595 芯片, 然后使用 RCK 和 SCK 信号控制数据的锁存和输出。
四.软件流程图和关键代码介绍
(一)关键代码介绍
①两数倒计时计时器:
reg [3:0] count_r;
assign count = count_r;
reg [1:0] sign_r;
assign sign0 = sign_r[0];
assign sign1 = sign_r[1];
always @(posedge clk) begin
if (!rst) begin
sign_r <= 0;
count_r <= 0; //复位计数器
end else begin
case (sign_r)
2'b00: begin //模式0:从num1 - 1开始计数
if (count_r == 0) begin
count_r <= num1 - 1; //直接加载num1 - 1
end else begin
count_r <= count_r - 1; //倒计时
if (count_r == 1) begin
sign_r <= 1; //在count_r达到1时切换到模式1
end
end
end
// ...其他模式...
endcase
end
end
功能:实现两个不同的数值(num1和num2)之间的循环倒计时。 可以看作是一个简化的状态机, 具有4种状态, 每种状态对应不同的倒计时数值。
关键点:
count_r:4位寄存器, 用于存储当前的倒计时数值。
sign_r:2位寄存器, 作为状态指示器, 用于控制计数模式。 使用sign_r实现了简单的状态机,在四个状态中循环跳转.
case (sign_r): 根据当前的状态(sign_r的值)选择不同的计数模式。
count_r <= num1 - 1; / count_r <= num2 - 1;: 在每种状态下, 当计数器达到0时, 重新加载预设的初始值(num1 - 1或num2 - 1)。
倒计时策略:从指定值(num1 - 1 or num2 - 1)开始递减到1,目的是保证进入每种状态都有一个完整的num1和num2那么多个周期.
②调色器模块相关代码:
reg r_r;
reg b_r;
reg g_r;
reg [7:0] counter;
reg [7:0] brightness;
assign r = r_r;
assign b = b_r;
assign g = g_r;
always @(posedge clk) begin
brightness <= 120;
counter = counter + 1;
if (state0 == 0 && state1 ==0)begin
r_r = 0;
b_r = 1;
g_r = 1;
end
// ...其他状态...
end
功能:根据输入信号(state0和state1), 控制RGB LED的颜色和亮度。 调色器通过调节不同颜色分量的占空比来实现不同的颜色效果.
关键点:
r_r, b_r, g_r: 寄存器, 用于存储红、绿、蓝颜色分量的输出值(0或1)。
counter:8位计数器, 用于实现PWM (脉冲宽度调制)控制。
brightness:8位寄存器, 用于控制LED的亮度。
if (counter < brightness) ... else ...: 使用PWM控制LED的亮度。 当计数器的值小于brightness时, 输出高电平(点亮LED); 否则, 输出低电平(关闭LED)。
只根据state0和state1两个信号,设置灯的显示方式
黄色LED的亮度通过PWM调节实现
③数码管译码器模块相关代码:
reg [6:0] temp_seg1;
reg [6:0] temp_seg2;
always @(*) begin
if (Y0 == 0) begin
temp_seg2 = 7'b0111111; //个位显示0
temp_seg1 = 7'b0111111; //十位显示0
end else if (Y1 == 0) begin
temp_seg2 = 7'b0000110; //个位显示1
temp_seg1 = 7'b0111111; //十位显示0
end
// ...其他条件...
end
功能:将输入的4位BCD码转换为数码管的7段显示信号。
关键点:
temp_seg1, temp_seg2:7位寄存器, 用于存储两个数码管的段码值。
if (Y0 == 0) ... else if (Y1 == 0) ...: 使用一系列if-else语句根据输入的BCD码, 设置数码管的段码值。
例如,如果输入为0 (Y0 == 0), 则将temp_seg2设置为7'b0111111, 对应于数码管显示"0"的段码。
①蜂鸣器生成模块 (decoder 模块内):
// 定义频率和计数器
reg [15:0] counter;
reg buzzer_r;
parameter CLK_FREQ = 12_000_000; // 假设时钟频率为 12MHz
parameter BEEP_FREQ = 1_000; // 蜂鸣器频率为 1kHz
parameter COUNTER_MAX = CLK_FREQ / (2 * BEEP_FREQ); // 计数器最大值
// 生成方波
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
buzzer_r <= 0;
end else begin
if (counter == COUNTER_MAX) begin
counter <= 0;
buzzer_r <= ~buzzer_r; // 翻转蜂鸣器信号
end else begin
counter <= counter + 1;
end
end
end
// 控制蜂鸣器开关
reg beep_enable;
always @(*) begin
beep_enable = ((prox_dat2[11:9] == 3'b111)||(prox_dat2[11:9] == 3'b110)||(prox_dat2[11:9] == 3'b101)) ? 1'b1 : 1'b0; // 使能蜂鸣器
end
assign buzzer = beep_enable ? buzzer_r : 1'b0; // 输出蜂鸣器信号
功能:生成用于驱动蜂鸣器的PWM 信号, 并根据接近程度数据控制蜂鸣器的启停。
关键点:
CLK_FREQ: 定义系统时钟频率 (12MHz)。
BEEP_FREQ: 定义蜂鸣器信号的频率 (1kHz)。
COUNTER_MAX: 根据时钟频率和蜂鸣器频率计算计数器的最大值。
buzzer_r <= ~buzzer_r;: 通过翻转 buzzer_r 信号, 生成 方波。
beep_enable: 根据接近程度数据 (prox_dat2[11:9]) 控制蜂鸣器的使能。当接近程度数据满足特定条件时, 使能蜂鸣器。
assign buzzer = beep_enable ? buzzer_r : 1'b0;: 使用条件运算符根据 beep_enable 信号控制蜂鸣器的输出。
蜂鸣器发声频率固定, 由代码中的BEEP_FREQ参数决定. 只能控制响与不响.
②光照过低点亮 LED 灯模块 (segment_scan 模块内):
// 计算显示的数字
reg [7:0] integer_part;
reg [7:0] decimal_part;
reg [15:0] display_value;
//led灯寄存器
reg led_red_r;
reg led_green_r;
reg led_blue_r;
always @(*) begin
integer_part = dat_5 * 10 + dat_6; // 整数部分 dat_4 * 10 +
decimal_part = dat_7 * 10 + dat_8; // 小数部分
display_value = integer_part * 100 + decimal_part; // 显示的数字乘以 100
end
assign led_red = led_red_r;
assign led_green = led_green_r;
assign led_blue = led_blue_r;
//判断led灯
always @(*) begin
if ((display_value < 1000)&&(dat_4 == 0)&&(dat_5 == 0)) begin
led_red_r <= 0;
led_green_r <= 0;
led_blue_r <= 0;
end else begin
led_red_r <= 1;
led_green_r <= 1;
led_blue_r <= 1;
end
end
功能:根据从传感器读取的数据,如果数据有效,控制 RGB LED 灯同时亮灭, 不进行颜色区分。 实际是照度高了就全部熄灭,否则就同时亮起。
关键点:
dat_1 - dat_8: 来自 decoder 模块, 存储数码管的显示数据 (BCD 码)。
integer_part 和 decimal_part: 用于计算显示的数字的整数部分和小数部分。
display_value: 计算出的完整的显示数值。
led_red_r、 led_green_r、 led_blue_r: 寄存器, 用于存储 RGB LED 灯的控制信号 (0 或 1)。
if ((display_value < 1000)&&(dat_4 == 0)&&(dat_5 == 0)) ... else ...: 根据显示数值是否小于 10.00 来判断是否点亮 LED 灯。 该条件可能需要根据实际情况进行调整。如果显示的数值小于 10,就关闭三个灯,否则同时点亮三个灯。
五.功能展示图及说明
(一)第一部分:交通灯
①红灯亮起,进行红灯倒数
②黄灯亮起,进行黄灯倒数
③绿灯亮起,进行绿灯倒数,同时蜂鸣器响起
②黄灯亮起,进行黄灯倒数,结束后返回红灯状态进行循环
(二)第二部分:亮度与接近检测
①正常状态
②亮度低于固定值(设定为10.00),led灯亮起
③过于接近(具体表现在表示接近程度的led灯亮起大于五个),蜂鸣器响起,为了便于图片展示,这里用数码管发光来表现蜂鸣器(核心板右侧数字最上方的数码管)
六.项目中遇到的难题和解决方法
①问题:WebIDE图形化编程的学习曲线较陡峭,难以快速上手。
解决方法:参考WebIDE的例程,并积极向他人请教。
②问题:WebIDE图形化编程比较困难,难以找到代码中的错误。
解决方法:导出main文件后再查找错误。
③问题:数码管显示亮度不够,在白天难以看清。
解决方法:在低光环境下进行拍摄。
对本次活动的心得体会(包括意见或建议):
这次寒假练活动让我受益匪浅。通过这个项目,我不仅巩固了数字电路的知识,还学习了WebIDE图形化编程和Verilog编程。在项目开发过程中,我遇到了许多困难,但是通过查阅资料、咨询他人、调试代码,最终都成功解决了。这次活动让我深刻体会到了理论与实践相结合的重要性,也让我对电子设计产生了更浓厚的兴趣。
七.意见或建议
希望活动组织方能够提供更多的WebIDE图形化编程的例程,方便初学者学习和参考。
希望活动组织方能够提供更详细的74系列逻辑门电路的应用资料,帮助初学者更好地理解数字电路的原理。
希望活动组织方能够组织更多的线上交流活动,让大家能够互相学习,互相帮助。
八.FPGA资源占用报告以及项目链接
WebIDE项目链接:https://www.stepfpga.com/project/17066/gui?type=top
第一部分
第二部分