PAJ7620U2手势识别——读取手势数据寄存器数据与LED指示(完)

2023-11-04


前言

  在前面的教程中呢,小编带领各位读者完成了对所有寄存器的配置,本章教程只需要完成对手势数据寄存器里面的数据读出即可,因为我们只检测上、下、左、右挥手数据,因此用四个led灯作为挥手数据结果指示即可。本章教程是基于FPGA的PAJ7620U2手势识别的最后一章教程,具体实现方法请继续往下浏览。

一、如何读取手势数据寄存器数据?

  在上一章教程中,我们采用的是突发读操作的时序图来对模块进行配置的,但是本章教程我们采用单次读操作对模块进行配置,单次读操作与突发读操作在前半段配置方式都是一样的,都是要指定读取的寄存器:
在这里插入图片描述
  但是在后半段,连续读操作是从DATA状态,跳转到主机返回ACK响应,再从ACK响应跳转到DATA状态,结合官方数据手册:
在这里插入图片描述
  我们发现,不管是采用哪种读方式,读取到数据后,都不会自动停下,这时候结合前面的数据手册,需要我们设置“中断”,当读取到的8位数据不为全0时,则中断读操作。但是呢,我们采用的是FPGA来配置这个模块,对数据的处理就简单得多,因此只需要检测出该模块数据变化,将变化的数据作为LED灯亮起的触发信号,触发以后LED灯在下次触发信号到来时,一直保持亮起即可。
  这里呢,我们采用单次读操作,因为后续利用Singal Tap II触发波形信号的时候,可以观测到从IDLE到STOP一整个的执行周期,因为整个执行周期是非常短暂的,远远小于我们手势变化的时间,因此在这里使用单次读操作是完全可以采集到手势数据的变化情况。

二、配置步骤

1.模块状态转移图绘制

在这里插入图片描述
  从图中可以看出,读取0x43寄存器数值状态转移图与读取0x00寄存器状态转移图绘制方式一样,因此各位读者如果学会了读取0x00寄存器数值操作后,本章教程对大家应该没有难度。

2.模块波形图绘制

在这里插入图片描述
在这里插入图片描述
  从波形图可以看出,除了跳转信号外,我们还需要引入两路信号,一路是po_data_reg,这个信号主要是在DATA状态下寄存拼接的数据。第二路信号是po_data,这个信号是在po_data_reg信号拼接完成后,读取DATA状态末尾拼接完成的数据。我们取po_data信号低四位,这低四位数据,某位由0变化为1后,则代表上、下、左、右挥手动作被检测出来,我们利用这个变化来驱动LED灯亮起。因为驱动LED灯亮起非常简单,我们可以在顶层文件直接编写代码,就不再进行波形图的绘制。

3.上板验证

  设置skip_en_6信号为触发条件:
在这里插入图片描述
  使用连续触发,抓取到的信号波形如图所示:
在这里插入图片描述
  我们发现,在DATA状态下,一直没有采集到数据,并且4个LED灯也一直保持高电平,即熄灭状态。我们向左挥手,抓取到的信号波形如下:
在这里插入图片描述
  可以看到,LED灯已经发生了变化,第二位已经由高电平变为低电平,变亮了。但是为什么DATA状态下,SDA还是为低电平呢?因为我们使用的是连续触发,触发时间非常短暂,po_data采集到数据以后,马上让LED灯点亮,在下次采集数据时,po_data已经归零了,但是LED灯还维持在点亮状态没有改变。接下来,我们分别朝右、上、下挥手,抓取到的信号波形如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
  LED灯低三位数值都有变化,因此我们代码验证通过,且上板现象与预期一致(具体的实验现象各位读者可自行绑定引脚测试,在这里小编就不做演示了),整个工程验证通过。

4.参考代码(i2c_ctrl和paj7620_top)

module  i2c_ctrl
(
	input	wire			sys_clk		,
	input	wire			sys_rst_n	,
	input	wire	[23:0]	cfg_data	,
	input	wire			i2c_start	,
	input	wire	[5:0]	cfg_num		,
	
	output	wire			scl			,							
	output	reg				cfg_start	,
	output	reg				i2c_clk		,
	output	reg		[2:0]	mode		,
	output	reg		[7:0]	po_data		,
	
	inout	wire			sda
);

localparam	CNT_CLK_MAX		=	5'd25	;
localparam	CNT_WAIT_MAX	=	10'd1000;
localparam	CNT_DELAY_MAX	=	10'd1000;
localparam	SLAVE_ID		=	7'h73	;
localparam	SENSOR_ADDR		=	8'hEF	;
localparam	DATA_ADDR		=	8'h43	;
localparam	IDLE		=	4'd0	,
			START		=	4'd1	,
			SLAVE_ADDR	=	4'd2	,
			WAIT		=	4'd3	,
			STOP		=	4'd4	,
			ACK_1		=	4'd5	,
			DEVICE_ADDR	=	4'd6	,
			ACK_2		=	4'd7	,
			DATA		=	4'd8	,
			ACK_3		=	4'd9	,
			NACK		=	4'd10	;

reg		[4:0]	cnt_clk		;	//分频计数器
reg		[9:0]	cnt_wait	;	//开始状态等待1000us计数器
reg				skip_en_0	;	//唤醒状态跳转信号
reg				skip_en_1	;	//激活bank0跳转信号
reg				skip_en_2	;	//配置0x00寄存器状态跳转信号
reg				skip_en_3	;	//读取0x00寄存器状态跳转信号
reg				skip_en_4	;	//配置51个操作寄存器
reg				skip_en_5	;	//配置0x43寄存器状态跳转信号
reg				skip_en_6	;	//读取0x43寄存器状态跳转信号
reg				error_en	;	//读取出来的值不是0x20,错误信号
reg		[3:0]	n_state		;	//次态
reg		[3:0]	c_state		;	//现态	
reg		[1:0]	cnt_i2c_clk	;	//对i2c_clk分频时钟个数计数			
reg		[2:0]	cnt_bit		;	//对传输的8bit数据进行计数	
reg				i2c_scl		;	//就是SCL		
reg				i2c_sda		;	//SDA赋值给i2c_sda
reg		[9:0]	cnt_delay	;	//发送完指令后等待1000us计数器			
reg				i2c_end		;	//i2c结束信号	
reg		[7:0]	po_data_reg	;	//采集数据,拼接完成后赋值给po_data
reg		[7:0]	slave_addr	;	//不同模式下7'h73+1'bx
reg		[7:0]	device_addr	;	//不同模式下寄存器地址变化
reg		[7:0]	wr_data		;	//向地址写入的数据
reg		[7:0]	rec_data	;	//唤醒操作读取0x00寄存器数据寄存
reg				ack			;
wire			sda_in		;
wire			sda_en		;

assign	scl		=	i2c_scl		;
assign	sda_in	=	sda			;	//从设备发送到主机的数据
assign	sda_en	=	((c_state == ACK_1)||(c_state == ACK_2)||(c_state == ACK_3)||((c_state == DATA)&&(mode == 3'd3))||((c_state == DATA)&&(mode == 3'd6))) ? 1'b0 : 1'b1		;	//主机控制sda有效
assign	sda		=	(sda_en == 1'b1) ? i2c_sda : 1'bz  ;

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@(*)
	case(mode)
		3'd0	:slave_addr	=	{SLAVE_ID,1'b0}  ;
		3'd1	:begin
					slave_addr  =	{SLAVE_ID,1'b0}  ;
					device_addr	=	SENSOR_ADDR  ;
					wr_data		=	8'h00  ;
				 end
		3'd2	:begin
					slave_addr  =	{SLAVE_ID,1'b0}  ;
					device_addr	=	8'h00  ;		
				 end
		3'd3	:slave_addr  = 	{SLAVE_ID,1'b1}  ;
		3'd4	:begin
					slave_addr	<=  cfg_data[23:16]  ;
					device_addr	<=  cfg_data[15:8]   ;
					wr_data	    <=  cfg_data[7:0]	 ;
				 end
		3'd5	:begin	
					slave_addr  <=  {SLAVE_ID,1'b0}  ;
					device_addr	<=  DATA_ADDR  ;
				 end
		3'd6	:slave_addr  =  {SLAVE_ID,1'b1}  ;
		default	:begin
					slave_addr	<=  8'd0 ;
					device_addr	<=  8'd0 ;
					wr_data	    <=  8'd0 ;		
				 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  ;
	
//产生i2c驱动时钟	
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)
		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)||(skip_en_4 == 1'b1)||(skip_en_5 == 1'b1)||(skip_en_6 == 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)||(skip_en_4 == 1'b1)||(skip_en_5 == 1'b1)||(skip_en_6 == 1'b1))
							n_state  =  SLAVE_ADDR  ;
						else
							n_state  =  START  ;
		SLAVE_ADDR	:	if(skip_en_0 == 1'b1)
							n_state  =  WAIT  ;
						else  if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_3 == 1'b1)||(skip_en_4 == 1'b1)||(skip_en_5 == 1'b1)||(skip_en_6 == 1'b1))
							n_state  =  ACK_1  ;
						else
							n_state  =  SLAVE_ADDR  ;
		ACK_1		:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_4 == 1'b1)||(skip_en_5 == 1'b1))
							n_state  =  DEVICE_ADDR  ;
						else  if((skip_en_3 == 1'b1)||(skip_en_6 == 1'b1))
							n_state  =  DATA  ;
						else
							n_state  =  ACK_1  ;
		DEVICE_ADDR	:	if((skip_en_1 == 1'b1)||(skip_en_2 == 1'b1)||(skip_en_4 == 1'b1)||(skip_en_5 == 1'b1))
							n_state  =  ACK_2  ;
						else
							n_state  =  DEVICE_ADDR  ;
		ACK_2		:	if((skip_en_1 == 1'b1)||(skip_en_4 == 1'b1))
							n_state  =  DATA  ;
						else  if((skip_en_2 == 1'b1)||(skip_en_5 == 1'b1))
							n_state  =  STOP  ;
						else
							n_state  =  ACK_2  ;
		DATA		:	if((skip_en_1 == 1'b1)||(skip_en_4 == 1'b1))
							n_state  =  ACK_3  ;
						else  if((skip_en_3 == 1'b1)||(skip_en_6 == 1'b1))
							n_state  =  NACK  ;
						else  if(error_en == 1'b1)
							n_state  =  IDLE  ;
						else
							n_state  =  DATA  ;
		ACK_3		:	if((skip_en_1 == 1'b1)||(skip_en_4 == 1'b1))
							n_state  =  STOP  ;
						else
							n_state  =  ACK_3  ;
		WAIT		:	if(skip_en_0 == 1'b1)
							n_state  =  STOP  ;
						else
							n_state  =  WAIT  ;
		NACK		:	if((skip_en_3 == 1'b1)||(skip_en_6 == 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)||(skip_en_4 == 1'b1)||(skip_en_5 == 1'b1)||(skip_en_6 == 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
			cnt_wait	<=  10'd0	;
			skip_en_0	<=  1'b0	;
			skip_en_1	<=  1'b0	;
			skip_en_2   <=  1'b0	;
			skip_en_3   <=  1'b0 	;
			skip_en_4   <=  1'b0	;
			skip_en_5   <=  1'b0	;
			skip_en_6	<=  1'b0	;
			error_en	<=  1'b0	;
			cnt_i2c_clk	<=  2'd0	;
			cnt_bit		<=  3'd0	;
			cnt_delay	<=  10'd0	;
			mode		<=  3'd0	;
			i2c_end		<=  1'b0	;
		end
	else
		case(c_state)
			IDLE		:begin
							cnt_wait  <=  cnt_wait + 1'b1  ;
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;	
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
							if((i2c_start == 1'b1)&&(mode == 3'd4))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;	
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd5))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  1'b0  ;
							if((cnt_wait == CNT_WAIT_MAX - 2'd2)&&(mode == 3'd6))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  1'b0  ;								
						 end
			START		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;			
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd4))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd5))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd6))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  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)&&(mode == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd4))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd5))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd6))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  1'b0  ;									
						 end
			ACK_1		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1)&&(ack == 1'b1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd2)&&(ack == 1'b1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd3)&&(ack == 1'b1))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd4)&&(ack == 1'b1))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd5)&&(ack == 1'b1))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd6)&&(ack == 1'b1))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  1'b0  ;									
						 end
			DEVICE_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)&&(mode == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd4))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd5))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  1'b0  ;								
						 end
			ACK_2		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1)&&(ack == 1'b1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd2)&&(ack == 1'b1))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd4)&&(ack == 1'b1))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd5)&&(ack == 1'b1))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  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)&&(mode == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd3)&&(rec_data == 8'h20))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd4))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd6))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  1'b0  ;								
							if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd3)&&(rec_data != 8'h20))
								begin
									error_en  <=  1'b1  ;
									mode	  <=  3'd0  ;
								end
							else
								begin
									error_en  <=  1'b0  ;
									mode	  <=  mode  ;
								end							
						 end
			ACK_3		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1)&&(ack == 1'b1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd4)&&(ack == 1'b1))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;								
						 end						 
			WAIT		:begin
							if((cnt_delay == CNT_DELAY_MAX - 2'd2)&&(mode == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							cnt_delay  <=  cnt_delay + 1'b1  ;
						 end
			NACK		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd3)&&(ack == 1'b1))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd6)&&(ack == 1'b1))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  1'b0  ;								
						 end
			STOP		:begin
							cnt_i2c_clk  <=  cnt_i2c_clk + 1'b1  ;			
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd0))
								skip_en_0  <=  1'b1  ;
							else
								skip_en_0  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd1))
								skip_en_1  <=  1'b1  ;
							else
								skip_en_1  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd2))
								skip_en_2  <=  1'b1  ;
							else
								skip_en_2  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd3))
								skip_en_3  <=  1'b1  ;
							else
								skip_en_3  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd4))
								skip_en_4  <=  1'b1  ;
							else
								skip_en_4  <=  1'b0  ;
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd5))
								skip_en_5  <=  1'b1  ;
							else
								skip_en_5  <=  1'b0  ;	
							if((cnt_i2c_clk == 2'd2)&&(mode == 3'd6))
								skip_en_6  <=  1'b1  ;
							else
								skip_en_6  <=  1'b0  ;									
							if(cnt_i2c_clk == 2'd2)
								i2c_end  <=  1'b1  ;
							else
								i2c_end  <=  1'b0  ;						    
							if((i2c_end == 1'b1)&&(mode <= 3'd3))
								mode  <=  mode + 1'b1  ;
							else  if((mode == 3'd4)&&(i2c_end == 1'b1)&&(cfg_num == 6'd51))
								mode  <=  mode + 1'b1  ;
							else  if((i2c_end == 1'b1)&&(mode == 3'd5))
								mode  <=  mode + 1'b1  ;
							else
								mode  <=  mode  ;
						 end
			default		:begin
							cnt_wait  	<=  10'd0   ;
							skip_en_0	<=  1'b0	;
							skip_en_1	<=  1'b0	;
							skip_en_2   <=  1'b0	;
							skip_en_3   <=  1'b0	;
							skip_en_4   <=  1'b0	;
							skip_en_5   <=  1'b0	;
							skip_en_6   <=  1'b0	;
							error_en	<=  1'b0	;
							cnt_i2c_clk	<=  2'd0	;
							cnt_bit		<=  3'd0	;
							cnt_delay	<=  10'd0	;
							mode		<=  mode	;
							i2c_end		<=  1'b0	;
						 end
		endcase
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rec_data  <=  8'd0  ;
	else
		case(c_state)
			DATA	:	if((mode == 3'd3)&&(cnt_i2c_clk == 2'd1))
							rec_data  <=  {rec_data[6:0],sda_in}  ;
						else
							rec_data  <=  rec_data  ;
			default	:	rec_data  <=  8'd0  ;
		endcase
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		po_data_reg  <=  8'd0  ;
	else  
		case(c_state)
			DATA	:	if((mode == 3'd6)&&(cnt_i2c_clk == 2'd1))
							po_data_reg  <=  {po_data_reg[6:0],sda_in}  ;
						else
							po_data_reg  <=  po_data_reg  ;
			default	:	po_data_reg  <=  po_data_reg  ;
		endcase
		
always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		po_data  <=  8'd0  ;
	else  if((cnt_i2c_clk == 2'd2)&&(cnt_bit == 3'd7)&&(mode == 3'd6))
		po_data  <=  po_data_reg  ;
	else
		po_data  <=  po_data  ;
		
always@(*)
	case(c_state)
		ACK_1,ACK_2,ACK_3  :  ack  =  ~sda_in  ;
		NACK			   :  ack  =  i2c_sda  ;
		default	:	ack  =  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,ACK_1,DEVICE_ADDR,ACK_2,DATA,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)
							i2c_sda  =  1'b1  ;
						else
							i2c_sda  =  1'b0  ;
		SLAVE_ADDR	:	i2c_sda  =  slave_addr[7 - cnt_bit]  ;
		ACK_1,ACK_2,ACK_3,
					:	i2c_sda	 =  1'b0  ;
		NACK		:	i2c_sda  =  1'b1  ;
		DEVICE_ADDR	:	i2c_sda  =  device_addr[7 - cnt_bit]  ;
		DATA		:	i2c_sda  =  wr_data[7 - cnt_bit]  ;
		WAIT		:	i2c_sda  =  1'b0  ;
		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
module  paj7620_top
(	
	input	wire			sys_clk		,
	input	wire			sys_rst_n	,
	
	output	wire			scl			,
	output	reg		[3:0]	led			,
	
	inout	wire			sda	
);

wire	[23:0]	cfg_data	;
wire			i2c_start	;
wire	[5:0]	cfg_num		;
wire			i2c_clk		;
wire	[2:0]	mode		;
wire			cfg_start	;
wire	[7:0]	po_data		;

always@(posedge i2c_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		led  <=  4'b1111  ;
	else  if(po_data[3:0] == 4'b0001)
		led  <=  4'b1110  ;
	else  if(po_data[3:0] == 4'b0010)
		led  <=  4'b1101  ;
	else  if(po_data[3:0] == 4'b0100)
		led  <=  4'b1011  ;	
	else  if(po_data[3:0] == 4'b1000)
		led  <=  4'b0111  ;
	else
		led  <=  led  ;

i2c_ctrl  i2c_ctrl_inst
(
	.sys_clk	(sys_clk	)	,
	.sys_rst_n	(sys_rst_n	)	,
	.cfg_data	(cfg_data	)	,
	.i2c_start	(i2c_start	)	,
	.cfg_num	(cfg_num	)	,
	.scl		(scl		)	,
	.i2c_clk	(i2c_clk	)	,
	.mode		(mode		)	,
	.cfg_start	(cfg_start	)	,
	.po_data	(po_data	)	,
	.sda        (sda        )
);

paj7620_cfg  paj7620_cfg_inst
(
	.i2c_clk	(i2c_clk	),
	.sys_rst_n	(sys_rst_n	),
	.cfg_start	(cfg_start	),
	.mode		(mode		),
	.cfg_data	(cfg_data	),
	.cfg_num	(cfg_num	),
	.i2c_start  (i2c_start  )
);

endmodule

总结

  小编在这里用了7章的教程,带领各位读者完成了对paj7620手势识别模块上、下、左、右的识别配置,感谢各位读者的支持,后续将为大家带来4x4矩阵键盘密码锁工程的实现,敬请期待。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PAJ7620U2手势识别——读取手势数据寄存器数据与LED指示(完) 的相关文章

  • 各种FIFO硬件设计(FIFO概念、异步、同步、非2次幂深度FIFO)

    文章目录 一 FIFO概述 二 FIFO分类 三 FIFO重要信号与参数 3 1 信号 3 2 参数 3 2 1 data depth的确定 四 FIFO存储原理 五 同步FIFO 5 1 空满信号判断 5 2 同步FIFO源码 5 3 测
  • 【Xilinx Vivado时序分析/约束系列6】FPGA开发时序分析/约束-IO时序输入延时

    目录 源同步FPGA输入时序分析的模型 input delay约束 极限input delay 往期系列博客 源同步FPGA输入时序分析的模型 以下为源同步FPGA输入时序分析的模型的示意图 在之前的文章中介绍过 在此介绍一下各个时钟延时的
  • 8x8LED点阵

    点量这个只需要把9高电平 13低电平就可以了 共阳极点阵 行线是led的正极 列线是led的列线 左上角点亮 显示多个灯是动态扫描的 一个一个显示的 然后间隔速度要快就可以造成显示 点阵由两篇74Hc595级联在一起驱动的 只需要三个io口
  • DDR的VTT有源端接和无源端接(slua886a笔记)

    DDR的VTT有源端接和无源端接 slua886a笔记 背景 对于DDR的VTT端接 一直有说法是有源端接可降低功耗 之前一直没仔细理解其中原因 现在找了些相关的资料来介绍和对比有源和无源端接 理解有源端接的优点和降低功耗的原理 主要基于读
  • Vivido添加pynq-Z2开发板

    一 下载pynq z2开发板文件 下载地址 https www tulembedded com FPGA ProductsPYNQ Z2 html 二 将下载的文件解压到vivado安装的位置 如果boards目录下面没有boards fi
  • Verilog中forever、repeat、while、for四类循环语句(含Verilog实例)

    当搭建FPGA逻辑时 使用循环语句可以使语句更加简洁易懂 Verilog中存在四类循环语句 如标题 几种循环语句的具体介绍和用法如下 1 forever 连续的执行语句 语法格式 forever
  • Verilog实例-AMBA(AHB)协议

    目录 一 简介 1 1 AHB 1 2 signal list 1 3 Bus interconnection 总线互联 1 4 Overview of AMBA AHB operation 1 4 1 Basic transfer 1 4
  • 【FPGA入门】第八篇、FPGA驱动VGA实现动态图像移动

    目录 第一部分 实现效果 第二部分 动态VGA显示的原理 1 将动态显示的区域提前进行赋值 2 图像块的移动是每张图片叠加后的效果 3 如何实现图像块位置的改变 第三部分 系统结构和驱动波形 1 系统的Top down结构 2 图像块移动的
  • Verilog HDL——分频 计数

    分频 计数 module traffic Clk 50M Rst Clk30 Clk 1Hz input Clk 50M Rst output Clk30 Clk 1Hz 分频器 reg Clk 1Hz 分频器 50M分频 reg 31 0
  • 手把手教你Modelsim仿真【2020.4版本】

    首先新建一个文件夹 test5 打开Modelsim 依次选择 File gt Change Directory 把目录选择到创建的 test5 文件夹 创建库 依次选择 File gt New gt Library 一般我们选择第三个 库
  • verilog中wire和reg类型的区别

    module counter parameter CNT MAX 25 d24 999 999 input wire sys clk input wire sys rst n output reg led out reg 24 0 cnt
  • 用Vscode编辑verilog代码配置

    这篇教程感觉很详细了 我这里分享一下vscode和插件的安装包链接 都是官网下载的 放心食用 用VSCode编辑verilog代码 iverilog编译 自动例化 自动补全 自动格式化等常用插件 链接 https pan baidu com
  • 握手2倍速率进,一倍速率出[verilog]

    module two to one parameter WORD LEN 33 input clk input arst input 2 WORD LEN 1 0 i din input i din valid output o din r
  • FPGA硬件工程师Verilog面试题(基础篇二)

    作者简介 大家好我是 嵌入式基地 是一名嵌入式工程师 希望一起努力 一起进步 个人主页 嵌入式基地 系列专栏 FPGA Verilog 习题专栏 微信公众号 嵌入式基地 FPGA硬件工程师Verilog面试题 二 习题一 多功能数据处理器
  • FPGA_时钟显示(时钟可调)

    1 实验说明 在数码管显示数据的基础上 让六位数码管显示数字时钟 并且通过按键可以对时间进行修改 实验目标 六位数码管分别显示时间的时分秒 且通过按键可实现加减调整时间及清零功能 key1 切换键 选择待调整的时间单位 时 分 秒 key2
  • Verilog HDL——Modelsim仿真

    常用testbench语法 finish 和 stop finish任务用于终止仿真并跳出仿真器 stop任务则用于中止仿真 timescale time unit time precision time unit指定计时和延时的测量单位
  • PAJ7620U2手势识别——配置0x00寄存器(3)

    文章目录 前言 一 为啥要配置0x00寄存器 二 配置步骤 1 单个读操作步骤图 2 模块状态转移图绘制 3 模块波形图绘制 4 上板验证 5 参考代码 总结 前言 在前面的教程中 小编带领各位读者学习了如何通过I2C协议去唤醒PAJ762
  • 【电子技术】什么是LFSR?

    目录 0 前言 1 数学基础 1 1 逻辑异或 1 2 模2乘法 和 模2除法 2 线性反馈移位寄存器LFSR 3 抽头和特征多项式 4 阶线性反馈移位寄存器实例 0 前言 线性反馈移位寄存器 Linear Feedback Shift R
  • 画时序图软件——TimeGen和Timing Designer下载

    在写实验报告的时候需要画波形图 但是手头没有很好的软件 就上网搜了一些 分享出来 这里分享的是TimeGen和Timing Designer两个软件 资源均来自网上 有侵权请联系 TimeGen使用和安装都比较简单 我发的应该里面有破解方法
  • 串口通信知识点总结

    串口是串行接口 serial port 的简称 也称为串行通信接口或COM接口 串口通信是指采用串行通信协议 serial communication 在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式 串口按电气标准及协议来划分

随机推荐

  • 子类的构造函数和析构函数

    1 构造函数是否可以被继承 子类可以继承父类的所有成员变量和成员函数 但不能继承父类的构造函数 因此 在创建子类对象时 为了初始化从父类继承来的数据成员 系统需要调用其父类的额构造函数 2 父类构造函数的调用规则 如果子类没有定义构造函数
  • axios的三层封装思想

    1 工具函数层 设置默认请求地址 设置默认超时时间 设置默认请求拦截 设置默认响应拦截 ajax工具函数层 import axios from axios axios defaults baseURL http localhost 5000
  • vue2插件开发小试

    开发vue插件的官方文档是这样描述的 插件通常会为Vue添加全局功能 插件的范围没有限制 一般有下面几种 1 添加全局方法或者属性 如 vue element 2 添加全局资源 指令 过滤器 过渡等 如 vue touch 3 通过全局 m
  • KDD 2023

    下载地址 点我跳转 1 DoubleAdapt A Meta learning Approach to Incremental Learning for Stock Trend Forecasting Code None Area 一种用于
  • ubuntu 安装Pangolin 过程

    前言 大家好 好久没有写技术博客了 在工作学习中遇到一些问题及解决方法 希望能帮助到大家 Pangolin 想必大家都非常熟悉了 这个是一款开源的OPENGL显示库 可以用来视频显示 而且开发容易 代码我们可以从Github 进行下载 ht
  • JSP基础语法

    1 gt 2 gt hr
  • C++(13)——STl之List的实现

    STL STL是C 的标准模板库 是一个具有工业强度 高效的C 程序库 STL一个最为重要的特点就是数据结构和算法的分离 你可以使用其中的一些函数操作几乎热河的数据集合 包含链表 容器和数组 STL的另一个特性就是它不是面向对象的 STL主
  • 【环境配置】安装 Visual Studio 2022 Community 卡住了&& 安装 Windows SDK (Software Development Kits)卡住了

    问题原因 a 系统升级了 b 之前卸载没卸载干净 注册表里存在旧的信息 解决过程 1 查看日志 在资源管理器中输入 TEMP windowssdk 查看日志文件 找到最新的日志文件 在文件中搜索 Warning 出现了一组长串数字 用 括起
  • 基于Matlab小车倒立摆系统的控制(附上完整源码+数据)

    本文介绍了如何使用Matlab对小车倒立摆系统进行控制 倒立摆是一种经典的控制系统问题 通过控制小车的速度和方向 实现倒立摆的平衡 本文使用了模糊控制算法和PID控制算法来实现系统的控制 并通过Matlab进行仿真和实验验证 文章目录 1
  • Linux--编译链接(过程、原理、执行、多个文件)

    1 编译链接四个步骤 1 预编译 gcc E main c o main i 2 编译 gcc S main i o main s 3 汇编 gcc c main s o main o 4 链接 gcc main o o main 执行 m
  • 报错:RuntimeError: CUDA error: no kernel image is available for execution on the device

    报错 RuntimeError CUDA error no kernel image is available for execution on the device 提醒 安装pytorch时 除了要注意pytorch与torchvisi
  • vue 父子 子父 传值

    文档 Vue js 渐进式 JavaScript 框架 Vue js vuejs org 父给子传值 父组件
  • 【计算机基础】面试常问之进程、线程和协程

    文章目录 背景 为什么会有进程 线程和协程 1 进程的出现 2 线程的出现 3 协程的出现 1 进程 Process 1 1 什么是进程 程序与进程的区别 特点 1 2 进程通信及使用场景 无名管道 pipe 命名管道 FIFO 消息队列
  • 什么是区块链?为什么需要区块链?

    从个故事开始吧 第一章 信任 账本时代的故事 小王问你借100W 答应一年后还你200W 你心动了 可是又怕他不还 于是乎你找到了你们村长做鉴证人 你打了一个借条 上面写着 2018年 月小王借小胡100W 答应2019年 月还小胡200W
  • 服务器系统初始化时间长,企业级-Shell案例1——服务器系统配置初始化

    bin bash 安装系统性能分析工具及其他 yum install gcc make autoconf vim sysstat net tools iostat iftop iotp wget lrzsz lsof unzip opens
  • BUUCTF【Web】LoveSQL

    进入靶场后感觉这个SQL很熟悉 跟之前的第一关easySQL相似 但是这关显然要更难一点 还是用之前的方法 用1 试试发现有回显 所以这一关还是单引号闭合 首先使用万能用户名 密码随便输入 1 or 1 1 得到提示 此时发现他的用户名是a
  • Jetpack学习之Lifecycle

    Jetpack是Google为了解决Android架构问题而引入的 Google官方说的说法 Jetpack是一套库 工具和指南 可以帮助开发者更轻松地编写应用程序 Jetpack中的组件可以帮助开发者遵循最佳做法 摆脱编写样板代码的工作并
  • DVWA不能修改等级问题解决

    在DVWA平台上进行测试时 会出现等级改了 但是有的模块是impossible的情况 我是这样解决的 1 先清空浏览器的缓存 这里可以清空最近的 就是打开DVWA之后的清空就可以了e g 最近一小时 2 退出DVWA 重新登录 3 换了浏览
  • CMakeList实战

    1 FIND PACKAGE FIND PACKAGE
  • PAJ7620U2手势识别——读取手势数据寄存器数据与LED指示(完)

    文章目录 前言 一 如何读取手势数据寄存器数据 二 配置步骤 1 模块状态转移图绘制 2 模块波形图绘制 3 上板验证 4 参考代码 i2c ctrl和paj7620 top 总结 前言 在前面的教程中呢 小编带领各位读者完成了对所有寄存器