Bootstrap

基于FPGA的遥控灯控制器设计

目录

顶层设计:

模块分析:

红外遥控模块 inf_rcv:

led灯信号产生模块 PWM:

重复码提示灯模块 led_ctrl:

烧录验证:


本文分享利用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

;