学习内容:
今天学习了led流水灯,以及跑马灯的实现,有限状态机知识的回顾,更重要的是呼吸灯的实现。值得肯定的是,今天对fpga的代码实现有了进一步认识,基本掌握了如何去书写的基本结构,以及仿真文件的一些参数的含义。但不足的是,今天对于呼吸灯和流水灯的结合实现,没能顺利完成,当然,在这其中也经过很多思考,也是很值得肯定的。
困难的产生与解决:
1. 今天发现有些同学编译不成功,说mutil..... 这种一般是,写了多个相同的变量在不同的地方被赋值。特别是多个always中,因为always之间是并列进行的(即:可理解为多线程的)。
2. 呼吸灯的实现,开始没懂。其实现其实比较巧妙,虽然这个普通的led灯没有多个电平的分级,但可以实现在时间上的分级,即 持续高电平10ns和持续100ns 其亮度是不一样的。这其中实现很巧妙,很值得反复琢磨。
还有今天把实现流水灯与呼吸灯结合的任务理解为了 跑马灯与呼吸灯结合,这难度却不料想是要大得多的。但说实话也很期待实现。
疑问产生:
wire类型变量和寄存器reg变量有什么区别,特别是在使用的时候有什么区别?
接下来打算:
后面将进一步思考流水灯和呼吸灯的实现,以及进一步思考跑马灯和呼吸灯结合,看能实现不。还有就是,尽量把呼吸灯的实现逻辑,过程细节,能想清楚。
收获杂记:
仿真文件中:
步骤① ,是传入参数值的方式
前面那个 .TIME 是fsm_led 中的参数名字 括号中的TIME是该仿真文件中的文件
下面还有就是今天实现的一些代码,包括流水灯,跑马灯,呼吸灯,流水灯与呼吸灯结合。
其中实现方法多种多样,比如流水灯,可以通过case列举的方式实现定时移位,可以用移位<<符号进行状态移位,还有用状态机,进行状态转移(文中的方法就是用的有限状态机)
(有限状态机:就是给一个初始状态,然后就会在这个状态内相互转换,实质也就是把所有情况列举出,然后给予一定转化条件,这种思考设计方式就叫有限状态机设计(个人理解))
流水灯代码:(有限状态机)
module fsm_led(
input clk,
input rst_n,
output reg[3:0] led
);
parameter TIME = 24 'd9_999_999;//计数器的挤时上限
//状态空间
parameter S_LED0 = 2'd0;
parameter S_LED1 = 2'd1;
parameter S_LED2 = 2'd2;
parameter S_LED3 = 2'd3;
//四个LED的值
parameter LED0 = 4'b0001;
parameter LED1 = 4'b0010;
parameter LED2 = 4'b0100;
parameter LED3 = 4'b1000;
reg [1:0] state;//保存正处于的状态
reg [23:0] cnt ;//计数寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 24 'd0;
end
else if (cnt == TIME) begin
cnt <=24'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
state <= S_LED0;
end
else begin
case (state)
S_LED0:begin
if (cnt == TIME) begin
state <= S_LED1;//切换到 下一个状态
led <=LED1;
end
else begin
state <= S_LED0;//保持原有状态
led <=LED0;
end
end
S_LED1:begin
if (cnt == TIME) begin
state <= S_LED2;//切换到 下一个状态
led <=LED2;
end
else begin
state <= S_LED1;//保持原有状态
led <=LED1;
end
end
S_LED2:begin
if (cnt == TIME) begin
state <= S_LED3;//切换到 下一个状态
led <=LED3;
end
else begin
state <= S_LED2;//保持原有状态
led <=LED2;
end
end
S_LED3:begin
if (cnt == TIME) begin
state <= S_LED0;//切换到 下一个状态
led <= LED0;
end
else begin
state <= S_LED3;//保持原有状态
led <= LED3;
end
end
default: ;
endcase
end
end
endmodule
跑马灯:
module horse_led(
input clk,
input rst_n,
output [3:0] led
);
parameter TIME = 24'd9_999_999;//一个状态持续时间
reg [23:0] cnt;
reg [7:0] led_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt = 24'd0;
end
else if(cnt == TIME)begin
cnt <=24'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
led_reg <= 8'b1111_0000;//跑马灯 从全灭到全亮再逐渐全灭,实质就是这八位的循环变化
end
else if(cnt == TIME)begin
led_reg <={led_reg[0],led_reg[7:1]};
end
else begin
led_reg <= led_reg;
end
end
assign led = led_reg[3:0];
endmodule
呼吸灯:(时间分层实现(非电平分级))
module breath_led(
input clk,
input rst_n,
output reg led
);
parameter cnt_us = 6'd50;
parameter cnt_ms = 10'd1000;
parameter cnt_s=10'd1000 ;
reg [5:0] cnt1;
wire add_cnt1;//计时开始的标志
wire end_cnt1;//计时器结束的标志
reg [9:0] cnt2;
wire add_cnt2;//计时开始的标志
wire end_cnt2;//计时器结束的标志
reg [9:0] cnt3;
wire add_cnt3;//计时开始的标志
wire end_cnt3;//计时器结束的标志
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt1 <= 6'd0;
end
else if (add_cnt1) begin
if (end_cnt1) begin
cnt1 <= 6'd0;
end
else begin
cnt1 <= cnt1+1'd1;
end
end
else begin
cnt1 <= cnt1;
end
end
assign add_cnt1 = 1;
assign end_cnt1 = add_cnt1 && cnt1==cnt_us;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt2 <= 10'd0;
end
else if (add_cnt2) begin
if (end_cnt2) begin
cnt2 <= 10'd0;
end
else begin
cnt2 <= cnt2+1'd1;
end
end
else begin
cnt2 <= cnt2;
end
end
assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && cnt2==cnt_ms;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt3 <= 10'd0;
end
else if (add_cnt3) begin
if (end_cnt3) begin
cnt3 <= 10'd0;
end
else begin
cnt3 <= cnt3+1'd1;
end
end
else begin
cnt3 <= cnt3;
end
end
assign add_cnt3 = end_cnt2;
assign end_cnt3 = add_cnt3 && cnt3==cnt_s;
reg [1:0] flag;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
flag <= 1'd0;
end
else if(end_cnt3)begin
flag = ~flag;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led <= 1'd0;
end
else if (!flag) begin
led <= cnt3>cnt2?1'b1:1'b0;
end
else if(flag) begin
led <= cnt3>cnt2?1'b0:1'b1;
end
else
led <= led;
end
endmodule
流水灯式呼吸灯
module breath_led(
input clk,
input rst_n,
output reg [3:0]led
);
parameter TIME = 100_000_000;//间隔2s
//状态空间
parameter S_LED0 = 2'd0;
parameter S_LED1 = 2'd1;
parameter S_LED2 = 2'd2;
parameter S_LED3 = 2'd3;
//三个计时器的计时上限
parameter time_us = 50;
parameter time_ms = 1000;
parameter time_s = 1000;
reg [5:0] cnt_us;
wire add_cnt_us;//开始计时的标志
wire end_cnt_us;//结束计时的标志
reg [9:0] cnt_ms;
wire add_cnt_ms;//开始计时的标志
wire end_cnt_ms;//结束计时的标志
reg [9:0] cnt_s;
wire add_cnt_s;//开始计时的标志
wire end_cnt_s;//结束计时的标志
reg flag;//亮灭切换标志
reg [3:0] led_reg;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_us <= 6'd0;
end
else if(add_cnt_us)begin
if(end_cnt_us)begin
cnt_us <= 6'd0;
end
else begin
cnt_us <= cnt_us + 1'd1;
end
end
else begin
cnt_us <= cnt_us;
end
end
assign add_cnt_us = 1;
assign end_cnt_us = add_cnt_us && cnt_us == time_us - 1'd1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_ms <= 10'd0;
end
else if(add_cnt_ms)begin
if(end_cnt_ms)begin
cnt_ms <= 10'd0;
end
else begin
cnt_ms <= cnt_ms + 1'd1;
end
end
else begin
cnt_ms <= cnt_ms;
end
end
assign add_cnt_ms = end_cnt_us;
assign end_cnt_ms = add_cnt_ms && cnt_ms == time_ms - 1'd1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_s <= 10'd0;
end
else if(add_cnt_s)begin
if(end_cnt_s)begin
cnt_s <= 10'd0;
end
else begin
cnt_s <= cnt_s + 1'd1;
end
end
else begin
cnt_s <= cnt_s;
end
end
assign add_cnt_s = end_cnt_ms;
assign end_cnt_s = add_cnt_s && cnt_s == time_s - 1'd1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag <= 1'b0;
end
else if(end_cnt_s)begin//计满一秒,led完成了从灭→亮的变化
flag <= ~flag;
end
else begin
flag <= flag;
end
end
reg [26:0] cnt;//时钟计数器
reg [1:0] current_stat;//当前状态寄存器
//计时模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin//复位
cnt <= 27'd0;//计数器清0
end
else if(cnt == TIME - 1)begin//记满1s
cnt <= 27'd0;//计数器清0
end
else begin
cnt <= cnt + 27'd1;//其他时间加1
end
end
//状态切换
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
current_stat <= 2'd0;//当前状态初始化为0
end
else begin
case(current_stat)
S_LED0: begin//状态为0时
if(cnt == TIME - 1)begin
current_stat <= S_LED1;
led[0] <= 1'b0;
end
else begin
current_stat <= S_LED0;
if(!flag)begin
led[0] <= (cnt_ms<cnt_s)?1'b0:1'b1;
end
else begin
led[0] <= (cnt_ms>cnt_s)?1'b0:1'b1;
end
end
end
S_LED1: begin
if(cnt == TIME - 1)begin
current_stat <= S_LED2;
led[1] <= 1'b0;
end
else begin
current_stat <= S_LED1;
if(!flag)begin
led[1] <= (cnt_ms<cnt_s)?1'b0:1'b1;
end
else begin
led[1] <= (cnt_ms>cnt_s)?1'b0:1'b1;
end
end
end
S_LED2: begin
if(cnt == TIME - 1)begin
current_stat <= S_LED3;
led[2] <= 1'b0;
end
else begin
current_stat <= S_LED2;
if(!flag)begin
led[2] <= (cnt_ms<cnt_s)?1'b0:1'b1;
end
else begin
led[2] <= (cnt_ms>cnt_s)?1'b0:1'b1;
end
end
end
S_LED3: begin
if(cnt == TIME - 1)begin
current_stat <= S_LED0;
led[3] <= 1'b0;
end
else begin
current_stat <= S_LED3;
if(!flag)begin
led[3] <= (cnt_ms<cnt_s)?1'b0:1'b1;
end
else begin
led[3] <= (cnt_ms>cnt_s)?1'b0:1'b1;
end
end
end
default:;
endcase
end
end
endmodule
注:本次及以后采用的芯片型号均为:EP4CE6F17C8