实验要求
依旧还是点灯大师修炼环节,从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设计思想与验证方法