实验要求

    依旧还是点灯大师修炼环节,从led实验中摘出一个有点意思的,分享一下实现思路。最终要实现第二个试验,为了让思路更流畅,第一个实验要求是为第二个实验做了思路上的基础,不过仅做展示,做思考用,重点实现第二个实验要求。
1.控制一个led按照用户输入(8位二进制数)进行亮灭,且亮灭持续时长相等。即一共有8个相等时段,每个时段led亮灭由输入控制。功能目标抽象为8个大小一样的箱子中放小球,放或者不放
2.每隔 10ms让 LED 灯的一个8状态循环执行一次。

设计输入

实验1

    实验1完整代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
module led_counter_3(
input i_sys_clk,
input i_sys_rst_n,
input [7:0] i_led_option,//8bit 二进制控制每个时段led灯亮或者灭
input [3:0] i_timeSpan, //输入的是计数的最大值,如果是直接输入时间,需要单独写一个时间转换成计数最大值的模块,这个也不难,这里为了方便省略一下

output reg o_led
);

reg [3:0] r_cnt_time;
reg [2:0] r_cnt_num ;

//r_cnt_time计数器定义
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_time <= 0;
else if(r_cnt_time == i_timeSpan - 1)
r_cnt_time <= 0;
else
r_cnt_time <= r_cnt_time + 1;
end

//r_cnt_num计数器定义
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_num <= 0;
else if(r_cnt_num == 3'd7 && r_cnt_time == i_timeSpan - 1)
r_cnt_num <= 0;
else if(r_cnt_time == i_timeSpan - 1)
r_cnt_num <= r_cnt_num + 1;
else
r_cnt_num <= r_cnt_num;
end

//
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
o_led <= 0;
else case (r_cnt_num)
0: o_led <= i_led_option[0];
1: o_led <= i_led_option[1];
2: o_led <= i_led_option[2];
3: o_led <= i_led_option[3];
4: o_led <= i_led_option[4];
5: o_led <= i_led_option[5];
6: o_led <= i_led_option[6];
7: o_led <= i_led_option[7];
default: o_led <= o_led;
endcase
end

endmodule

实验2

    针对实验2,一共写了两个程序,一是在8个循环的最后拼接上间隔时段,然后再重新进行循环。二是定义大的循环时段,在每一个时段里面的某一时间段执行该循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//方法1-改动代码

//间隔时间计数器
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_interval <= 0;
else if(r_cnt_interval == Interval_CNT_MAX - 1)
r_cnt_interval <= 0;
else if(r_cnt_num == STATE_NUM - 1) //在状态树龄计数器为8的时候开始计数
r_cnt_interval <= r_cnt_interval + 1;
else
r_cnt_interval <= r_cnt_interval;
end

//状态数量计数器
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_num <= 0;
else if(r_cnt_num == STATE_NUM - 1 && r_cnt_interval == Interval_CNT_MAX - 1) //把中间的时间间隔作为第9个状态构成一个循环
r_cnt_num <= 0;
else if(r_cnt_num == Interval_CNT_MAX - 2 && r_cnt == i_timeSpan -1) //重要改动
r_cnt_num <= STATE_NUM - 1;
else if(r_cnt == i_timeSpan - 1)
r_cnt_num <= r_cnt_num + 1;
else
r_cnt_num <= r_cnt_num;
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//方法2-改动代码

//间隔时间计数器
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_interval <= 0;
else if(r_cnt_interval == Interval_CNT_MAX - 1)
r_cnt_interval <= 0;
else
r_cnt_interval <= r_cnt_interval + 1;
end

//每个状态时长计数器
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_time <= 0;
else if(r_cnt_time == i_timeSpan - 1)
r_cnt_time <= 0;
else if(flag) //改动
r_cnt_time <= r_cnt_time + 1;
else
r_cnt_time <= r_cnt_time;
end

//状态数量计数器
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
r_cnt_num <= 0;
else if(r_cnt_num == 3'd7 && r_cnt_time == i_timeSpan - 1)
r_cnt_num <= 0;
else if(r_cnt_time == i_timeSpan - 1)
r_cnt_num <= r_cnt_num + 1;
else
r_cnt_num <= r_cnt_num;
end

//标志信号-重要改动
always @(posedge i_sys_clk, negedge i_sys_rst_n) begin
if(!i_sys_rst_n)
flag <= 0;
else if(r_cnt_num == 3'd7 && r_cnt_time == i_timeSpan - 1)
flag <= 0;
else if(r_cnt_interval == 0)
flag <= 1;
else
flag <= flag;
end

    总结起来,两个程序能实现相同的效果,第一个程序思路在于“8个紧挨着的箱子中方或者不放小球,中间是空地,然后再放8个这样的箱子”;第二个程序思路在于“连续分隔出相同间隔的相邻空地,在每一块空地上放这8个紧挨的箱子”。
    不过要实现这种“执行一次循环+空白+执行一次循环”的目的,两种程序都能实现最终目的,并且程序一的“时间间隔计数器最大值”小于第二个程序。

实验题目来源

    实验来自以下链接,代码为个人编写。
1.小梅哥-FPGA设计思想与验证方法