目录
本文分享利用FPGA实现的遥控灯控制器设计,实现灯的开关以及亮度调节控制功能。具体功能如下:通过红外遥控器控制LED开灯、关灯、高亮、中亮、低亮效果。
顶层设计:
顶层视图如下图 所示,由四个模块构成,分别是红外遥控模块inf_rcv、数码管显示模块seg_595_dynamic、led灯信号产生模块pwm以及重复码提示灯模块。
模块分析:
红外遥控模块 inf_rcv:
具体教程请见:基于FPGA的红外遥控详细教程1(verilog)-CSDN博客
module inf_rcv(
input sys_clk,
input sys_rst_n,
input inf_rcv,
output reg [19:0]data,
output reg repeat_en
);
parameter CNT_560US_MIN=19'd20_000;
parameter CNT_560US_MAX=19'd35_000;
parameter CNT_1_69MS_MIN=19'd80_000;
parameter CNT_1_69MS_MAX=19'd90_000;
parameter CNT_2_25MS_MIN=19'd100_000;
parameter CNT_2_25MS_MAX=19'd125_000;
parameter CNT_4_5MS_MIN=19'd175_000;
parameter CNT_4_5MS_MAX=19'd275_000;
parameter CNT_9MS_MIN=19'd400_000;
parameter CNT_9MS_MAX=19'd490_000;
parameter IDLE=5'b00001;
parameter TIME_9MS=5'b00010;
parameter ARBIT=5'b00100;
parameter DATA=5'b01000;
parameter REPEAT=5'b10000;
reg [4:0]state;
reg inf_in_dly1;
reg inf_in_dly2;
reg [18:0]cnt;
wire inf_in_rise;
wire inf_in_fall;
reg flag_9ms;
reg flag_4_5ms;
reg [5:0]cnt_data;
reg flag_1_69ms;
reg flag_560us;
reg [31:0]data_reg;
reg flag_2_25ms;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
state<=IDLE;
else case(state)
IDLE:
if(inf_in_fall)
state<=TIME_9MS;
else
state<=IDLE;
TIME_9MS:
if((inf_in_rise==1'b1)&&(flag_9ms==1'b1))
state<=ARBIT;
else if((inf_in_rise==1'b1)&&(flag_9ms==1'b0))
state<=IDLE;
else
state<=TIME_9MS;
ARBIT:
if((inf_in_fall==1'b1)&&(flag_2_25ms==1'b1))
state<=REPEAT;
else if((inf_in_fall==1'b1)&&(flag_4_5ms==1'b1))
state<=DATA;
else if((inf_in_fall==1'b1)&&(flag_2_25ms==1'b0)&&(flag_4_5ms==1'b0))
state<=IDLE;
else
state<=ARBIT;
DATA:
if((inf_in_rise==1'b1)&&(flag_560us==1'b0))
state<=IDLE;
else if((inf_in_fall==1'b1)&&(flag_560us==1'b0)&&(flag_1_69ms==1'b0))
state<=IDLE;
else if((inf_in_rise==1'b1)&&(cnt_data==6'd32))
state<=IDLE;
REPEAT:
if(inf_in_rise==1'b1)
state<=IDLE;
else
state<=REPEAT;
default:
state<=IDLE;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
begin
inf_in_dly1<=1'b0;
inf_in_dly2<=1'b0;
end
else
begin
inf_in_dly1<=inf_rcv;
inf_in_dly2<=inf_in_dly1;
end
assign inf_in_fall=(inf_in_dly2==1'b1)&&(inf_in_dly1==1'b0);
assign inf_in_rise=(inf_in_dly1==1'b1)&&(inf_in_dly2==1'b0);
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt<=19'd0;
else
case (state)
IDLE:
cnt<=19'd0;
TIME_9MS:
if((inf_in_rise==1'b1)&&(flag_9ms==1'b1))
cnt<=19'd0;
else
cnt<=cnt+1'b1;
ARBIT:
if((inf_in_fall==1'b1)&&((flag_4_5ms==1'b1)||(flag_2_25ms==1'b1)))
cnt<=19'd0;
else
cnt<=cnt+1'b1;
DATA:
if((inf_in_rise==1'b1)&&(flag_560us==1'b1))
cnt<=19'd0;
else if((inf_in_fall==1'b1)&&((flag_1_69ms==1'b1)||(flag_560us==1'b1)))
cnt<=19'd0;
else
cnt<=cnt+1'b1;
default:
cnt<=19'd0;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
flag_9ms<=1'b0;
else if((state==TIME_9MS)&&(cnt>=CNT_9MS_MIN)&&(cnt<=CNT_9MS_MAX))
flag_9ms<=1'b1;
else
flag_9ms<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
flag_4_5ms<=1'b0;
else if((state==ARBIT)&&(cnt>=CNT_4_5MS_MIN)&&(cnt<=CNT_4_5MS_MAX))
flag_4_5ms<=1'b1;
else
flag_4_5ms<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
flag_560us<=1'b0;
else if((state==DATA)&&(cnt>=CNT_560US_MIN)&&(cnt<=CNT_560US_MAX))
flag_560us<=1'b1;
else
flag_560us<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
flag_1_69ms<=1'b0;
else if((state==DATA)&&(cnt>=CNT_1_69MS_MIN)&&(cnt<=CNT_1_69MS_MAX))
flag_1_69ms<=1'b1;
else
flag_1_69ms<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
flag_2_25ms<=1'b0;
else if((state==ARBIT)&&(cnt>=CNT_2_25MS_MIN)&&(cnt<=CNT_2_25MS_MAX))
flag_2_25ms<=1'b1;
else
flag_2_25ms<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_data<=6'd0;
else if((inf_in_rise==1)&&(cnt_data==6'd32))
cnt_data<=6'd0;
else if((inf_in_fall==1)&&(state==DATA))
cnt_data<=cnt_data+1'd1;
else
cnt_data<=cnt_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
data_reg<=32'b0;
else if((state==DATA)&&(inf_in_fall==1'b1)&&(flag_560us==1'b1))
data_reg[cnt_data]<=1'b0;
else if((state==DATA)&&(inf_in_fall==1'b1)&&(flag_1_69ms==1'b1))
data_reg[cnt_data]<=1'b1;
else
data_reg<=data_reg;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
data<=20'b0;
else if((cnt_data==6'd32)&&(~data_reg[23:16]==data_reg[31:24])&&(~data_reg[15:8]==data_reg[7:0]))
data<={12'b0,data_reg[23:16]};
else
data<=data;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
repeat_en<=1'b0;
else if((state==REPEAT)&&(~data_reg[23:16]==data_reg[31:24]))
repeat_en<=1'b1;
else
repeat_en<=1'b0;
endmodule
led灯信号产生模块 PWM:
红外遥控模块输出按下的遥控器数据,根据不同按键反馈的不同数据达到控制LED灯的功能。LED灯的亮度由PWM输出信号的占空比决定,具体解释与代码如下
module PWM(
input sys_clk,
input sys_rst_n,
input [19:0]data, //按键传输的数据
output reg led_pwm //LED控制信号
);
reg [3:0]cnt10;
always@(posedge sys_clk or negedge sys_rst_n) //系统时钟做10次计数
if(!sys_rst_n)
cnt10<=4'd0;
else if(cnt10==9)
cnt10<=4'd0;
else
cnt10<=cnt10+1'd1;
//LED控制信号输出
//按键0传输的数据为22
//按键1传输的数据为12
//按键2传输的数据为24
//按键3传输的数据为94
//按键4传输的数据为8
//按键0表示开灯;按键1表示关灯;按键2表示高亮;按键3表示中亮;按键4表示低亮
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
led_pwm<=1'b1;
else if(data==22)
led_pwm<=1'b0;
else if(data==12)
led_pwm<=1'b1;
else if(data==24) //高亮 此时占空比为90%
begin
if(cnt10<=8)
led_pwm<=1'b0;
else
led_pwm<=1'b1;
end
else if(data==94) //中亮 此时占空比为50%
begin
if(cnt10<=4)
led_pwm<=1'b0;
else
led_pwm<=1'b1;
end
else if(data==8) //低亮 此时占空比为10%
begin
if(cnt10<=1)
led_pwm<=1'b0;
else
led_pwm<=1'b1;
end
else
led_pwm<=1'b1;
endmodule
重复码提示灯模块 led_ctrl:
若持续按住某个按键不放,则令一LED灯闪烁,达到重复码提示灯作用。
module led_ctrl(
input sys_clk,
input sys_rst_n,
input repeat_en,
output reg led
);
reg repeat_en_1;
reg repeat_en_2;
wire repeat_en_rise;
reg [21:0]cnt;
parameter CNT_MAX=22'd2500_000;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
begin
repeat_en_1<=1'b0;
repeat_en_2<=1'b0;
end
else
begin
repeat_en_1<=repeat_en;
repeat_en_2<=repeat_en_1;
end
assign repeat_en_rise=(repeat_en_1==1'b1)&&(repeat_en_2==1'b0);
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt<=22'd0;
else if(repeat_en_rise==1'b1)
cnt<=CNT_MAX;
else if(cnt>1'b0)
cnt<=cnt-1'b1;
else
cnt<=22'd0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
led<=1'b1;
else if(cnt>0)
led<=1'b0;
else
led<=1'b1;
endmodule
烧录验证:
如下图为初始上电状态,数码管显示0,LED灭
当按下遥控按键0,LED灯亮,传输数据为22
当按下遥控按键1,LED灯灭,传输数据为12
当按下遥控按键2,LED为高亮,传输数据为24
当按下遥控按键3,LED灯中亮,传输数据为94
当按下遥控按键4,LED灯低亮,传输数据为8
本文参考野火FPGA开发指南
代码资源免费上传,供大家参考!
https://download.csdn.net/download/m0_64758206/90191020?spm=1001.2014.3001.5503