项目介绍
使用WebIDE的图形化编程,使用常规的74系列的元器件,构建一个交通灯控制系统:
要求1:在数码管上显示计时信息- 图形化
要求2:蜂鸣器报警- 图形化
要求3:接近传感器检测人员走近-Verilog
要求4:环境光感知,自动点亮路灯(小脚丫核心板上的单色LED)- Verilog
使用板卡:STEP Baseboard4.0底板+STEP MXO2 LPC核心板
前两个要求用WebIDE的图形化实现,后两个要求用本地软件Diamond来实现。
设计思路
由于要求1与要求2通过同一个工程得到实现,要求3与要求4通过另一个工程实现,所以在后续的报告中将分开介绍两者。
要求1与要求2
1.系统功能概述
根据项目需求进行分析,所设计的交通灯控制系统应具备以下几个核心功能:
- 整数分频器将高频的系统时钟分频为低频信号,以驱动状态机和倒计时逻辑。
- 通过状态机控制交通灯的四种状态(S1-S4),每个状态对应不同的LED灯组合和倒计时时间以及蜂鸣器报警信号。
- 核心板上的数码管实时显示倒计时数值,三色LED灯实时变换颜色,蜂鸣器在状态切换时发出警报。
2.模块划分
为了实现核心功能,并适应图形化编程的特点,将系统划分为五个模块:
- 主模块:顶层模块,连接所有子模块,协调时钟、复位、蜂鸣器、数码管和交通灯等信号的传输。
- 时钟分频模块:将系统时钟分频为低频信号,供状态机使用。
- 状态机与倒计时模块:实现状态机逻辑,管理倒计时、LED状态切换和蜂鸣信号。
- 蜂鸣器模块:根据状态机的标志信号生成特定频率的蜂鸣警报。
- 数码管显示模块:将倒计时数值转换为七段数码管编码并输出。
模块划分图
3.流程图
本系统采用的状态机包含状态S1、S2、S3、S4,通过倒计时结束来触发状态切换,形成闭环。状态机切换的流程图如下:
流程图
要求3与要求4
要求3和要求4可以通过修改平台所给的lab8例程来实现。分析可得,原有的例程可实现的功能是:在数码管上实时显示光照强度、通过核心板上亮起的单色LED灯的个数体现事物与接近传感器的距离。因此,只需要在此基础上进行修改以实现这两个功能:
- 接近传感器检测:当人员或物体靠近接近传感器时,点亮一个单色LED灯。
- 环境光感知:当环境光减弱到一定程度时,点亮一个单色LED灯。
根据要求,整个系统的框图设计为:
细节上,人员走近检测和自动感应路灯是两个独立的功能,它们的流程图如下:
关键代码介绍
要求1与要求2
前两个要求是通过WebIDE的图形化编程实现的,项目链接为:程序WebIDE链接
根据上一步的设计,框架主体包括时钟分频模块、状态机与倒计时模块、蜂鸣器控制模块与数码管显示模块。
时钟分频模块
分频器根据分频系数(参数N)生成低频时钟信号,输出一个1秒的时钟周期clk1h。
assign clkout = (N==1)? clk1:(N[0]? clk3:clk2);
状态机与倒计时模块
1. 状态机设计
定义了四个状态:S1对应的是红灯,倒计时为9秒;S2对应的是红蓝灯,倒计时为3秒;S3对应的是绿灯,倒计时为7秒;S4对应的是白灯,倒计时为3秒。
parameter S1 = 4'b00, //状态机状态编码
S2 = 4'b01,
S3 = 4'b10,
S4 = 4'b11;
parameter time_s1 = 4'd9, //计时参数
time_s2 = 4'd3,
time_s3 = 4'd7,
time_s4 = 4'd3;
//交通灯的控制
parameter led_s1 = 6'b110110, // 红色
led_s2 = 6'b011110, // 红蓝色
led_s3 = 6'b101101, // 绿色
led_s4 = 6'b000000; // 白色
2. 第一段(同步逻辑)
描述次态到现态的转移,根据复位信号或时钟更新当前状态。
always @ (posedge clk1h or negedge rst_n)
begin
if(!rst_n)
cur_state <= S1;
else
cur_state <= next_state;
end
3. 第二段(组合逻辑)
状态切换逻辑。通过判断倒计时(tiomecont)是否归零来切换状态,并更新倒计时数值以及蜂鸣信号。
always @ (cur_state or rst_n or timecont)
begin
if(!rst_n) begin
next_state = S1;
end
else begin
case(cur_state)
S1:begin
if(timecont==1) begin
next_state = S2;
flag=1'b0;end
else begin
next_state = S1;
flag=1'b0;end
end
S2:begin
if(timecont==1) begin
next_state = S3;
flag=1'b1;end
else begin
next_state = S2;
flag=1'b1;end
end
S3:begin
if(timecont==1) begin
next_state = S4;
flag=1'b0;end
else begin
next_state = S3;
flag=1'b0;end
end
S4:begin
if(timecont==1) begin
next_state = S1;
flag=1'b1;end
else begin
next_state = S4;
flag=1'b1;end
end
default: next_state = S1;
endcase
end
end
4. 第三段(同步逻辑)
倒计时与输出控制。根据系统当前所处状态来更新倒计时和数码管显示数值,LED灯的输出也在这个部分实现。
always @ (posedge clk1h or negedge rst_n)
begin
if(!rst_n==1) begin
out <= led_s1;
timecont <= time_s1;
cnt_ge <= 4'd9;
end
else begin
case(next_state)
S1:begin
out <= led_s1;
if(timecont == 1) begin
timecont <= time_s1;
cnt_ge <= 4'd9;end
else begin
timecont <= timecont - 1;
cnt_ge <= cnt_ge - 1;end
end
S2:begin
out <= led_s2;
if(timecont == 1) begin
timecont <= time_s2;
cnt_ge <= 4'd3;end
else begin
timecont <= timecont - 1;
cnt_ge <= cnt_ge - 1;
end
end
S3:begin
out <= led_s3;
if(timecont == 1) begin
timecont <= time_s3;
cnt_ge <= 4'd7;end
else begin
timecont <= timecont - 1;
cnt_ge <= cnt_ge - 1;end
end
S4:begin
out <= led_s4;
if(timecont == 1) begin
timecont <= time_s4;
cnt_ge <= 4'd3;end
else begin
timecont <= timecont - 1;
cnt_ge <= cnt_ge - 1;end
end
default:begin
out <= led_s1;
end
endcase
end
end
蜂鸣器控制模块
由于板卡内置的蜂鸣器是一个无源蜂鸣器,所以需要生成方波信号来使它蜂鸣报警。使用计数器生成指定频率的方波信号,只有当蜂鸣信号(flag)有效时,计数器才会翻转beep信号,生成方波,蜂鸣器发出警报声。
reg beep;
reg [31:0] counter;// 计数器
parameter CLK_FREQ = 50000000;// 输入时钟频率
parameter BEEP_FREQ = 2000;//蜂鸣器频率
localparam HALF_PERIOD = CLK_FREQ / (2* BEEP_FREQ);
//生成固定频率方波
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)begin
counter <= 0;
beep <= 0;end
else if (flag)begin
if(counter >= HALF_PERIOD -1)begin
counter <= 0 ;
beep <= ~beep ;end//翻转信号
else begin
counter <= counter + 1 ;end
end
end
数码管显示模块
先把十进制数值转换为七段数码管编码。
reg [6:0] seg [9:0];
//数显设置
initial
begin
seg[0] = 7'h3f; // 0
seg[1] = 7'h06; // 1
seg[2] = 7'h5b; // 2
seg[3] = 7'h4f; // 3
seg[4] = 7'h66; // 4
seg[5] = 7'h6d; // 5
seg[6] = 7'h7d; // 6
seg[7] = 7'h07; // 7
seg[8] = 7'h7f; // 8
seg[9] = 7'h6f; // 9
end
将倒计时的个位数值和十位数值分别映射到两个数码管。
assign seg_led_1[8:0] = {2'b00,seg[cnt_ge]};
assign seg_led_2[8:0] = {2'b00,seg[cnt_shi]};
管脚分配
程序的管脚分配如下:
要求3与要求4
程序代码是在所给例程上进行修改得到的,与原有例程对比,删去了整个segment.v文件以及decoder.v和prox_detect.v文件里有关数码管显示的部分。
在decoder.v增加以下关键模块,初始态没有LED小灯亮起,当感应到人员靠近接近传感器时,核心板上的第一个单色LED小灯亮起;当感应到环境光减弱到一定程度时,核心板上的最后一个单色LED小灯亮起。
// LED控制
always @(*) begin
Y_out = 8'b11111111;
// 接近检测
if(prox_dat2 > 16'h200)
Y_out[0]= 1'b0;
// 环境光感知
if(lux_data[31:08]<5'b11110 )
Y_out[7]= 1'b0;
end
功能展示图及说明
要求1与要求2
程序开始运行,首先显示红灯倒计时。
红灯结束后,变为红蓝灯并发出蜂鸣,持续3秒。
显示绿灯倒计时,时长为7秒。
绿灯结束后,变为白灯并发出蜂鸣,持续3秒。之后将继续显示红灯,进行循环。
要求3与要求4
初始没有小灯亮起。
当笔头靠近接近传感器时,第一个小灯亮起。
当环境光变弱时,最后一个小灯亮起。
用手覆盖住两个传感器所在的位置,两个小灯都亮起。
FPGA资源占用报告
要求1与要求2
Design Summary:
Number of registers: 82 out of 4635 (2%)
PFU registers: 82 out of 4320 (2%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 85 out of 2160 (4%)
SLICEs as Logic/ROM: 85 out of 2160 (4%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 63 out of 2160 (3%)
Number of LUT4s: 169 out of 4320 (4%)
Number used as logic LUTs: 43
Number used as distributed RAM: 0
Number used as ripple logic: 126
Number used as shift registers: 0
Number of PIO sites used: 27 + 4(JTAG) out of 105 (30%)
Number of block RAMs: 0 out of 10 (0%)
Number of GSRs: 1 out of 1 (100%)
EFB used : No
JTAG used : No
Readback used : No
Oscillator used : No
Startup used : No
POR : On
Bandgap : On
Number of Power Controller: 0 out of 1 (0%)
Number of Dynamic Bank Controller (BCINRD): 0 out of 6 (0%)
Number of Dynamic Bank Controller (BCLVDSO): 0 out of 1 (0%)
Number of DCCA: 0 out of 8 (0%)
Number of DCMA: 0 out of 2 (0%)
Number of PLLs: 0 out of 2 (0%)
Number of DQSDLLs: 0 out of 2 (0%)
Number of CLKDIVC: 0 out of 4 (0%)
Number of ECLKSYNCA: 0 out of 4 (0%)
Number of ECLKBRIDGECS: 0 out of 2 (0%)
要求3与要求4
Design Summary
Number of registers: 214 out of 4635 (5%)
PFU registers: 212 out of 4320 (5%)
PIO registers: 2 out of 315 (1%)
Number of SLICEs: 972 out of 2160 (45%)
SLICEs as Logic/ROM: 972 out of 2160 (45%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 342 out of 2160 (16%)
Number of LUT4s: 1943 out of 4320 (45%)
Number used as logic LUTs: 1259
Number used as distributed RAM: 0
Number used as ripple logic: 684
Number used as shift registers: 0
Number of PIO sites used: 15 + 4(JTAG) out of 105 (18%)
Number of block RAMs: 0 out of 10 (0%)
Number of GSRs: 1 out of 1 (100%)
EFB used : No
JTAG used : No
Readback used : No
Oscillator used : No
Startup used : No
POR : On
Bandgap : On
Number of Power Controller: 0 out of 1 (0%)
Number of Dynamic Bank Controller (BCINRD): 0 out of 6 (0%)
Number of Dynamic Bank Controller (BCLVDSO): 0 out of 1 (0%)
Number of DCCA: 0 out of 8 (0%)
Number of DCMA: 0 out of 2 (0%)
Number of PLLs: 0 out of 2 (0%)
Number of DQSDLLs: 0 out of 2 (0%)
Number of CLKDIVC: 0 out of 4 (0%)
Number of ECLKSYNCA: 0 out of 4 (0%)
Number of ECLKBRIDGECS: 0 out of 2 (0%)
难题和解决方法
在刚开始尝试实现第二个任务要求的时候,发现蜂鸣器总是不工作,后来经过学习才发现无源蜂鸣器需要靠方波信号激发。
心得体会
通过这次实践第一次接触到FPGA,尽管过程中出现了很多问题,但在最后功能得到实现的那一刻是很有成就感的,体会到了程序开发的乐趣。同时,通过这次活动提升了自己的编程能力和动手能力。