32单片机矩阵键盘-同列组合键不能识别故障-已解决

news2024/11/24 12:58:23

一、电路原理

1.1. 矩阵键盘电路

 1.2. gd32f103单片机端是iic,中间经过一个pca9535芯片。

1.3 pca9535 的功能请参考相关文档

这里主要用到的是设置输入输出模式,读取输入值,输出高或者输出低等功能。

二、基本要求

2.1 单个按键识别

2.2 组合键识别(一般是两个按键同时按下)

2.3 按键消抖

2.4 防止识别重复按键,不需要识别长短按键。

三、前期已经完成的识别程序

3.1 程序基本原理描述(称为行扫描模式)

3.1.1 L信号(P1端口)作输入模式,H信号(P0端口)作输出模式,任意时刻只有一个H信号为低电平,其他为高电平。

使用i计数,i=0时,H1为低,其他(H2-H6)输出高,读取L信号,如果都为1(取低6位,0x3f),则表示没有按键被按下,如果不等于0x3f,则表示有按键被按下,有按键被按下,则需要循环6次,判断其中的哪些位(考虑多个按键被按下的情况)为0,则为0的位表示有按键被按下,这样就找到了被按下的按键。

其他行依次类推,i=1时,H2输出低,其他(H1,H3-H6)输出高。

L信号是输入引脚,外部电路有10K上拉电阻,如果不跟外部连接的话,读信号肯定是个高电平,所以没有按键按下时,判断为高电平。

如果按键按下,同时按键所在的H信号正好也是低电平的话,按键闭合导致电路形成回路,上拉电阻的一端(这一端正好接着L信号)电压被拉低为0,L读到的正好也是低电平,这时可以判断按键被按下。特别说明,H信号为高的时候,即使按键被按下,L信号仍然是高,没法得出按键被按下的情况。所以这里一定要某一个H信号(比如H1)为低,其他H信号(则是H2-H6)为高,就能够分辨是哪一行有按键了。

3.1.2 按键也要消抖,这里是连续采集到两次,则认为识别到了一个有效按键。

g_btns_info.pressCnt[index]++;

3.1.3 按键也要防止重复识别,按下一次就识别一次,不能因为久按而识别多次。

if(g_btns_info.pressCnt[index] < 2)
 {    
           g_btns_info.pressCnt[index]++;
            if(g_btns_info.pressCnt[index] == 2)//检测到不止1次

3.1.4 我程序中有串口上报键值的部分,可以注释掉。printf是串口打印,用于调试

send_btn_change_to_cpu(index+1,1); //发送按键按下/松开

3.2 源程序

结构体

typedef struct btn_info{
    uint8_t  value[KEY_MAX];         //0表示松开,1表示按下
    uint8_t  reportEn[KEY_MAX];   //1,需要上报,0不需要上报
    uint16_t  pressCnt[KEY_MAX];     //消抖,长按区分
}BTN_INFO;

		
//只有6行,这些数字用于分别扫描每一行
const static uint8_t key_scan_line[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};

// 6*6 的键盘矩阵,总共有33个按键,按键个数在h文件中定义
static BTN_INFO g_btns_info;

TaskHandle_t  TaskHandle_key_Matrix;   //存放按键任务指针



//端口的配置
void matrix_keys_init(void)
{
	uint8_t outcfg_dat[2]={0,0xff};   //IIC芯片GPIO输出模式,对应的位要设置为0
	//1. iic的初始化
	nca9555_init(NCA9555_IIC_CONTROLER);
		
	//矩阵按键,P0端口配置为输出,P1端口配置为输入,因为P1端口上用了上拉电阻
	nca9555_write_2config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,outcfg_dat);

	nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0); //P0端口输出0

#ifdef 	BTNS_USE_INT   //宏在btns_leds.h中定义
	//中断引脚初始化
	//2. 中断引脚的初始化 PB12,外部中断12
	//2.1 时钟使能
	rcu_periph_clock_enable(RCU_GPIOB);
	rcu_periph_clock_enable(RCU_AF);		
	
	gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, GPIO_PIN_12);	
	
	//2.2 复用为外部中断引脚,
	gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_12);
	
	//设置触发方式,低电平触发
	exti_init(EXTI_12, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
	exti_interrupt_enable(EXTI_12);
	exti_interrupt_flag_clear(EXTI_12);
	//2.3 nvic允许中断
	//中断控制器使能,使用的是外部中断12
	nvic_irq_enable(EXTI10_15_IRQn,  7, 0);   //允许中断,并设置优先级

	//初始化之后读取一次
	matrix_keys_row_scan();	

#endif			
	memset(&g_btns_info,0,sizeof(g_btns_info));   //数据清零	
}








static uint8_t matrix_keys_row_scan(void)
{
	uint8_t key_row_dat;
	//读取P1(L信号)端口的值
	if(nca9555_read_inport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,1,&key_row_dat) == 0)  //表示读取成功
	{
		if((key_row_dat&0x3f) != 0x3f)   //只判断低6位,不相等表示有按键按下
		{
			return key_row_dat&0x3f;
		}
		else
		{
			return 0x3f;
		//	printf("ERROR: KEY_ROW_SCAN key_row_dat == 0x3f\r\n");
		}
	}
	else //iic读取失败
	{
		printf("ERROR: KEY_ROW_SCAN nca9555_read_inport\r\n");
		return 0xff;
	}
}

				
							

/***
 *函数名:KEY_SCAN
 *功  能:6*6按键扫描
 *返回值:1~36,对应36个按键,0表示没有检测到
 */
char matrix_keys_scan(void)
{    
    uint8_t key_row_num=0;        //行扫描结果记录
    uint8_t i,j;
	uint8_t index;   //
	static uint8_t release_report = 0;  //松开上报。
	
	key_row_num = matrix_keys_row_scan();
	if(key_row_num < 0x3f)   //读取到了一个有效的按键触发
	{	
		for(i=0;i<COL_NUM;i++)  //每一列扫描一次
		{
			//分六次,对行信号进行分别输出,任意时刻,只有一个行信号是0,其他都是高电平
			if(nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, key_scan_line[i])) //P0端口输出0
			{
				printf("ERROR: KEY_ROW_SCAN nca9555_write_outport i=%d\r\n",i);
				continue;  //写入失败,直接往下试试
				//	return -1;
			}
			//再次读取输入
			key_row_num = matrix_keys_row_scan();

			for(j=0;j<ROW_NUM;j++)  //每一行扫描一次
			{
				index = 6*i+j;
				if(!((key_row_num>>j)&(1))) //按下
				{
					if(g_btns_info.pressCnt[index] < 2)
					{	
						g_btns_info.pressCnt[index]++;
						if(g_btns_info.pressCnt[index] == 2)//检测到不止1次
						{   //条件限制上报一次
							g_btns_info.value[index] = 1;
						//	g_btns_info.reportEn[index] = 1;  //按下上报
							send_btn_change_to_cpu(index+1,1); //发送按键按下/松开
							printf("----btn:%d press\r\n",index+1);
							release_report = 1;   //记录需要释放标志
						}
					}
				}
				else //松开
				{
					if(g_btns_info.value[index]) //之前的状态是按下
					{
						g_btns_info.value[index] = 0;
					//	g_btns_info.reportEn[index] = 2;   //松开上报
						send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
						printf("++++btn:%d release\r\n",index+1);
						g_btns_info.pressCnt[index] = 0;
					}		
				}
			}
		}
	}
	else
	{
		if(release_report)  //需要上报释放信息。
		{		
			for(index=0;index<COL_NUM*ROW_NUM;index++)
			{
				if(g_btns_info.value[index]) //之前的状态是按下
				{
					g_btns_info.value[index] = 0;
				//	g_btns_info.reportEn[index] = 2;   //松开上报
					send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
					printf("#####btn:%d release\r\n",index+1);
					g_btns_info.pressCnt[index] = 0;
				}
				
			}
		//	btn_start_scan = 0;   //按键不再扫描
			release_report = 0;
		}
	}
	
	//设置输出0,这样按下时,L端就会变为0,触发中断
	nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0);	
	
	return 0;
}




#ifdef 	BTNS_USE_INT
//外部中断12的处理函数,按键按下和松开都会触发中断!!!!
void exint12_handle(void)
{

	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	
	xTaskNotifyFromISR(TaskHandle_key_Matrix, 0, eIncrement, &xHigherPriorityTaskWoken);  //唤醒休眠的任务
	//并且禁止中断
	exti_interrupt_disable(EXTI_12);   //扫描完毕之后再使能
}

#endif


//freeRTos任务
void task_matrix_keys_scan(void* arg)
{	
	//1. 矩阵按键扫描初始化
	matrix_keys_init();

	while(1)
	{	
		//等待任务被唤醒
		ulTaskNotifyTake(pdFALSE, portMAX_DELAY);   //减1,然后无限等待
		{	
			matrix_keys_scan();

			vTaskDelay(30);    //延时30ms
#ifdef 	BTNS_USE_INT	
			exti_interrupt_enable(EXTI_12);   //扫描完毕之后再使能		
#endif

		}		
	}
}

单个按键的识别是正常的,不在同列的组合按键也是没有问题的。

 

四、遇到的问题

4.1 部分组合键不能识别

同一列(同一根L线上)比如A2+A8这种类似的组合都不能正常识别。

按下A2时,(程序打印)提示A2被按下,A2不松开的情况下,同时按下A8,程序提示A2松开。

反之,先按下A8,提示A8按下,同时把A2也按下,提示A8松开。

4.2 不正常的组合键的示波器波形(测试L引脚上的信号)

 4.3 正常的按键的示波器波形(测试L引脚上的信号)

 4.4 大致原因

从示波器来看的话,很明显的低电平没有拉下去,而单片机将那样的一个电平识别为高。

软件得到高电平,认为第一次的按键被释放。(实际是两个按键同时按下了)。

这确实是个芯片问题,没想到9535这个芯片输出低的时候,阻抗这么大,还是说两个按键同时按下之后,实际是芯片内部电路被短路了,因为有一个引脚是高,而另一个引脚是低,这个时候电流大,导致芯片内部一些保护措施?

 H中只有一个为低,两个按键按下后,所以必然会有这样的问题是存在的。(这里假设A2和A8同时按下 的情况)

五、问题的解决

5.1  考虑列扫描的方式

行扫描有问题,那能不能换成列扫描呢?

两个按键在同一个列上,那换成列扫描,两个按键就肯定不会在同一行,这个确实是可以的。

然而,我尝试了一下,发现可以解决这个问题,但是同一行的两个按键又不可识别了。

这里因为行没有接上拉电阻,我只能用默认这个H的信号为低电平,有按键按下时是高电平

	//只有6行,这些数字用于分别扫描每一行
const uint8_t key_scan_line[] = {0x1,0x2,0x4,0x8,0x10,0x20};


 
//端口的配置,全部配置为输入接口
void matrix_keys_init(void)
{
	uint8_t outcfg_dat[2]={0xff,0xff};   //IIC芯片GPIO输出模式,对应的位要设置为0
	//1. iic的初始化
	nca9555_init(NCA9555_IIC_CONTROLER);
		
	//矩阵按键,P0端口配置为输出,P1端口配置为输入,因为P1端口上用了上拉电阻
	nca9555_write_2config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,outcfg_dat);

//	nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0); //P0端口输出0
	
	//默认是输入,把输入寄存器读出来一次,读出来的值不关心
	nca9555_read_inport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0,outcfg_dat);
	nca9555_read_inport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,1,outcfg_dat);
	
	//P1 端口的输出寄存器全部配置为0,表示输出的时候会输出低电平
	outcfg_dat[0] = 0;
	outcfg_dat[1] = 0;
	nca9555_write_2outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,outcfg_dat);
	//key_board cs引脚PE8,不需要??
//	rcu_periph_clock_enable(RCU_GPIOE);			
//	gpio_init(GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_8);	
//	gpio_bit_reset(GPIOE, GPIO_PIN_8);

#ifdef 	BTNS_USE_INT   //宏在btns_leds.h中定义
	//中断引脚初始化
	//2. 中断引脚的初始化 PB12,外部中断12
	//2.1 时钟使能
	rcu_periph_clock_enable(RCU_GPIOB);
	rcu_periph_clock_enable(RCU_AF);		
	
	gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, GPIO_PIN_12);	
	
	//2.2 复用为外部中断引脚,
	//GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9);
	gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_12);
	
	//设置触发方式,低电平触发
	exti_init(EXTI_12, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
	exti_interrupt_enable(EXTI_12);
	exti_interrupt_flag_clear(EXTI_12);
	//2.3 nvic允许中断
	//中断控制器使能,使用的是外部中断12
	nvic_irq_enable(EXTI10_15_IRQn,  1, 2);   //允许中断,并设置优先级

	//初始化之后读取一次
	//matrix_keys_row_scan();	

#endif		
	
	memset(&g_btns_info,0,sizeof(g_btns_info));   //数据清零
	
	
}




uint8_t matrix_keys_row_scan(void)
{
	uint8_t key_row_dat;
	
	nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0x0);  //设置输出,释放一下电平
	nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0xff);  //设置输入
	//读P0端口,没有按键时,应该是0,有按键时不是0
	if(nca9555_read_inport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0,&key_row_dat) == 0)  //表示读取成功
	{
		if((key_row_dat & 0x3f) != 0)   //只判断低6位,不相等表示有按键按下
		{
			return key_row_dat&0x3f;
		}
		else
		{
			return 0x7f;
		//	printf("ERROR: KEY_ROW_SCAN key_row_dat == 0x3f\r\n");
		}
	}
	else //iic读取失败
	{
		printf("ERROR: KEY_ROW_SCAN nca9555_read_inport\r\n");
		return 0xff;
	}
}




 
char matrix_keys_scan(void)
{    
//    uint8_t Key_Num=0xff;            //1-16对应的按键数
    uint8_t key_row_num=0;        //行扫描结果记录
    uint8_t i,j;
	uint8_t index;   //
	static uint8_t release_report = 0;  //松开上报。
	
	key_row_num = matrix_keys_row_scan();
	if(key_row_num < 0x3f)   //读取到了一个有效的按键触发
	{
		for(i=0;i<COL_NUM;i++)  //每一列扫描一次
		{
			
			//P1端口只有一个引脚为输入模式,其他为输出,并且输出低电平
			if(nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,1, key_scan_line[i])) 
			{
				printf("ERROR: KEY_ROW_SCAN nca9555_write_outport i=%d\r\n",i);
				continue;  //写入失败,直接往下试试
				//	return -1;
			}
			//再次读取输入
			key_row_num = matrix_keys_row_scan();
			
		//	printf("i = %d num = %#x\r\n",i,key_row_num);
			
			if(key_row_num >= 0x3f)
				continue;
			
			for(j=0;j<ROW_NUM;j++)  //每一行扫描一次
			{
				index = 6*i+j;
				if(((key_row_num>>j)&(1))) //按下
				{
					if(g_btns_info.pressCnt[index] < 2)
					{	
						g_btns_info.pressCnt[index]++;
						if(g_btns_info.pressCnt[index] == 2)//检测到不止1次
						{   //条件限制上报一次
							g_btns_info.value[index] = 1;
						//	g_btns_info.reportEn[index] = 1;  //按下上报
							send_btn_change_to_cpu(index+1,1); //发送按键按下/松开
							printf("----btn:%d press\r\n",index+1);
							release_report = 1;   //记录需要释放标志
						}
					}
				}
				else //松开
				{
					if(g_btns_info.value[index]) //之前的状态是按下
					{
						g_btns_info.value[index] = 0;
					//	g_btns_info.reportEn[index] = 2;   //松开上报
						send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
						printf("++++btn:%d release\r\n",index+1);
						g_btns_info.pressCnt[index] = 0;
					}
		
				}
			}		
		}
	}
	else
	{
		if(release_report)  //需要上报释放信息。
		{		
			for(index=0;index<COL_NUM*ROW_NUM;index++)
			{
				if(g_btns_info.value[index]) //之前的状态是按下
				{
					g_btns_info.value[index] = 0;
				//	g_btns_info.reportEn[index] = 2;   //松开上报
					send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
					printf("####btn:%d release\r\n",index+1);
					g_btns_info.pressCnt[index] = 0;
				}
				
			}
			btn_start_scan = 0;   //按键不再扫描
			release_report = 0;
		}
	}
	//P1端口全部改为输入模式
	//nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0x0);  //设置输出,释放一下电平
	nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,1, 0xff);
//	nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0xff);
	//nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0);	
	
	return 0;
}

5.2  在原有行扫描的基础上,增加列扫描方式。

后来发现如果按下两个键的时候,软件检测到了按键松开,那我能否在检测到松开的时候,再进行一次列扫描呢?

答案是可以的,经过一番调试,已经能够正常识别了。

(这里因为行没有接上拉电阻,我只能用默认这个H的信号为低电平,有按键按下时是高电平)

注意增加的两个函数

//检测到按键释放后,扫描一次行。
//P1(L信号)输出高,P0(H信号) 改为输入,读到某些位高电平表示有按键被按下,如果是0则表示按键都松开
//col : 0-5 分别表示L1 - L6
uint8_t matrix_keys_col_scan(uint8_t col)

//识别是哪个按键
//col : 0-5 分别表示L1 - L6
void matrix_keys_scan_col(uint8_t col,uint8_t dat)

#if 1   //2023-02-09  增加



//检测到按键释放后,扫描一次行。
//P1(L信号)输出高,P0(H信号) 改为输入,读到某些位高电平表示有按键被按下,如果是0则表示按键都松开
//col : 0-5 分别表示L1 - L6
uint8_t matrix_keys_col_scan(uint8_t col)
{
	uint8_t outcfg_dat[2]={0xff,0};  //P0改为输入,P1改为输出,并且输出高
	uint8_t key_row_dat;
	uint8_t outdat = 0;
	uint8_t ret;

	//P0改输入之前,先输出0,释放一下电平
	nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0);
	//配置
	nca9555_write_2config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,outcfg_dat);
//	nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0x0);  //设置输出,释放一下电平
//	nca9555_write_config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0xff);  //设置输出,释放一下电平
	
	//P1 输出1
	outdat = 1<< col;
	nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,1, outdat); //P1(L信号)端口输出0
	
	//读P0(H信号)端口,没有按键时,应该是0,有按键时不是0
	if(nca9555_read_inport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0,&key_row_dat) == 0)  //表示读取成功
	{
		if((key_row_dat & 0x3f) != 0)   //只判断低6位,不相等表示有按键按下
		{
			ret = key_row_dat&0x3f;
		}
		else
		{
			ret = 0x7f;
		//	printf("ERROR: KEY_ROW_SCAN key_row_dat == 0x3f\r\n");
		}
	}
	else //iic读取失败
	{
		printf("ERROR: KEY_ROW_SCAN nca9555_read_inport\r\n");
		ret = 0xff;
	}
	
	//配置,默认是P0(H信号)输出,P1(L信号) 改为输入
	outcfg_dat[0]=0;   
	outcfg_dat[1]=0xff;
	nca9555_write_2config(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,outcfg_dat);
	
	return ret;
}


//识别是哪个按键
//col : 0-5 分别表示L1 - L6
void matrix_keys_scan_col(uint8_t col,uint8_t dat)
{	
	uint8_t index,j;
	if(!dat || (dat >= 0x3f))
		return;
	
	for(j=0;j<ROW_NUM;j++)  //每一行扫描一次
	{
		index = 6*j+col;
		if(((dat>>j)&(1))) //高电平表示按下,低表示松开
		{
			if(!g_btns_info.value[index])
			{	
			//	g_btns_info.pressCnt[index]++;
			//	if(g_btns_info.pressCnt[index] == 2)//检测到不止1次
				{   //条件限制上报一次
					g_btns_info.value[index] = 1;
				//	g_btns_info.reportEn[index] = 1;  //按下上报
					send_btn_change_to_cpu(index+1,1); //发送按键按下/松开
					printf("@#@#btn:%d press\r\n",index+1);
				//	release_report = 1;   //记录需要释放标志
				}
			}
		}
		else if(g_btns_info.value[index]) //之前的状态是按下
		{								
			g_btns_info.value[index] = 0;
		//	g_btns_info.reportEn[index] = 2;   //松开上报
			send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
			printf("@@@btn:%d release\r\n",index+1);
			g_btns_info.pressCnt[index] = 0;			
		}
	}	
}



#endif




							

/***
 *函数名:KEY_SCAN
 *功  能:6*6按键扫描
 *返回值:1~36,对应36个按键,0表示没有检测到
 */
char matrix_keys_scan(void)
{    
    uint8_t key_row_num=0;        //行扫描结果记录
    uint8_t i,j;
	uint8_t index,col_dat;   //
	static uint8_t release_report = 0;  //松开上报。
	
	key_row_num = matrix_keys_row_scan();
	if(key_row_num < 0x3f)   //读取到了一个有效的按键触发
	{
		for(i=0;i<COL_NUM;i++)  //每一列扫描一次
		{
			if(nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, key_scan_line[i])) //P0端口输出0
			{
				printf("ERROR: KEY_ROW_SCAN nca9555_write_outport i=%d\r\n",i);
				continue;  //写入失败,直接往下试试
				//	return -1;
			}
			//再次读取输入
			key_row_num = matrix_keys_row_scan();

			for(j=0;j<ROW_NUM;j++)  //每一行扫描一次
			{
				index = 6*i+j;
				if(!((key_row_num>>j)&(1))) //按下
				{
					if(g_btns_info.pressCnt[index] < 2)
					{	
						g_btns_info.pressCnt[index]++;
						if(g_btns_info.pressCnt[index] == 2)//检测到不止1次
						{   //条件限制上报一次
							g_btns_info.value[index] = 1;
						//	g_btns_info.reportEn[index] = 1;  //按下上报
							send_btn_change_to_cpu(index+1,1); //发送按键按下/松开
							printf("----btn:%d press\r\n",index+1);
							release_report = 1;   //记录需要释放标志
						}
					}
				}
				else //松开
				{
					if(g_btns_info.value[index]) //之前的状态是按下
					{
						#if 1
						col_dat = matrix_keys_col_scan(j);
				//		printf("j = %d dat = %#x,index = %d\r\n",j,col_dat,index);
						if(col_dat >= 0x3f)
						{						
							g_btns_info.value[index] = 0;
						//	g_btns_info.reportEn[index] = 2;   //松开上报
							send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
							printf("++++btn:%d release\r\n",index+1);
							g_btns_info.pressCnt[index] = 0;
						}
						else{
							matrix_keys_scan_col(j,col_dat);
						}
						#else
						g_btns_info.value[index] = 0;
					//	g_btns_info.reportEn[index] = 2;   //松开上报
						send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
						printf("++++btn:%d release\r\n",index+1);
						g_btns_info.pressCnt[index] = 0;
						#endif
					}		
				}
			}
		}
	}
	else
	{
		if(release_report)  //需要上报释放信息。
		{		
			for(index=0;index<COL_NUM*ROW_NUM;index++)
			{
				if(g_btns_info.value[index]) //之前的状态是按下
				{
					#if 1
					j = index%6;
					col_dat = matrix_keys_col_scan(j);
				//	printf("22- j = %d dat = %#x,index = %d\r\n",j,col_dat,index);
					if(col_dat >= 0x3f)
					{						
						g_btns_info.value[index] = 0;
					//	g_btns_info.reportEn[index] = 2;   //松开上报
						send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
						printf("####btn:%d release\r\n",index+1);
						g_btns_info.pressCnt[index] = 0;
					}
					#else
				
					g_btns_info.value[index] = 0;
				//	g_btns_info.reportEn[index] = 2;   //松开上报
					send_btn_change_to_cpu(index+1,0); //发送按键按下/松开
					printf("#####btn:%d release\r\n",index+1);
					g_btns_info.pressCnt[index] = 0;
					#endif
				}
				
			}
		//	btn_start_scan = 0;   //按键不再扫描
			release_report = 0;
		}
	}

	nca9555_write_outport(NCA9555_IIC_CONTROLER,KEYS_IIC_ADDR,0, 0);	
	
	return 0;
}

以为这是一个死结,但是只要能想到办法,还是可以解决的。

两个键组合已经没有问题了,但是这个软件仍然有bug,三个键组合的时候,还是有些不能识别的情况,如同在一个列上两个按下,第三个与其中一个同行,这样无法识别第三个按键的按下和松开,好在项目没有这个需求,先这样吧。

感谢大家多来批评指正。谢谢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/333718.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

米尔基于ARM嵌入式核心板的电池管理系统(BMS)

BMS全称是Battery Management System&#xff0c;电池管理系统。它是配合监控储能电池状态的设备&#xff0c;主要就是为了智能化管理及维护各个电池单元&#xff0c;防止电池出现过充电和过放电&#xff0c;延长电池的使用寿命&#xff0c;监控电池的状态。 图片摘自网络 电池…

【C++入门】命名空间,输出输入,缺省参数,函数重载

文章目录命名空间C输入与输出缺省参数函数重载命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标 识符的名称进行本地化&#xff0…

电子技术——共源共栅放大器

电子技术——共源共栅放大器 之前我们提到过&#xff0c;提高基础增益单元&#xff08;共源放大器&#xff09;的一种方法是提高其 ror_oro​ 的阻值&#xff0c;之后我们学过共栅放大器作为电流缓冲器可以做到这一点&#xff0c;自然地我们就得到了终极解决方案&#xff0c;也…

Fluid-数据缓存亲和性调度原理解析

前言在Fluid中&#xff0c;Dataset资源对象中所定义的远程文件是可被调度的&#xff0c;这意味着你能够像管理你的Pod一样管理远程文件缓存在Kubernetes集群上的存放位置。另外&#xff0c;Fluid同样支持对于应用的数据缓存亲和性调度&#xff0c;这种调度方式将应用(e.g. 数据…

iOS 导航条isTranslucent几个注意点(iOS11及iOS13的变化)

文章主要针对11及13之后的导航变化进行总结&#xff0c;主要是设置透明度时对转场&#xff0c;包括标题&#xff0c;背景透明&#xff0c;图片&#xff0c;颜色等设置的影响。 每一个iOS版本的发布苹果最不稳写的可能就数这个导航条了吧&#xff0c;改了又改。 因此isTranslu…

Prometheus监控Java-JMX

一、什么是 JMX Exporter ? JMX Exporter 利用 Java 的 JMX 机制来读取 JVM 运行时的一些监控数据&#xff0c;然后将其转换为 Prometheus 所认知的 metrics 格式&#xff0c;以便让 Prometheus 对其进行监控采集。 那么&#xff0c;JMX 又是什么呢&#xff1f;它的全称是&a…

【Redis场景4】单机环境下秒杀问题

单机环境下的秒杀问题 秒杀下单功能及并发测试 完整代码GitHub&#xff1a;https://github.com/xbhog/hm-dianping/tree/20230130-xbhog-redisSpike 秒杀条件分析&#xff1a; 秒杀是否开始或结束&#xff0c;如果尚未开始或已经结束则无法下单库存是否充足&#xff0c;不足…

【体验测评】ChatGDP

前言 今天在去打针之前测试了下比较火的ChatGPT,总得来说还是比较好用的&#xff0c;尤其是跟浏览器搭配可以当摘要看&#xff0c;然后再进行细化查阅。 ​针对可以写论文跟交作业&#xff0c;我觉得查重率这一关比较麻烦&#xff0c;不现实&#xff0c;尤其是参与人增多的时…

php宝塔搭建部署实战易优养殖基地网站源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套php开发的易优养殖基地网站源码&#xff0c;感兴趣的朋友可以自行下载学习。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&#xff0c;宝…

选择游戏开发工具的原则

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。昨天为了给我的精致1010游戏方便的增加更多关卡&#xff0c;我用 Unity 做了个关卡编辑器&a…

pycharm的terminal与Project interpreter 配置环境不一致的问题

考虑自己的项目名中是否出现了中文&#xff0c;我是因为这个原因导致Terminal 前面出现了PS&#xff0c;用第2条解决切换终端环境后还是安装包不一致。终端出现PS&#xff0c;考虑在settings中搜索找到Terminal&#xff0c;修改其Shell path为cmd.exe&#xff0c;关闭重新打开T…

SpringCloud保姆级搭建教程三---Feign

1、第一点就是要明白服务与服务之间在怎么样的情况下&#xff0c;如何使用feign答&#xff1a;服务A要调用服务B的某个controller方法的时候&#xff0c;服务A就需要使用feign ,和服务B是没关系的所以&#xff0c;首先&#xff0c;在服务A中添加feign的依赖&#xff0c;我这里就…

nodejs基于vue高校图书馆座位预约系统

目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 2.1 使用工具简介 4 2.2 环境配置 4 2.3 B/S结构简介 4 2.4 MySQL数据库 5 2.5 框架介绍 5 3 系统分析 63.1系统可行性分析 6 3.1.1经济可行性 6 3.1.2技术可行…

软件测试电商项目实战(写进简历没问题)

前言 说实话&#xff0c;在找项目的过程中&#xff0c;我下载过&#xff08;甚至付费下载过&#xff09;N多个项目、联系过很多项目的作者&#xff0c;但是绝大部分项目&#xff0c;在我看来&#xff0c;并不适合你拿来练习&#xff0c;它们或多或少都存在着“问题”&#xff…

【i2c协议介绍】

文章目录协议简单介绍五种速度模式master/slave和transmitter/receiver关系第一种情况&#xff1a;master作为transmitter&#xff0c;slave作为receiver第二种情况&#xff1a;当master作为receiver&#xff0c;slave作为transmitteri2c基本信号start产生stop信号数据传输有效…

OpenAI ChatGPT 注册使用全攻略,以及常见问题解决办法

前言 这个时代&#xff0c;利用好 AI 完成自己的工作&#xff0c;放大自己的效率&#xff0c;已是一种必不可少的技能。 文章目录前言一、注册和登录二、常见问题和解决办法三、参考链接一、注册和登录 1&#xff09;注册网址&#xff1a;https://chat.openai.com/auth/login …

8.数据库编程

梳理 名词解释 简答题 1.游标的使用步骤 ① 声明游标。 用DECLARE语句为一条SELECT语句定义游标 EXEC SQL DECLARE<游标名> CURSOR FOR <SELECT语句>;使用T-SQL语句生成一个结果集&#xff0c;并且定义游标的特征&#xff0c;如游标中的记录是否可以修改。 定…

《趣学算法》读书笔记

内容摘要 主要介绍我对本书的一些自我感觉比较亮点地方的总结。 第一章 算法 算法有两条线索&#xff0c;数据结构、算法策略。 算法特性 时间复杂度 常见算法时间复杂度 时间复杂度的渐进上界 渐进精确界 用渐进上界和渐进下界逼近&#xff0c; 空间复杂度 递归 递归包…

浅谈监控易运维系统在金融信创国产化中的使用

自2019年&#xff0c;国家明确信创产业将成为拉动经济发展的重要途径和崭新动能以来&#xff0c;全行业进入一个高速发展新阶段。此前倡导的“28”安全可控体系&#xff0c;其中在8大基础行业中,金融行业信创产品推广成为重中之重。金融行业信创&#xff0c;是为解决行业本质安…

ENVE5.3安装与汉化(一次性安装成功附安装包)

目录 1.安装包下载 2. 软件安装 3. ENVI5安装目录说明 1.安装包下载 链接&#xff1a;https://pan.baidu.com/s/1dp2ucQa3DMHLYpw239-_vA?pwd6944 提取码&#xff1a;6944 2. 软件安装 安装前注意事项&#xff1a; 安装全程断网&#xff1b;下载、解压和安装都应该在英文…