ZC-CLS381RGB颜色识别+8x8点阵指示——配置颜色识别寄存器组(上)

这篇具有很好参考价值的文章主要介绍了ZC-CLS381RGB颜色识别+8x8点阵指示——配置颜色识别寄存器组(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

  在现代工业生产中,颜色识别技术已经成为了一个非常重要的技术。颜色识别可以用于产品质量检测、物料分类、机器视觉等领域。本文将介绍如何使用FPGA结合ZC-CLS381RGB进行颜色识别。
  本教程通过对采集到的图像信息中,R、G、B三个颜色分量的占比,来判断识别到的颜色信息。本教程只实现对红色、绿色、蓝色的识别,如果各位读者要想实现对其它色彩信息的识别,可根据三个色彩分量的占比来判断。

一、ZC-CLS381RGB简介

  ZC-CLS381RGB是一款基于RGB三基色原理的颜色识别传感器。它可以通过对物体反射光的RGB三基色分量进行测量,来判断物体的颜色。该传感器具有高精度、快速响应、稳定性好等特点,广泛应用于自动化生产线、机器人、智能家居等领域。

二、配置寄存器组

  ZC-CLS381RGB是一款RGB LED驱动器芯片,需要通过配置寄存器来让该模块正常工作。下面就对颜色识别需要配置的寄存器进行介绍。

1.主控寄存器

  MAIN_CTRL Register是主控寄存器,下图是主控寄存器的配置介绍:

zc-cls381颜色识别传感器,fpga开发
  bit7~bit5,bit3,bit0:保留位(Reserved),使用时将这几位置0即可。
  bit4:软件复位位(SW Reset),当该位被置1时,芯片会进行软件复位,即将所有寄存器的值恢复为默认值。在使用ZC-CLS381RGB时,如果出现异常情况,例如芯片无法正常工作或者输出异常,可以通过将SW Reset位置1来进行软件复位,以恢复芯片的正常工作状态。同时,在初始化芯片时,也可以通过将SW Reset位置1来确保芯片的寄存器值处于默认状态,以避免出现不可预期的问题。但是如果软件复位位一直为高电平,模块就无法正常采集颜色,一直处于复位状态,如果要关闭该位则还需要发送一次指令。因此在本设计初始化时,将该位置为0,不启用软件复位。
  bit2:颜色传感器模式位(CS Mode),该位置为1时,表示所有的光传感器通道都被激活,包括RGB(三原色)、IR(红外光)和COMP(环境光)。这意味着该传感器可以同时测量红、绿、蓝三种颜色的光线强度、红外线的强度以及环境光的强度,并将这些数据传输到寄存器中进行处理。初始化配置时,需将该位置为1。
  bit1:环境光传感器/颜色传感器使能位(ALS/CS Enable),当该位置1时,表示使能环境光传感器和颜色传感器。在本设计中,需要使用到这两个传感器,因此在初始化时需要将该位置为1。

2.检测速率寄存器

  ALS_CS_MEAS_RATE Register是环境光传感器和颜色传感器检测速率寄存器,下图是对该寄存器的配置介绍:

zc-cls381颜色识别传感器,fpga开发
  bit7、bit3:保留位(Reserved),使用时这两位需要置0。
  bit6,bit5,bit4:环境光传感器和颜色传感器速率位(ALS/CS Resolution),初始化时设置{bit6,bit5,bit4}=100,利用最快的时间对采集到的数据进行转换。
  bit2,bit1,bit0:环境光传感器和颜色传感器测量速率位(ALS/CS Measurement Rate),初始化设置{bit2,bit1,bit0}=000,利用最快的采集速率采集数据。

2.增益寄存器

  ALS_CS_MEAS_RATE Register是环境光传感器和颜色传感器增益寄存器,下图是对该寄存器的配置介绍:

zc-cls381颜色识别传感器,fpga开发
  bit7~bit3:保留位(Reserved),使用时这两位需要置0。
  bit2~bit0:环境光传感器和颜色传感器增益率位(Reserved),初始化时设置{bit2,bit1,bit0}=100,将增益率调到最大,以此增强信号的强度,使得信号更容易被检测到。

2.颜色数据寄存器

  因为本教程采集的是红色、绿色、蓝色数据,芯片手册提供的寄存器组如下图所示:

zc-cls381颜色识别传感器,fpga开发
  0x0D、0x0E、0x0F分别表示绿色信息的低8位、中8位、高8位数据;0x10、0x11、0x12分别表示红色信息的低8位、中8位、高8位数据;0x13、0x14、0x15分别表示蓝色信息的低8位、中8位、高8位数据。在使用中,直接读取这些寄存器内的数据,然后拼接起来,即可得到红、绿、蓝色数据,再根据三个数据的占比,从而对采集到的物体颜色进行判断。

三、状态转移图和信号波形图绘制

  在正式开始使用器件时,需要等待一段时间让器件稳定下来,如图所示:

zc-cls381颜色识别传感器,fpga开发
  待机唤醒时间最大为10ms,表示在测量的时候,两次获取数据的时间间隔最大为10ms。由于在数据手册内,未说明上电后直到模块稳定需要等待的时间,在这里我们人为设置上电等待的时间为20ms,给模块一个缓冲的时间,然后再对它进行配置。配置寄存器组信号波形图如下图所示:

zc-cls381颜色识别传感器,fpga开发
  其中,i2c_start作为i2c控制模块的开始信号,检测到该开始信号后,就开始配置寄存器,向各个寄存器内写入数据。综上绘制的i2c控制模块配置寄存器组的状态转移图如下图所示:

zc-cls381颜色识别传感器,fpga开发
  为了设计方便,对于50MHZ的系统时钟,将其分频为1MHZ的i2c驱动时钟用来驱动后续模块,同时令一个SCL时钟周期为4us,高电平持续时间为2us,低电平持续时间也为2us。这样设计的好处是,满足SCL高电平持续时间大于0.6us,SCL低电平持续时间大于1.3us。如下图所示:

zc-cls381颜色识别传感器,fpga开发
  综上,绘制的分频信号波形图如下图所示:

zc-cls381颜色识别传感器,fpga开发
  结合状态转移图,绘制的配置寄存器信号波形图如下图所示:

zc-cls381颜色识别传感器,fpga开发

zc-cls381颜色识别传感器,fpga开发

zc-cls381颜色识别传感器,fpga开发
  需要注意的是,配置寄存器组跳转条件为skip_en_0,这里配置的寄存器是向寄存器里面写入数据,总共需要配置三个,三个寄存器配置完成后,才能读出颜色数据。因此,step从0自增到1,必须要在cfg_num为3并且检测到结束信号的情况下进行。

总结

  本章配置完成颜色识别所需的寄存器,下一章完成ws2812 8x8点阵的驱动配置。文章来源地址https://www.toymoban.com/news/detail-772632.html

参考代码

1.配置模块

module  cls381_cfg_ctrl
(
	input	wire			i2c_clk		,	//与i2c_ctrl公用的驱动时钟
	input	wire			sys_rst_n	,
	input	wire			cfg_start	,	//cfg_ctrl模块开始信号,i2c_ctrl模块每配置完成一次产生
	
	output	wire	[15:0]	cfg_data	,	//打包的寄存器地址和数据
	output	reg		[3:0]	cfg_num		,	//配置的寄存器个数
	output	reg				i2c_start		//i2c_ctrl模块开始信号
);

localparam	CNT_WAIT_MAX  =  15'd20_000  ;	//上电等待20ms

reg		[14:0]	cnt_wait		;		//等待20ms计数器
reg				i2c_start_reg	;		//i2c_start未打拍的信号,打拍后才与数据和个数保持同步
wire	[15:0]	cfg_data_reg[11:0]	;	//待发送数据的寄存

always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		cnt_wait  <=  15'd0  ;
	else  if(cnt_wait >= CNT_WAIT_MAX - 1'b1)
		cnt_wait  <=  CNT_WAIT_MAX  ;
	else
		cnt_wait  <=  cnt_wait + 1'b1  ;

always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		i2c_start_reg  <=  1'b0  ;
	else  if(cnt_wait == CNT_WAIT_MAX - 2'd2)
		i2c_start_reg  <=  1'b1  ;
	else
		i2c_start_reg  <=  1'b0  ;
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		cfg_num  <=  4'd0  ;
	else  if((cfg_num == 4'd12)&&(cfg_start == 1'b1))
		cfg_num  <=  4'd4  ;
	else  if((cfg_start == 1'b1)||(i2c_start_reg == 1'b1))
		cfg_num  <=  cfg_num + 1'b1  ;
	else
		cfg_num  <=  cfg_num  ;
	
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)	
		i2c_start  <=  1'b0  ;
	else  if((cfg_start == 1'b1)||(i2c_start_reg == 1'b1))	
		i2c_start  <=  1'b1  ;
	else
		i2c_start  <=  1'b0  ;

assign  cfg_data = (cfg_num == 4'd0) ? 16'd0 : cfg_data_reg[cfg_num - 1]  ;
assign  cfg_data_reg[00]  =  {8'h00,8'b0000_0110}  ;
assign  cfg_data_reg[01]  =  {8'h04,8'b0100_0000}  ;
assign  cfg_data_reg[02]  =  {8'h05,8'b0000_0100}  ;
assign  cfg_data_reg[03]  =  {8'h0F,8'h0}  ;
assign  cfg_data_reg[04]  =  {8'h0E,8'h0}  ;
assign  cfg_data_reg[05]  =  {8'h0D,8'h0}  ;
assign  cfg_data_reg[06]  =  {8'h12,8'h0}  ;
assign  cfg_data_reg[07]  =  {8'h11,8'h0}  ;
assign  cfg_data_reg[08]  =  {8'h10,8'h0}  ;
assign  cfg_data_reg[09]  =  {8'h15,8'h0}  ;
assign  cfg_data_reg[10]  =  {8'h14,8'h0}  ;
assign  cfg_data_reg[11]  =  {8'h13,8'h0}  ;

endmodule

2.i2c控制模块

module  i2c_ctrl
(
	input	wire			sys_clk		,
	input	wire			sys_rst_n	,
	input	wire			i2c_start	,
	input	wire	[3:0]	cfg_num		,
	input	wire	[15:0]	cfg_data	,
	
	output	wire			scl			,
	output	reg				i2c_clk		,
	output	reg				cfg_start	,
	output	reg		[23:0]	data_r		,
	output	reg		[23:0]	data_g		,
	output	reg		[23:0]	data_b		,
	
	inout	wire			sda
);

localparam	IDLE		=	4'd0	,
			START		=	4'd1	,
			SLAVE_ADDR	=	4'd2	,
			ACK_1		=	4'd3	,
			REG_ADDR	=	4'd4	,
			ACK_2		=	4'd5	,
			DATA		=	4'd6	,
			ACK_3		=	4'd7	,
			STOP		=	4'd8	,
			NACK		=	4'd9	,
			WAIT		=	4'd10	;
localparam	CNT_CLK_MAX		=	5'd25		;	//系统时钟计数器最大值
localparam	SLAVE_ID		=	7'h53		;	//从设备的I2C ID号

reg		[4:0]	cnt_clk		;	//系统时钟计数器,计数25次产生1MHZ i2c驱动时钟
reg				skip_en_0	;	//配置寄存器状态跳转信号
reg				skip_en_1	;	//读取绿色分量状态跳转信号
reg				skip_en_2	;	//读取红色分量状态跳转信号
reg				skip_en_3	;	//读取蓝色分量状态跳转信号
reg		[3:0]	n_state		;	//次态
reg		[3:0]	c_state		;	//现态
reg		[1:0]	cnt_i2c_clk	;	//i2c_clk时钟计数器,每计数4次就是一个SCL周期
reg		[2:0]	cnt_bit		;	//计数发送的比特数
reg				i2c_scl		;	//这就是scl信号,加i2c_是为了与i2c_sda同步
reg				i2c_sda		;	//由主机产生,在主机控制SDA通信总线时赋值给SDA
reg				ack_en		;	//响应使能信号,为1时代表接收的ACK响应有效
reg				i2c_end		;	//结束信号,在STOP最后一个时钟周期拉高,表示一次通信结束
reg		[2:0]	step		;	//操作步骤信号,与跳转信号相关联
								//在向寄存器里面写入数据或者读出数据时,状态跳转情况是不一样的
reg				flag_g		;	//读取绿色数据指示不同的状态跳转
reg		[1:0]	cnt_g		;	//绿色寄存器个数计数
(*noprune*)reg		[23:0]	rec_data_g	;	//读取到的绿色分量
reg				flag_r		;	//读取红色数据指示不同的状态跳转
reg		[1:0]	cnt_r		;	//红色寄存器个数计数
(*noprune*)reg		[23:0]	rec_data_r	;	//读取到的红色分量
reg				flag_b		;	//读取蓝色数据指示不同的状态跳转
reg		[1:0]	cnt_b		;	//蓝色寄存器个数计数
(*noprune*)reg		[23:0]	rec_data_b	;	//读取到的蓝色分量
reg		[7:0]	slave_addr	;
reg		[7:0]	reg_addr	;
reg		[7:0]	wr_data		;
wire			sda_in		;	//sda赋值给sda_in,主机在接收从机数据时采集sda_in的数据,间接采集了SDA数据
wire			sda_en		;	//主机控制SDA使能信号,为1代表主机控制SDA,为0代表控制权为从机

assign  scl  =  i2c_scl  ;
//三态门
assign  sda_in  =  sda  ;
assign  sda_en  =  ((c_state == ACK_1)||(c_state == ACK_2)||(c_state == ACK_3)||((step != 3'd0)&&(c_state == DATA))) ? 1'b0 : 1'b1  ;
assign  sda     =  (sda_en == 1'b1) ? i2c_sda : 1'bz  ;

always@(*)
	case(step)
		3'd0	:begin	
					slave_addr  =  {SLAVE_ID,1'b0}  ;
					reg_addr	=  cfg_data[15:8]  ;	//主控寄存器地址
					wr_data		=  cfg_data[7:0]  ;
				 end
		3'd1	:begin
					slave_addr  =  {SLAVE_ID,flag_g}  ;
					reg_addr	=  cfg_data[15:8]  ;
					wr_data		=  8'h0  ;	//未写入数据
				 end
		3'd2	:begin
					slave_addr  =  {SLAVE_ID,flag_r}  ;
					reg_addr	=  cfg_data[15:8]  ;
					wr_data		=  8'h0  ;	//未写入数据
				 end
		3'd3	:begin
					slave_addr  =  {SLAVE_ID,flag_b}  ;
					reg_addr	=  cfg_data[15:8]  ;
					wr_data		=  8'h0  ;	//未写入数据
				 end				 
		default	:begin	
					slave_addr  =  slave_addr  ;
					reg_addr	=  reg_addr  ;
					wr_data		=  wr_data  ;
				 end
	endcase		

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		cnt_clk  <=  5'd0  ;
	else  if(cnt_clk == CNT_CLK_MAX - 1'b1)
		cnt_clk  <=  5'd0  ;
	else
		cnt_clk  <=  cnt_clk + 1'b1  ;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		i2c_clk  <=  1'b0  ;
	else  if(cnt_clk == CNT_CLK_MAX - 1'b1)
		i2c_clk  <=  ~i2c_clk  ;
	else
		i2c_clk  <=  i2c_clk  ;
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		cfg_start  <=  1'b0  ;
	else
		cfg_start  <=  i2c_end  ;
		
//状态机第一段
always@(posedge i2c_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((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  START  ;
						else
							n_state  =  IDLE  ;
		START		:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  SLAVE_ADDR  ;
						else
							n_state  =  START  ;
		SLAVE_ADDR	:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  ACK_1  ;
						else
							n_state  =  SLAVE_ADDR  ;
		ACK_1		:	if((skip_en_0 == 1'b1)||((skip_en_1 == 1'b1)&&(flag_g == 1'b0))||((skip_en_2 == 1'b1)&&(flag_r == 1'b0))||((skip_en_3 == 1'b1)&&(flag_b == 1'b0)))
							n_state  =  REG_ADDR  ;
						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  DATA  ;
						else
							n_state  =  ACK_1  ;
		REG_ADDR	:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  ACK_2  ;
						else
							n_state  =  REG_ADDR  ;
		ACK_2		:	if(skip_en_0 == 1'b1)
							n_state  =  DATA  ;
						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  WAIT  ;
						else
							n_state  =  ACK_2  ;
		WAIT		:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  START  ;
						else
							n_state  =  WAIT  ;
		DATA		:	if(skip_en_0 == 1'b1)
							n_state  =  ACK_3  ;
						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  NACK  ;
						else
							n_state  =  DATA  ;
		ACK_3		:	if(skip_en_0 == 1'b1)
							n_state  =  STOP  ;
						else
							n_state  =  ACK_3  ;
		NACK		:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  STOP  ;
						else
							n_state  =  NACK  ;
		STOP		:	if((skip_en_0 == 1'b1)||(skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1))
							n_state  =  IDLE  ;
						else
							n_state  =  STOP  ;
		default		:	n_state  =  IDLE  ;
	endcase
	
//状态机第三段
always@(posedge i2c_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_2 	<=  1'b0	;
			skip_en_3	<=  1'b0	;
			cnt_i2c_clk	<=  2'd0	;
			cnt_bit		<=  3'd0	;
			flag_g		<=  1'b0	;
			cnt_g		<=  2'd0	;
			flag_r		<=  1'b0	;
			cnt_r		<=  2'd0	;	
			flag_b		<=  1'b0	;
			cnt_b		<=  2'd0	;			
			i2c_end		<=  1'b0    ;
			step		<=  3'd0	;
		end
	else
		case(c_state)
			IDLE		:begin
							if((i2c_start == 1'b1)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((i2c_start == 1'b1)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((i2c_start == 1'b1)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((i2c_start == 1'b1)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;								
						 end
			START		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;								
						 end
			SLAVE_ADDR	:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if(cnt_i2c_clk == 2'd3)
								cnt_bit  <=  cnt_bit + 1'b1  ;
							else
								cnt_bit  <=  cnt_bit  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;									
						 end
			ACK_1		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;									
						 end
			REG_ADDR	:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if(cnt_i2c_clk == 2'd3)
								cnt_bit  <=  cnt_bit + 1'b1  ;
							else
								cnt_bit  <=  cnt_bit  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;									
						 end
			ACK_2		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;									
						 end	
			WAIT		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;	
							flag_g  <=  1'b1  ;
							flag_r  <=  1'b1  ;
							flag_b  <=  1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;									
						 end
			DATA		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if(cnt_i2c_clk == 2'd3)
								cnt_bit  <=  cnt_bit + 1'b1  ;
							else
								cnt_bit  <=  cnt_bit  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;									
						 end
			NACK		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;		
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;								
						 end	
			ACK_3		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(ack_en == 1'b1)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
						 end	
			STOP		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(step == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;								
							if(cnt_i2c_clk == 2'd2)	
								i2c_end  <=  1'b1  ;
							else
								i2c_end  <=  1'b0  ;
							if((cnt_b == 2'd2)&&(cnt_i2c_clk == 2'd3))
								step  <=  3'd1  ;
							else  if((cfg_num == 3'd3)&&(cnt_i2c_clk == 2'd3))
								step  <=  step + 1'b1  ;
							else  if((cnt_r == 2'd2)&&(cnt_i2c_clk == 2'd3))
								step  <=  step + 1'b1  ;
							else  if((cnt_g == 2'd2)&&(cnt_i2c_clk == 2'd3))
								step  <=  step + 1'b1  ;							
							else
								step  <=  step  ;
							if((i2c_end == 1'b1)&&(cnt_g == 2'd2))
								cnt_g  <=  2'd0  ;
							else  if((i2c_end == 1'b1)&&(cfg_num >= 4'd4)&&(cfg_num <= 4'd6))
								cnt_g  <=  cnt_g + 1'b1  ;
							else
								cnt_g  <=  cnt_g  ;
							if((i2c_end == 1'b1)&&(cnt_r == 2'd2))
								cnt_r  <=  2'd0  ;
							else  if((i2c_end == 1'b1)&&(cfg_num >= 4'd7)&&(cfg_num <= 4'd9))
								cnt_r  <=  cnt_r + 1'b1  ;
							else
								cnt_r  <=  cnt_r  ;	
							if((i2c_end == 1'b1)&&(cnt_b == 2'd2))
								cnt_b  <=  2'd0  ;
							else  if((i2c_end == 1'b1)&&(cfg_num >= 4'd10)&&(cfg_num <= 4'd12))
								cnt_b  <=  cnt_b + 1'b1  ;
							else
								cnt_b  <=  cnt_b  ;									
							if(i2c_end == 1'b1)
								begin
									flag_g  <=  1'b0  ;
									flag_r  <=  1'b0  ;
									flag_b  <=  1'b0  ;
								end
							else
								begin
									flag_g  <=  flag_g  ;
									flag_r  <=  flag_r  ;
									flag_b  <=  flag_b  ;
								end
						 end
			default		:begin
							skip_en_0	<=  1'b0   	;
							skip_en_1   <=  1'b0    ;
							cnt_i2c_clk	<=  2'd0	;
							cnt_bit		<=  3'd0	;
							flag_g		<=  1'b0	;
							cnt_g		<=  2'd0	;
							i2c_end		<=  1'b0    ;
							step		<=  3'd0	;
						 end
		endcase
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rec_data_g  <=  24'd0  ;
	else
		case(c_state)
			DATA	:	if((step == 3'd1)&&(cnt_i2c_clk == 2'd1))
							rec_data_g  <=  {rec_data_g[22:0],sda_in}  ;
						else
							rec_data_g  <=  rec_data_g  ;
			default	:	rec_data_g  <=  rec_data_g  ;	//必须写这一句
		endcase
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rec_data_r  <=  24'd0  ;
	else
		case(c_state)
			DATA	:	if((step == 3'd2)&&(cnt_i2c_clk == 2'd1))
							rec_data_r  <=  {rec_data_r[22:0],sda_in}  ;
						else
							rec_data_r  <=  rec_data_r  ;
			default	:	rec_data_r  <=  rec_data_r  ;	//必须写这一句
		endcase	

always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rec_data_b  <=  24'd0  ;
	else
		case(c_state)
			DATA	:	if((step == 3'd3)&&(cnt_i2c_clk == 2'd1))
							rec_data_b  <=  {rec_data_b[22:0],sda_in}  ;
						else
							rec_data_b  <=  rec_data_b  ;
			default	:	rec_data_b  <=  rec_data_b  ;	//必须写这一句
		endcase	

always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		begin
			data_r	<=  24'd0  ;
			data_g	<=  24'd0  ;
			data_b	<=  24'd0  ;
		end
	else  if((step == 3'd3)&&(c_state == STOP)&&(cnt_b == 2'd2))
		begin
			data_r  <=  rec_data_r  ;
			data_g	<=  rec_data_g  ;
			data_b  <=  rec_data_b  ;
		end
	else
		begin
			data_r  <=  data_r  ;
			data_g	<=  data_g  ;
			data_b  <=  data_b  ;
		end
		
always@(*)
	case(c_state)
		ACK_1,ACK_2,ACK_3
					:	ack_en  =  ~sda_in  ;
		NACK		:	ack_en  =  i2c_sda  ;
		default		:	ack_en  =  1'b0  ;
	endcase
	
always@(*)
	case(c_state)
		IDLE		:	i2c_scl  =  1'b1  ;
		START		:	if(cnt_i2c_clk == 2'd3)
							i2c_scl  =  1'b0  ;
						else
							i2c_scl  =  1'b1  ;
		SLAVE_ADDR,REG_ADDR,DATA,ACK_1,ACK_2,ACK_3,NACK
					:	if((cnt_i2c_clk == 2'd0)||(cnt_i2c_clk == 2'd3))
							i2c_scl  =  1'b0  ;
						else
							i2c_scl  =  1'b1  ;
		WAIT		:	i2c_scl  =  1'b0  ;
		STOP		:	if(cnt_i2c_clk == 2'd0)
							i2c_scl  =  1'b0  ;
						else
							i2c_scl  =  1'b1  ;	
		default		:	i2c_scl  =  1'b1  ;
	endcase
	
always@(*)
	case(c_state)
		IDLE		:	i2c_sda  =  1'b1  ;
		START		:	if((cnt_i2c_clk == 2'd0)||(cnt_i2c_clk == 2'd1))
							i2c_sda  =  1'b1  ;
						else
							i2c_sda  =  1'b0  ;
		SLAVE_ADDR	:	i2c_sda  =  slave_addr[7 - cnt_bit]  ;
		REG_ADDR	:	i2c_sda  =  reg_addr[7 - cnt_bit]  ;
		DATA		:	i2c_sda  =  wr_data[7 - cnt_bit]  ;
		ACK_1,ACK_2,ACK_3,NACK,WAIT	
					:	i2c_sda  =  1'b1  ;
		STOP		:	if((cnt_i2c_clk == 2'd0)||(cnt_i2c_clk == 2'd1))
							i2c_sda  =  1'b0  ;
						else
							i2c_sda  =  1'b1  ;
		default		:	i2c_sda  =  1'b1  ;
	endcase

endmodule

3.顶层模块

module  cls381_top
(
	input	wire			sys_clk		,
	input	wire			sys_rst_n	,
	
	output	wire			scl			,
	output	reg				r_valid		,
	output	reg				g_valid		,
	output	reg				b_valid		,
	
	inout	wire			sda
);

wire			i2c_start	;
wire	[3:0]	cfg_num		;
wire	[15:0]	cfg_data	;
wire			i2c_clk		;
wire			cfg_start	;
wire	[23:0]	data_r		;
wire	[23:0]	data_g		;
wire	[23:0]	data_b		;

always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		begin
			r_valid  <=  1'b0  ;
			g_valid  <=  1'b0  ;
			b_valid  <=  1'b0  ;
		end
	else  if(data_r > data_g + data_b)
		begin
			r_valid  <=  1'b1  ;
			g_valid  <=  1'b0  ;
			b_valid  <=  1'b0  ;
		end
	else  if(data_g > data_r + data_b)
		begin
			r_valid  <=  1'b0  ;
			g_valid  <=  1'b1  ;
			b_valid  <=  1'b0  ;
		end
	else  if(data_b > data_r + data_g)
		begin
			r_valid  <=  1'b0  ;
			g_valid  <=  1'b0  ;
			b_valid  <=  1'b1  ;
		end
	else
		begin
			r_valid  <=  1'b0  ;
			g_valid  <=  1'b0  ;
			b_valid  <=  1'b0  ;		
		end

i2c_ctrl  i2c_ctrl_inst
(
	.sys_clk	(sys_clk	),
	.sys_rst_n	(sys_rst_n	),
	.i2c_start	(i2c_start	),
	.cfg_num	(cfg_num	),
	.cfg_data	(cfg_data	),
	.scl		(scl		),
	.i2c_clk	(i2c_clk	),
	.cfg_start	(cfg_start	),
	.data_r		(data_r		),
	.data_g		(data_g		),
	.data_b		(data_b		),
	.sda        (sda        )
);

cls381_cfg_ctrl  cls381_cfg_ctrl_inst
(
	.i2c_clk	(i2c_clk	),
	.sys_rst_n	(sys_rst_n	),
	.cfg_start	(cfg_start	),
	.cfg_data	(cfg_data	),
	.cfg_num	(cfg_num	),
	.i2c_start	(i2c_start	)
);

endmodule

到了这里,关于ZC-CLS381RGB颜色识别+8x8点阵指示——配置颜色识别寄存器组(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • EasyExcel使用: RGB字体,RGB背景颜色,fillForegroundColor颜色对照表

    使用EasyExcel导出表格可能会对字体颜色和单元格背景颜色进行自定义的修改。 可以自定义字体颜色或者每个单元格的颜色 要想自定义颜色,需要重写CellWriteHandler接口,实现 或者 两个方法,但是只能重写其中一个,全部重写的话只会运行第一个。 首先对于字体自定义颜色

    2024年02月15日
    浏览(37)
  • RGB颜色对照表

    常用颜色: 白色:rgb(255,255,255) 黑色:rgb(0,0,0) 红色:rgb(255,0,0) 绿色:rgb(0,255,0) 蓝色:rgb(0,0,255) 青色:rgb(0,255,255) 紫色:rgb(255,0,255) 颜色大全 RGB颜色对照表 对照表  

    2024年02月13日
    浏览(30)
  • 【音视频原理】图像相关概念 ⑥ ( YUV 与 RGB 之间的转换 | YUV444 颜色编码格式 转为 RGB 格式 | RGB 颜色编码格式 转为 YUV444 格式 )

    YUV 与 RGB 颜色格式之间进行转换时 , 涉及一系列的数学运算 ; YUV 颜色编码格式 转为 RGB 格式 的 转换公式 取决于 于 YUV 的具体子采样格式 : YUV444 YUV422 YUV420 YUV444 格式 转为 RGB 格式 的 转换公式如下 : R = Y + 1.13983 * (V - 128) G = Y - 0.39465 * (U - 128) - 0.58060 * (V - 128) B = Y + 2.03211 * (U

    2024年01月24日
    浏览(50)
  • RGB渐变颜色转换公式及例程

    公式:                         Gradient = A + (B-A) * N / Step Gradient表示第N步的R/G/B的值,A、B、Step表示从颜色A分Step步渐变为颜色B。 例程:        通过使用: 红 -- 绿 -- 蓝 -- 红  分步骤的方式,使其渐变色循环整个颜色值;          (1)红色(255,0,0)---绿色(0,25

    2024年02月05日
    浏览(35)
  • RGB、HSV、HSL和CMYK颜色空间

    目录 简介 RGB(红绿蓝)颜色空间 HSV(色调、饱和度、亮度)颜色空间 HSL(色调、饱和度、亮度)颜色空间 CMYK(青、品红、黄、黑)颜色空间 这四种颜色空间在不同的应用领域有不同的用途: RGB主要用于计算机图形学和显示设备中 ,可以通过调整红、绿、蓝三个分量的值

    2024年02月16日
    浏览(33)
  • 使用OpenCV显示图像的RGB颜色直方图

    2024年02月13日
    浏览(44)
  • STM32读取TCS3472颜色传感器读取RGB颜色和色温值和Lux

    1.3472能提供红,绿,蓝色(RGB)和清晰光感应值的数字输出 2.它通过 I2C协议通讯。 3.最好选择带led灯的版本,自带的led低电平能关闭。 4.这边VIN接5V电压输入,GND接GND,SCL接SCL(PF1)SDA接SDA(PF0),这边根据自己启动的IO口进行变换    5.我这边采用STM32Cube生成使用硬件I2C的方式

    2024年02月13日
    浏览(29)
  • RGB 与 BGR 颜色深度、像素和字节之间的关系

    在处理图像时,了解 RGB 和 BGR 色彩空间之间的区别非常重要。RGB 和 BGR 都具有三个颜色通道:红色、绿色和蓝色。但是,这些通道在图像文件中的存储顺序可能不同。 RGB 通常用于图像编辑和显示应用程序,顺序为红色、绿色和蓝色。 BGR 通常用于图像处理应用程序,顺序为

    2024年02月08日
    浏览(28)
  • 计算机图形学---常用颜色模型汇总(RGB,CMY,HSV)

    本文整理自西安交通大学软件学院祝继华老师的计算机图形学课件,请勿转载 颜色模型 :某个三维颜色空间中的一个 可见光子集 ,包含某个颜色域的所有颜色 用途:在某个颜色域内方便地指定颜色; 在某种特定环境中对颜色的特性和行为的解释方法; 没有一种颜色模型能

    2023年04月08日
    浏览(45)
  • C++ opencv HSV颜色空间转换+RGB三通道提升亮度

    #include iostream #include iomanip #includeopencv2//opencv.hpp using namespace std; using namespace cv; //函数adjustBrightness用于图片增加亮度 void adjustBrightness(cv::Mat image, int targetBrightness) {     // 获取图像的通道数     int channels = image.channels();     // 计算调整亮度的因子     float factor = 1.0f;     if

    2024年03月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包