前言
在现代工业生产中,颜色识别技术已经成为了一个非常重要的技术。颜色识别可以用于产品质量检测、物料分类、机器视觉等领域。本文将介绍如何使用FPGA结合ZC-CLS381RGB进行颜色识别。
本教程通过对采集到的图像信息中,R、G、B三个颜色分量的占比,来判断识别到的颜色信息。本教程只实现对红色、绿色、蓝色的识别,如果各位读者要想实现对其它色彩信息的识别,可根据三个色彩分量的占比来判断。
一、ZC-CLS381RGB简介
ZC-CLS381RGB是一款基于RGB三基色原理的颜色识别传感器。它可以通过对物体反射光的RGB三基色分量进行测量,来判断物体的颜色。该传感器具有高精度、快速响应、稳定性好等特点,广泛应用于自动化生产线、机器人、智能家居等领域。
二、配置寄存器组
ZC-CLS381RGB是一款RGB LED驱动器芯片,需要通过配置寄存器来让该模块正常工作。下面就对颜色识别需要配置的寄存器进行介绍。
1.主控寄存器
MAIN_CTRL Register是主控寄存器,下图是主控寄存器的配置介绍:
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是环境光传感器和颜色传感器检测速率寄存器,下图是对该寄存器的配置介绍:
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是环境光传感器和颜色传感器增益寄存器,下图是对该寄存器的配置介绍:
bit7~bit3:保留位(Reserved),使用时这两位需要置0。
bit2~bit0:环境光传感器和颜色传感器增益率位(Reserved),初始化时设置{bit2,bit1,bit0}=100,将增益率调到最大,以此增强信号的强度,使得信号更容易被检测到。
2.颜色数据寄存器
因为本教程采集的是红色、绿色、蓝色数据,芯片手册提供的寄存器组如下图所示:
0x0D、0x0E、0x0F分别表示绿色信息的低8位、中8位、高8位数据;0x10、0x11、0x12分别表示红色信息的低8位、中8位、高8位数据;0x13、0x14、0x15分别表示蓝色信息的低8位、中8位、高8位数据。在使用中,直接读取这些寄存器内的数据,然后拼接起来,即可得到红、绿、蓝色数据,再根据三个数据的占比,从而对采集到的物体颜色进行判断。
三、状态转移图和信号波形图绘制
在正式开始使用器件时,需要等待一段时间让器件稳定下来,如图所示:
待机唤醒时间最大为10ms,表示在测量的时候,两次获取数据的时间间隔最大为10ms。由于在数据手册内,未说明上电后直到模块稳定需要等待的时间,在这里我们人为设置上电等待的时间为20ms,给模块一个缓冲的时间,然后再对它进行配置。配置寄存器组信号波形图如下图所示:
其中,i2c_start作为i2c控制模块的开始信号,检测到该开始信号后,就开始配置寄存器,向各个寄存器内写入数据。综上绘制的i2c控制模块配置寄存器组的状态转移图如下图所示:
为了设计方便,对于50MHZ的系统时钟,将其分频为1MHZ的i2c驱动时钟用来驱动后续模块,同时令一个SCL时钟周期为4us,高电平持续时间为2us,低电平持续时间也为2us。这样设计的好处是,满足SCL高电平持续时间大于0.6us,SCL低电平持续时间大于1.3us。如下图所示:
综上,绘制的分频信号波形图如下图所示:
结合状态转移图,绘制的配置寄存器信号波形图如下图所示:
需要注意的是,配置寄存器组跳转条件为skip_en_0,这里配置的寄存器是向寄存器里面写入数据,总共需要配置三个,三个寄存器配置完成后,才能读出颜色数据。因此,step从0自增到1,必须要在cfg_num为3并且检测到结束信号的情况下进行。文章来源:https://www.toymoban.com/news/detail-772632.html
总结
本章配置完成颜色识别所需的寄存器,下一章完成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模板网!