• ZC-CLS381RGB颜色识别+8x8点阵指示——WS2812点阵驱动(中)



    前言

      RGB888点阵是一个由64个WS2812 RGB LED灯珠组成的点阵显示屏,可以用于艺术装饰、玩具和游戏、时钟计时器和状态指示器等各种场景。
      本文将向各位读者展示,如何利用FPGA驱动该8x8点阵显示屏,使得点阵显示特定的字符信息。

    一、WS2812简介

      WS2812 RGB LED灯珠广泛应用于LED灯带、室内和户外装饰照明、信号指示灯、车载设备等方面,由于它可以通过简单的控制器控制多个LED灯珠的颜色和亮度,因此具有非常广泛的市场前景。

    二、WS2812配置说明

      根据WS2812特性可知,要实现8x8图像的显示,就必须要配置64x24个数据,在设计中可以把配置64个数据和配置24个数据这两部分分开,在设计时,可以分成三个模块来实现此功能:配置模块、控制模块和顶层模块。
      配置模块用来指示需要配置的是64个RGB LED灯中的哪一个,并提供开始配置信号和待显示的24位图像信息,将上述信号提供给控制模块完成对LED灯显示与色彩信息的配置。
      控制模块用来配置配置模块发送过来的24位图像信息,对每一位进行解码然后按照特定格式发送“0”或者发送“1”,当配置完成24x64个数据并持续一段时间的低电平复位,就能够驱动8x8点阵显示了。
      顶层模块用来级联配置模块和控制模块,此处不再过多叙述。
      发送的“0”码或者“1”码配置规则如下图所示:
    在这里插入图片描述
      在本设计中,设定发送“0”码的总时间为1180ns,其中高电平占据300ns;发送“1”码的总时间为1280ns,其中高电平占据640ns;复位总时间为300us。

    三、波形图绘制

    1.配置模块

      配置模块信号波形图如下图所示:

    在这里插入图片描述
      如图所示,cfg_start信号为控制模块每完成一个24bit数据的配置,就发送拉高信号告知配置模块可以开始配置下一个24bit数据了。需要注意的是,cnt_wait信号为上电等待信号,这里人为设定等待20ms等待电源电压稳定、器件初始化和内部元件自适应调节,等待完成之后拉高start_en,指示器件开始工作。cfg_num是指示配置了多少个LED灯,cfg_data是指示需要向该LED灯里面写入什么数据去配置它,ws2812_start是控制模块的开始配置信号,与cfg_num和cfg_data是保持同步的。

    2.控制模块

      控制模块状态转移图如下图所示:
    在这里插入图片描述
      如图所示,初始时控制模块状态为空闲IDLE状态,即不进行任何数据的配置,当检测到配置模块发送的开始信号时,空闲状态就会跳转到仲裁ARBIT状态,仲裁状态仲裁发送的24位数据,每一位应该是发“0”还是发“1”,每一次发“0”或者发“1”完成后,又重新回到仲裁状态仲裁下一个数据的发送状态(“0”或“1”).当发送完成64x24个数据时,表明一副8x8图像数据配置完成,此时跳转都复位RST状态,数据持续发送一段时间低电平,结束后又重新回到空闲IDLE状态等待配置模块的开始信号到来,再继续开始配置。
      控制模块信号波形图如下图所示:
    在这里插入图片描述
      如图所示,cfg_data为待配置的24位数据,这里为了描述状态的跳转,假设配置的前两位数据分别位“0”和“1”,cfg_num初始为不定态,表示配置的是哪一个LED灯是不关心的,ws2812_start为该模块的开始工作信号。
      skip_en_0为仲裁状态跳转到发“0”码状态的跳转信号,或者是发“0”码状态跳转到仲裁状态的跳转信号;skip_en_1为仲裁状态跳转到发“1”码状态的跳转信号,或者是发“1”码状态跳转到仲裁状态的跳转信号;skip_en_rst为发“0”码或者“1”码状态跳转到复位状态的跳转信号,或者是复位状态跳转到空闲状态的跳转信号。
      n_state为次态,c_state为现态,两者具有一个时钟周期的差异。cnt_wait为全局计数器,计数仲裁、发“0”码或者“1”码、复位状态的时间,data为解码得到的24bit待配置数据的每一位数据,cnt_num位配置的数据个数,最多配置24个数据。
      led_data为输出信号,根据led_data高低电平持续时间不同,用来指示配置的LED灯不同的色彩信息。如图所示,发送“0”码总时间为SEND_ZERO_time+ARBIT_time=1180ns,高电平占据300ns;发送“1”码总时间为SEND_ONE_time+ARBIT_time=1280ns,高电平占据640ns。
      cfg_start为输出给配置模块的开始配置信号,该信号在控制模块每配置完成24bit图像数据时会拉高。

    总结

      本文介绍了如何利用FPGA驱动RGB888点阵显示屏显示特定的字符信息,详细阐述了配置模块和控制模块之间的协作关系,以及两个模块之间的信号传递图示以及每个信号的作用。下一章演示颜色识别与RGB88点阵关联效果。

    参考代码

    1.配置模块

    module  ws2812_cfg_ctrl
    (
    	input	wire			sys_clk			,
    	input	wire			sys_rst_n		,
    	input	wire			cfg_start		,	//配置模块开始工作指示的单脉冲信号,由控制模块产生
    	input	wire			r_valid			,	//红色分量有效信号,为持续拉高的电平信号
    	input	wire			g_valid			,	//绿色分量有效信号,为持续拉高的电平信号
    	input	wire			b_valid			,	//蓝色分量有效信号,为持续拉高的电平信号
    	
    	output	reg				ws2812_start	,	//控制模块开始工作指示的单脉冲信号,由配置模块产生
    	output	reg		[5:0]	cfg_num			,	//配置的8x8点阵个数,最大值64-1
    	output	reg		[23:0]	cfg_data			//待显示的颜色数据
    );
    
    localparam	CNT_WAIT_MAX  =  20'd1_000_000  ;	//上电等待20ms,自行设定
    
    wire	[23:0]	data_none[63:0]	;	//显示白色字母“N”
    wire	[23:0]	data_r[63:0]	;	//显示红色字母“R”
    wire	[23:0]	data_g[63:0]	;	//显示绿色字母“G”
    wire	[23:0]	data_b[63:0]	;	//显示蓝色字母“B”
    reg		[19:0]	cnt_wait  ;			//上电等待计数器,等待20ms后一直保持最大值
    reg				start_en  ;			//上电等待结束开始工作信号
    
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		cnt_wait  <=  20'd0  ;
    	else  if(cnt_wait >= CNT_WAIT_MAX - 1'b1)
    		cnt_wait  <=  CNT_WAIT_MAX  ;
    	else
    		cnt_wait  <=  cnt_wait + 1'b1  ;
    		
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		start_en  <=  1'b0  ;
    	else  if(cnt_wait == CNT_WAIT_MAX - 1'b1)
    		start_en  <=  1'b1  ;
    	else
    		start_en  <=  1'b0  ;
    		
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		ws2812_start  <=  1'b0  ;
    	else  if((start_en == 1'b1)||((cfg_start == 1'b1)&&(cfg_num == 6'd63)))
    		ws2812_start  <=  1'b1  ;
    	else
    		ws2812_start  <=  1'b0  ;
    		
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		cfg_num  <=  6'd0  ;
    	else  if(cfg_start == 1'b1)
    		cfg_num  <=  cfg_num + 1'b1  ;
    	else
    		cfg_num  <=  cfg_num  ;
    
    //选择显示的字母和颜色类型
    //r_valid有效显示红色“R”
    //g_valid有效显示绿色"G"
    //b_valid有效显示蓝色"B"
    //三种信号均无效显示白色"N"	
    //RGB每一位向右移5位是在不改变显示颜色条件下减小显示亮度,否则发光太刺眼
    always@(*)
    	case({r_valid,g_valid,b_valid})
    		3'b100	:	cfg_data  =  {(data_r[cfg_num][23:16] >> 5),(data_r[cfg_num][15:8] >> 5),(data_r[cfg_num][7:0] >> 5)}  ;
    		3'b010	:	cfg_data  =  {(data_g[cfg_num][23:16] >> 5),(data_g[cfg_num][15:8] >> 5),(data_g[cfg_num][7:0] >> 5)}  ;
    		3'b001	:	cfg_data  =  {(data_b[cfg_num][23:16] >> 5),(data_b[cfg_num][15:8] >> 5),(data_b[cfg_num][7:0] >> 5)}  ;		
    		default	:	cfg_data  =  {(data_none[cfg_num][23:16] >> 5),(data_none[cfg_num][15:8] >> 5),(data_none[cfg_num][7:0] >> 5)}  ;
    	endcase
    		
    //默认显示字母“N”
    assign  data_none[00]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[01]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[02]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[03]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[04]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[05]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[06]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[07]  =  {8'hff,8'hff,8'hff}  ;	
    assign  data_none[08]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[09]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[10]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[11]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[12]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[13]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[14]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[15]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[16]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[17]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[18]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[19]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[20]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[21]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[22]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[23]  =  {8'hff,8'hff,8'hff}  ;	
    assign  data_none[24]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[25]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[26]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[27]  =  {8'hff,8'hff,8'hff}  ;	
    assign  data_none[28]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[29]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[30]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[31]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[32]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[33]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[34]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[35]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[36]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[37]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[38]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[39]  =  {8'hff,8'hff,8'hff}  ;	
    assign  data_none[40]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[41]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[42]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[43]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[44]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[45]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[46]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[47]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[48]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[49]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[50]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[51]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[52]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[53]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[54]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[55]  =  {8'hff,8'hff,8'hff}  ;	
    assign  data_none[56]  =  {8'hff,8'hff,8'hff}  ;
    assign  data_none[57]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[58]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[59]  =  {8'h00,8'h00,8'h00}  ;	
    assign  data_none[60]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[61]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[62]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_none[63]  =  {8'hff,8'hff,8'hff}  ;
    //检测到红色显示字母“R”
    assign  data_r[00]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[01]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[02]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[03]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[04]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[05]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[06]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[07]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[08]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[09]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[10]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[11]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[12]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[13]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[14]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[15]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[16]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[17]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[18]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[19]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[20]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[21]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[22]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[23]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[24]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[25]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[26]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[27]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[28]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[29]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[30]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[31]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[32]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[33]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[34]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[35]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[36]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[37]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[38]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[39]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[40]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[41]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[42]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[43]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[44]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[45]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[46]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[47]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[48]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[49]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[50]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[51]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[52]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[53]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[54]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[55]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[56]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[57]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[58]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[59]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[60]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[61]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_r[62]  =  {8'h00,8'hff,8'h00}  ;
    assign  data_r[63]  =  {8'h00,8'h00,8'h00}  ;
    //检测到绿色显示字母“G”
    assign  data_g[00]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[01]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[02]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[03]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[04]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[05]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[06]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[07]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[08]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[09]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[10]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[11]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[12]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[13]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[14]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[15]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[16]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[17]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[18]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[19]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[20]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[21]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[22]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[23]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[24]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[25]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[26]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[27]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[28]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[29]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[30]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[31]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[32]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[33]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[34]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[35]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[36]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[37]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[38]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[39]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[40]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[41]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[42]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[43]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[44]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[45]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[46]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[47]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[48]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[49]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[50]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[51]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[52]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[53]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[54]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[55]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[56]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[57]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[58]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[59]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[60]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[61]  =  {8'hff,8'h00,8'h00}  ;
    assign  data_g[62]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_g[63]  =  {8'h00,8'h00,8'h00}  ;
    //检测到绿色显示字母“B”
    assign  data_b[00]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[01]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[02]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[03]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[04]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[05]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[06]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[07]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[08]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[09]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[10]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[11]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[12]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[13]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[14]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[15]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[16]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[17]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[18]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[19]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[20]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[21]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[22]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[23]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[24]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[25]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[26]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[27]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[28]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[29]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[30]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[31]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[32]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[33]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[34]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[35]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[36]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[37]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[38]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[39]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[40]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[41]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[42]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[43]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[44]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[45]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[46]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[47]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[48]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[49]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[50]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[51]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[52]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[53]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[54]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[55]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[56]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[57]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[58]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[59]  =  {8'h00,8'h00,8'hff}  ;
    assign  data_b[60]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[61]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[62]  =  {8'h00,8'h00,8'h00}  ;
    assign  data_b[63]  =  {8'h00,8'h00,8'h00}  ;
    
    endmodule
    
    • 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
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331

    2.控制模块

    module  ws2812_ctrl
    (
    	input	wire			sys_clk			,
    	input	wire			sys_rst_n		,
    	input	wire			ws2812_start	,	//控制模块开始工作指示的单脉冲信号,由配置模块产生
    	input	wire	[23:0]	cfg_data		,	//待配置的RGB888颜色数据
    	input	wire	[5:0]	cfg_num			,	//配置的RGB灯个数
    	
    	output	reg				cfg_start		,	//配置模块开始工作指示的单脉冲信号,由控制模块产生
    	output	reg				led_data	
    );
    
    localparam	IDLE		=	3'd0	,	//空闲状态,跳转条件是配置模块产生的ws2812_start
    			ARBIT		=	3'd1	,	//仲裁状态,判断每一位RGB888是0还是1,是0跳转到SEND_SERO,是1跳转到SEND_ONE
    			SEND_ZERO	=	3'd2	,	//发送数据0状态,发送24x64个数据完毕跳转到RST_N状态,发送完成0码重新跳转到仲裁状态
    			SEND_ONE	=	3'd3	,	//发送数据1状态,发送24x64个数据完毕跳转到RST_N状态,发送完成1码重新跳转到仲裁状态
    			RST_N		=	3'd4	;	//复位状态,发送完成24x64个数据后,复位状态会持续一段时间低电平
    localparam	CNT_WAIT_0	=	14'd55		,	//发送数据0等待时间,1100ns,总时间为CNT_WAIT_0 + ARBIT_time = 1180ns
    			CNT_WAIT_H0	=	14'd15		,	//发送数据0高电平时间,300ns,低电平时间为CNT_WAIT_0 - CNT_WAIT_H0 + ARBIT_time = 880ns
    			CNT_WAIT_1	=	14'd64		,	//发送数据1等待时间,1280ns,总时间为CNT_WAIT_1 + ARBIT_time = 1360ns
    			CNT_WAIT_H1	=	14'd32		,	//发送数据1高电平时间,640ns,低电平时间为CNT_WAIT_1 - CNT_WAIT_H1 + ARBIT_time = 720ns
    			CNT_WAIT_RST=	14'd15000	;	//发送24x64个数据完成,复位状态等待时间,总时间为300us
    			
    reg				skip_en_0	;	//	①仲裁状态跳转到发送数据0状态跳转信号;②发送数据0状态跳转到仲裁状态跳转信号
    reg				skip_en_1	;	//	①仲裁状态跳转到发送数据1状态跳转信号;②发送数据1状态跳转到仲裁状态跳转信号
    reg				skip_en_rst	;	//	①发送数据0/1状态跳转到复位状态跳转信号;②复位状态跳转到空闲状态跳转信号
    reg		[2:0]	n_state		;	//次态
    reg		[2:0]	c_state		;	//现态
    reg		[13:0]	cnt_wait	;	//全局等待计数器
    reg				data		;	//数据0或者1,解码cfg_data每一位得到
    reg		[4:0]	cnt_num		;	//对配置的RGB888比特个数计数,最多配置24-1个
    
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		c_state  <=  IDLE  ;
    	else
    		c_state  <=  n_state ;
    		
    always@(*)
    	case(c_state)
    		IDLE		:	if(ws2812_start == 1'b1)
    							n_state  =  ARBIT  ;
    						else
    							n_state  =  IDLE  ;
    		ARBIT		:	if(skip_en_0 == 1'b1)
    							n_state  =  SEND_ZERO  ;
    						else  if(skip_en_1 == 1'b1)
    							n_state  =  SEND_ONE  ;
    						else
    							n_state  =  ARBIT  ;
    		SEND_ZERO	:	if(skip_en_0 == 1'b1)
    							n_state  =  ARBIT  ;
    						else  if(skip_en_rst == 1'b1)
    							n_state  =  RST_N  ;
    						else
    							n_state  =  SEND_ZERO  ;
    		SEND_ONE	:	if(skip_en_1 == 1'b1)
    							n_state  =  ARBIT  ;
    						else  if(skip_en_rst == 1'b1)
    							n_state  =  RST_N  ;
    						else
    							n_state  =  SEND_ONE  ;
    		RST_N		:	if(skip_en_rst == 1'b1)
    							n_state  =  IDLE  ;
    						else
    							n_state  =  RST_N  ;
    		default		:	n_state  =  IDLE  ;
    	endcase
    	
    always@(posedge sys_clk or negedge sys_rst_n)
    	if(sys_rst_n == 1'b0)
    		begin
    			skip_en_0	<=  1'b0  ;
    			skip_en_1	<=  1'b0  ;
    			skip_en_rst	<=  1'b0  ;
    			cnt_wait	<=  14'd0 ;
    			data		<=  1'b0  ;
    			cnt_num		<=  5'd0  ;
    			cfg_start   <=  1'b0  ;
    			led_data	<=  1'b0  ;
    		end
    	else
    		case(c_state)
    			ARBIT		:begin
    							if(cnt_wait == 14'd3)
    								cnt_wait  <=  14'd0  ;
    							else
    								cnt_wait  <=  cnt_wait + 1'b1  ;
    							data  <=  cfg_data[23 - cnt_num]  ;
    							cfg_start  <=  1'b0  ;
    							if((data == 1'b0)&&(cnt_wait == 14'd2))
    								skip_en_0  <=  1'b1  ;
    							else  
    								skip_en_0  <=  1'b0  ;							
    							if((data == 1'b1)&&(cnt_wait == 14'd2))
    								skip_en_1  <=  1'b1  ;
    							else  
    								skip_en_1  <=  1'b0  ;							
    						 end
    			SEND_ZERO	:begin
    							if(cnt_wait == CNT_WAIT_0 - 1'b1)
    								cnt_wait  <=  14'd0  ;
    							else
    								cnt_wait  <=  cnt_wait + 1'b1  ;
    							if((cnt_wait == CNT_WAIT_0 - 1'b1)&&(cnt_num == 5'd23)&&(cfg_num != 6'd63))
    								cfg_start  <=  1'b1  ;
    							else
    								cfg_start  <=  1'b0  ;
    							if((cnt_num == 5'd23)&&(cnt_wait == CNT_WAIT_0 - 1'b1))
    								cnt_num  <=  6'd0  ;
    							else  if(cnt_wait == CNT_WAIT_0 - 1'b1)
    								cnt_num  <=  cnt_num + 1'b1  ;
    							else
    								cnt_num  <=  cnt_num  ;
    							if((cnt_wait == CNT_WAIT_0 - 2'd2)&&(cnt_num == 5'd23)&&(cfg_num == 6'd63))
    								skip_en_rst  <=  1'b1  ;
    							else  if(cnt_wait == CNT_WAIT_0 - 2'd2)
    								skip_en_0  <=  1'b1  ;
    							else
    								begin
    									skip_en_rst  <=  1'b0  ;
    									skip_en_0	 <=  1'b0  ;
    								end
    							if(cnt_wait <= CNT_WAIT_H0 - 1'b1)
    								led_data  <=  1'b1  ;
    							else
    								led_data  <=  1'b0  ;
    						 end
    			SEND_ONE	:begin
    							if(cnt_wait == CNT_WAIT_1 - 1'b1)
    								cnt_wait  <=  14'd0  ;
    							else
    								cnt_wait  <=  cnt_wait + 1'b1  ;	
    							if((cnt_wait == CNT_WAIT_1 - 1'b1)&&(cnt_num == 5'd23)&&(cfg_num != 6'd63))
    								cfg_start  <=  1'b1  ;
    							else
    								cfg_start  <=  1'b0  ;	
    							if((cnt_num == 5'd23)&&(cnt_wait == CNT_WAIT_1 - 1'b1))
    								cnt_num  <=  6'd0  ;
    							else  if(cnt_wait == CNT_WAIT_1 - 1'b1)
    								cnt_num  <=  cnt_num + 1'b1  ;
    							else
    								cnt_num  <=  cnt_num  ;								
    							if((cnt_wait == CNT_WAIT_1 - 2'd2)&&(cnt_num == 5'd23)&&(cfg_num == 6'd63))
    								skip_en_rst  <=  1'b1  ;
    							else  if(cnt_wait == CNT_WAIT_1 - 2'd2)
    								skip_en_1  <=  1'b1  ;
    							else
    								begin
    									skip_en_rst  <=  1'b0  ;
    									skip_en_1	 <=  1'b0  ;
    								end			
    							if(cnt_wait <= CNT_WAIT_H1 - 1'b1)
    								led_data  <=  1'b1  ;
    							else
    								led_data  <=  1'b0  ;			
    						 end
    			RST_N		:begin
    							if(cnt_wait == CNT_WAIT_RST - 1'b1)
    								cnt_wait  <=  14'd0  ;
    							else
    								cnt_wait  <=  cnt_wait + 1'b1  ;
    							if(cnt_wait == CNT_WAIT_RST - 1'b1)
    								cfg_start  <=  1'b1  ;
    							else
    								cfg_start  <=  1'b0  ;	
    							if(cnt_wait == CNT_WAIT_RST - 2'd2)
    								skip_en_rst  <=  1'b1  ;
    							else
    								skip_en_rst  <=  1'b0  ;
    							led_data  <=  1'b0  ;
    						 end
    			default		:begin
    							skip_en_0	<=  1'b0  ;
    							skip_en_1	<=  1'b0  ;
    							skip_en_rst	<=  1'b0  ;
    							cnt_wait	<=  14'd0 ;
    							data		<=  1'b0  ;
    							cnt_num		<=  5'd0  ;
    							led_data	<=  1'b0  ;
    							cfg_start   <=  1'b0  ;
    						 end
    		endcase
    
    endmodule
    
    • 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
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185

    3.顶层模块

    module  ws2812_top
    (
    	input	wire			sys_clk		,
    	input	wire			sys_rst_n	,
    	input	wire			r_valid		,
    	input	wire			g_valid		,
    	input	wire			b_valid		,
    	
    	output	wire			led_data
    );
    
    wire			cfg_start	;
    wire			ws2812_start;
    wire	[5:0]	cfg_num		;
    wire	[23:0]	cfg_data	;
    
    ws2812_cfg_ctrl  ws2812_cfg_ctrl_inst
    (
    	.sys_clk		(sys_clk		),
    	.sys_rst_n		(sys_rst_n		),
    	.cfg_start		(cfg_start		),
    	.r_valid		(r_valid		),
    	.g_valid		(g_valid		),
    	.b_valid		(b_valid		),
    	.ws2812_start	(ws2812_start	),
    	.cfg_num		(cfg_num		),
    	.cfg_data       (cfg_data       )
    );
    
    ws2812_ctrl  ws2812_ctrl_inst
    (
    	.sys_clk		(sys_clk		),
    	.sys_rst_n		(sys_rst_n		),
    	.ws2812_start	(ws2812_start	),
    	.cfg_data		(cfg_data		),
    	.cfg_num		(cfg_num		),
    	.cfg_start		(cfg_start		),
    	.led_data	    (led_data	    )
    );
    
    endmodule
    
    • 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
  • 相关阅读:
    PMP考试点02
    达芬奇机器人手术模拟系统RobotixMentQr
    数据结构之—顺序表和链表
    MongoDB - 聚合查询
    包含吲哚菁绿的多聚体白蛋白纳米球/载马钱子碱纳米粒的牛血清白蛋白微球的制备
    U盘坏了数据可以恢复吗?超详细的U盘数据恢复图文教程!
    MySQL下载安装运行
    计算机字符编码方式
    Doris通过ODBC驱动导入外部表数据
    【24届数字IC秋招总结】正式批面试经验汇总9——飞腾
  • 原文地址:https://blog.csdn.net/weixin_43828944/article/details/133862987