TSM12M(TSM16C)驱动程序及注意事项


完全个人调试过来,后移植过复旦微MCU(FM33G026)也完全可行,全篇纯手打
开的这个专栏会一直记录自己用过的驱动,有触摸芯片,RFID芯片,语音芯片,显示屏驱动,ADC,各种通讯模块等等,感兴趣的可以一起交流学习

源码查询该文章
专栏地址

一、简介

  TSM12是一种12通道的电容式触摸传感器芯片,采用I2C通信协议。这里建议使用GPIO模拟I2C,即软件I2C,因为很多MCU的硬件I2C不太稳定,调试时问题较多,而且管脚受限制,虽然硬件I2C的速度会更快。(TSM16基本兼容)

二、硬件连接

引脚说明
EN片选信号
INT中断信号
SDA数据信号
SCL时钟信号

TSM12硬件连接

 tips

  • RST引脚拉高复位,一般用不到(可以软件复位)因此可直接接地,节省引脚。
  • ID_SEL接地,所以地址是0xD0,接电源则是0xF0。
  • 在CSX引脚并一个小电容到地可调节灵敏度,越小越灵敏。不要也行。
  • P_CDEG(2:0) ,如上图为110,仅仅只是控制CS1的灵敏度

三、驱动层

 1、配置GPIO

在头文件中引脚宏定义(程序中有些繁杂的宏定义这里不列出,看懂即可,像speed等都进行了宏定义,延时函数用的正点原子的延时函数)

/* 片选 */
#define TSM12_EN_PORT			GPIOA
#define TSM12_EN_PIN			GPIO_PIN_8
/* 中断 */
#define TSM12_INT_PORT			GPIOB
#define TSM12_INT_PIN			GPIO_PIN_15
/* 数据 */
#define TSM12_SDA_PORT			GPIOB
#define TSM12_SDA_PIN			GPIO_PIN_7
/* 时钟 */
#define TSM12_SCL_PORT			GPIOB
#define TSM12_SCL_PIN			GPIO_PIN_6

使用带参宏快速配置引脚,可以减少代码量,或者创建一个配置函数同理

/* 带参宏的方式 */
static GPIO_InitTypeDef GPIO_InitStructure;
#define  IO_CFG(GPIOx,PINx,MODE,PULL,SPEED)      (GPIO_InitStructure.Pin = PINx,\
												  GPIO_InitStructure.Mode = MODE,\
											      GPIO_InitStructure.Pull = PULL,\
												  GPIO_InitStructure.Speed = SPEED,\
											      HAL_GPIO_Init(GPIOx,&GPIO_InitStructure))
/* 配置函数的方式 */				
void IO_config(GPIOx_Type* GPIOx, uint32_t pin,uint32_t mode,uint32_t pull,uint32_t speed)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_InitStructure.Pin = pin;
	GPIO_InitStructure.Mode = mode;
    GPIO_InitStructure.Pull = pull;
    GPIO_InitStructure.Speed = speed;
    HAL_GPIO_Init(GPIOx,&GPIO_InitStructure);
}					           

配置引脚(后面都以带参宏的方式配置为例)

/* 片选,低电平有效 */	
#define TSM12_EN_OUT_PP()               (IO_CFG(TSM12_EN_PORT,TSM12_EN_PIN,GPIO_MODE_OUTPUT_PP,GPIO_PULLUP,GPIO_SPEED_VH))
#define TSM12_EN_OUT_1()                (TSM12_EN_OUT_PP(),HAL_GPIO_WritePin(TSM12_EN_PORT,TSM12_EN_PIN,GPIO_PIN_SET))
#define TSM12_EN_OUT_0()				(TSM12_EN_OUT_PP(),HAL_GPIO_WritePin(TSM12_EN_PORT,TSM12_EN_PIN,GPIO_PIN_RESET))
/* 中断,上拉输入 */	
#define TSM12_INT_IPU()                 (IO_CFG(TSM12_INT_PORT,TSM12_INT_PIN,GPIO_MODE_OUTPUT_PP,GPIO_PULLUP,GPIO_SPEED_VH))
#define TSM12_INT_READIN()          	(HAL_GPIO_ReadPin(TSM12_INT_PORT,TSM12_INT_PIN))
#define TSM12_INT_EXTI_FALLING_EN()     (IO_CFG(TSM12_INT_PORT,TSM12_INT_PIN,GPIO_MODE_IT_FALLING,GPIO_PULLUP,GPIO_SPEED_VH),\
										HAL_NVIC_SetPriority(EXTI4_15_IRQn,2,0),HAL_NVIC_EnableIRQ(EXTI4_15_IRQn))
/* SCL */	
#define TSM12_SCL_OUT_PP()              (IO_CFG(TSM12_SCL_PORT,TSM12_SCL_PIN,GPIO_MODE_OUTPUT_PP,GPIO_PULLUP,GPIO_SPEED_VH))
#define TSM12_SCL_OUT_1()               (TSM12_SCL_OUT_PP(),HAL_GPIO_WritePin(TSM12_SCL_PORT,TSM12_SCL_PIN,GPIO_PIN_SET))
#define TSM12_SCL_OUT_0()				(TSM12_SCL_OUT_PP(),HAL_GPIO_WritePin(TSM12_SCL_PORT,TSM12_SCL_PIN,GPIO_PIN_RESET)) 
/* SDA 因为还要读取中断时发送的通道值,因此还要配置输入*/	
#define TSM12_SDA_OUT_PP()              (IO_CFG(TSM12_SDA_PORT,TSM12_SDA_PIN,GPIO_MODE_OUTPUT_PP,GPIO_PULLUP,GPIO_SPEED_VH))
#define TSM12_SDA_OUT_1()               (TSM12_SDA_OUT_PP(),HAL_GPIO_WritePin(TSM12_SDA_PORT,TSM12_SDA_PIN,GPIO_PIN_SET))
#define TSM12_SDA_OUT_0()				(TSM12_SDA_OUT_PP(),HAL_GPIO_WritePin(TSM12_SDA_PORT,TSM12_SDA_PIN,GPIO_PIN_RESET)) 
#define TSM12_SDA_IPU()                 (IO_CFG(TSM12_SDA_PORT,TSM12_SDA_PIN,GPIO_MODE_OUTPUT_PP,GPIO_PULLUP,GPIO_SPEED_VH))
#define TSM12_SDA_READIN()          	(HAL_GPIO_ReadPin(TSM12_SDA_PORT,TSM12_SDA_PIN))

 2、启动、停止、应答信号

  数据有效性:SCL为高时数据有效

数据有效性

  启动与停止信号

启动与停止信号

 tips

  • 处理数据时注意先EN片选(我注释掉是因为在其他调用以下函数的函数中先片选了,看自己习惯)
/********************************************************
 * @brief TSM12_I2C_Start()
 *   发送TSM12起始信号
 * @param
 *     @arg:
 * @return
 *   none
 * @note 硬件总在SCL高电平检测SDA状态,所以先操作SDA
 ******************************************************/
static void TSM12_I2C_Start(){
	TSM12_SCL_OUT_PP();
	TSM12_SDA_OUT_PP();
//	TSM12_EN_OUT_0();    //片选
	
	TSM12_SDA_OUT_1();   //SDA先拉高
	TSM12_SCL_OUT_1();
	delay_us(5);
	TSM12_SDA_OUT_0();  
	delay_us(5);
	TSM12_SCL_OUT_0();
	delay_us(5);
}

/***********************************************
 * @brief TSM12_I2C_Stop()
 *   发送TSM12停止信号
 * @param
 *     @arg:
 * @return
 *   none
 * @note 
 ***********************************************/
static void TSM12_I2C_Stop(){
	TSM12_SCL_OUT_PP();
	TSM12_SDA_OUT_PP();
//	TSM12_EN_OUT_0();    //片选
	
	TSM12_SDA_OUT_0();   //SDA先拉低
	TSM12_SCL_OUT_1();
	   
	delay_us(5);
	TSM12_SDA_OUT_1();  
	delay_us(5);
//	TSM12_EN_OUT_1();    //结束TSM12发送数据
}

  应答信号

应答信号

/***************************************************
 * @brief TSM12_I2C_MasterSendAck(BOOL isAck)
 *   主机发送TSM12应答或未应答信号
 * @param
 *     @arg:BOOL isAck:是否应答
 *  M_ACK           0
 *  M_NACK          1
 * @return
 *   none
 * @note 接收方成功接收数据写0,反之写1
 **************************************************/

static void TSM12_I2C_MasterSendAck(BOOL isAck){
	TSM12_SCL_OUT_PP();
	TSM12_SDA_OUT_PP();	
	
	if(isAck == M_ACK)  //先发送应答信号
	{
		TSM12_SDA_OUT_0();
	}else{
		TSM12_SDA_OUT_1();
	}
	TSM12_SCL_OUT_1();
	delay_us(5);
	TSM12_SCL_OUT_0();
}

/**************************************************
 * @brief TSM12_I2C_SlaveAck(void)
 *   检测从机应答信号
 * @param
 *     @arg:
 * @return BOOL 
 *  M_ACK           0
 *  M_NACK          1 
 * @note 检测从机是否应答
 *************************************************/

static BOOL TSM12_I2C_SlaveAck(void){
	TSM12_SDA_IPU();
	TSM12_SCL_OUT_PP();
	
	TSM12_SCL_OUT_1();
	delay_us(5);
	if(TSM12_SDA_READIN() == M_NACK)
	{
		TSM12_SCL_OUT_0();
		return M_NACK;
	}
	TSM12_SCL_OUT_0();
	return M_ACK;
}

 3、读写函数

7位从机地址跟一个读写方向位
数据位,最后一位为读写方向放在地址后

  写入一字节数据

 tips

  • 时序拉高至少4.7us。
  • 数据位,最后一位为读写方向放在地址后(参考上图)。
/**********************************************************************
 * @brief TSM12_I2C_WriteByte(u8 u8_data)
 *   TSM12写入8位数据
 * @param
 *     @arg:u8 u8_data
 * @return
 *   none
 * @note R/W  (O是Write,1是Read)高位先行,放在发送地址和读写位之后
 **********************************************************************/

static void TSM12_I2C_WriteByte(u8 u8_data){
	u8 i;
	TSM12_SDA_OUT_PP();			//配置SDA推挽输出
	TSM12_SCL_OUT_PP();			//配置SCL推挽输出
	for(i=8;i>0;i--)
	{
		if((u8_data & 0x80) == 0x80)
		{
			TSM12_SDA_OUT_1();      
		}else{
			TSM12_SDA_OUT_0();
		}
		u8_data <<= 1;
		TSM12_SCL_OUT_1();
		delay_us(5);				//至少4.7us
		TSM12_SCL_OUT_0();
		delay_us(5);
	}
}

  读取一字节数据

 tips

  • 注意拉高顺序,SCL高电平SDA数据才有效,因此读取的时候先拉高SCL较为稳妥。
/*****************************************************************
 * @brief TSM12_I2C_ReadByte(void)
 *   TSM12读取一个8位数据
 * @param
 *     @arg:
 * @return
 *   u8_data,返回一个8位数据
 * @note R/W  (O是Write,1是Read)高位先行,放在发送地址和读写位之后
 *****************************************************************/

static u8 TSM12_I2C_ReadByte(void){
	u8 i;
	u8 u8_data = 0x00;
	TSM12_SDA_IPU();         //读数据主机上拉输入
	TSM12_SCL_OUT_PP();
	
	for(i=8;i>0;i--)
	{
		TSM12_SCL_OUT_1();     //SCL高电平数据才有效
		delay_us(5);
		u8_data <<= 1;	         //先左移,如果运算完左移最终会多左移一次
		if(TSM12_SDA_READIN() == M_SET)
		{
			u8_data |= 0x01;
		}	
		TSM12_SCL_OUT_0();
		delay_us(5);
	}
	return u8_data;
}

  从机地址与寄存器映射等宏定义

详细的寄存器控制位查数据手册
寄存器地址

#define TSM12_ID_SEL_Address  				0xD0   	//接GND,如果接VDD则改为0xF0

#define TSM12_Sensitivity1                  0x02    //通道1,2灵敏度
#define TSM12_Sensitivity2                  0x03
#define TSM12_Sensitivity3                  0x04
#define TSM12_Sensitivity4                  0x05
#define TSM12_Sensitivity5                  0x06
#define TSM12_Sensitivity6                  0x07
#define TSM12_CTRL1                         0x08
#define TSM12_CTRL2                         0x09
#define TSM12_Ref_rst1                      0x0A
#define TSM12_Ref_rst2                      0x0B
#define TSM12_Ch_hold1                      0x0C
#define TSM12_Ch_hold2                      0x0D
#define TSM12_Cal_hold1                     0x0E
#define TSM12_Cal_hold2                     0x0F
#define TSM12_Output1                       0x10
#define TSM12_Output2                       0x11
#define TSM12_Output3                       0x12

#define TSM12_Sens_Reset                    0xBB  	//默认灵敏度
#define TSM12_Sens_User                     0x33 	//自定义灵敏度

  向TSM12写入数据

写入操作

 tips

  • 阴影格子是主机发送从机的数据,白色格子是主机读取从机的数据
  • 数据格式:8位数据和一个应答信号组成。
  • 数据写入顺序:先发送(从机地址+读写方向),然后是寄存器地址,再写入寄存器,直到停止信号。
/****************************************************************
 * @brief TSM12_I2C_WriteData(u8 regAdd,u8 u8_data)
 *   TSM12写入数据
 * @param
 *     @arg:u8 u8_data:要写入的数据
 *     @arg:u8 regAdd:寄存器地址
 * @return BOOL
 *   
 * @note 顺序:1)第一字节写入设备地址和R/W方向(1为Read)
 *             2)第二字节写入要访问的寄存器内部地址
 *             3)接下来就是写入寄存器,并跟随从机应答信号,直到停止信号
 *************************************************************/

static BOOL	TSM12_I2C_WriteData(u8 regAdd,u8 u8_data){
	
	TSM12_I2C_Start();
	TSM12_I2C_WriteByte(TSM12_ID_SEL_Address | 0x00);  //设备地址和写方向
	if(TSM12_I2C_SlaveAck() != M_ACK)		//检测从机应答信号
	{
		return M_FALSE;
	}
	TSM12_I2C_WriteByte(regAdd);            //寄存器内部地址
	if(TSM12_I2C_SlaveAck() != M_ACK)
	{
		return M_FALSE;
	}
	TSM12_I2C_WriteByte(u8_data);          //数据
	if(TSM12_I2C_SlaveAck() != M_ACK)
	{
		return M_FALSE;
	}
	TSM12_I2C_Stop();                //停止信号
	return M_TRUE;
}

  从TSM12读取数据

普通模式读写操作  tips

  • 读数据时要先写入对应寄存器地址,然后再读取数据。
  • 读操作最后停止信号前要发送非应答信号。
  • 注意前后两次写入地址的读写方向。
/*******************************************************
 * @brief TSM12_I2C_ReadData(u8 regAdd)
 *   TSM12读取数据
 * @param
 *     @arg:u8 regAdd:寄存器地址
 * @return u8
 *   
 * @note 顺序:1)写入设备地址
 *             2)写入寄存器地址
 *             3)开始读数据,先写入读方向设备地址
 *********************************************************/

static u8 TSM12_I2C_ReadData(u8 regAdd){
	u8 u8_data;           //读取的数据
	TSM12_I2C_Start();
	TSM12_I2C_WriteByte(TSM12_ID_SEL_Address | 0x00);  //设备地址和写方向
	if(TSM12_I2C_SlaveAck() != M_ACK)
	{
		return M_FALSE;
	}
	TSM12_I2C_WriteByte(regAdd);            //寄存器内部地址
	if(TSM12_I2C_SlaveAck() != M_ACK)
	{
		return M_FALSE;
	}
	TSM12_I2C_Stop();
	/*  */
	TSM12_I2C_Start();
	TSM12_I2C_WriteByte(TSM12_ID_SEL_Address | 0x01);  //设备地址和读方向
	if(TSM12_I2C_SlaveAck() != M_ACK)
	{
		return M_FALSE;
	}
	u8_data = TSM12_I2C_ReadByte();
	TSM12_I2C_MasterSendAck(M_NACK);              //停止信号前发送非应答信号
	TSM12_I2C_Stop();
	return u8_data;
}

4、配置中断

 配置引脚中断

static void TSM12_INT_IRQ_init(void){
	TSM12_SDA_OUT_1();
	TSM12_SCL_OUT_1();
	TSM12_INT_IRQ_IPU();
	TSM12_INT_IRQ_EXTI_FALLING_EN();	
}

 中断流程

TSM12中断流程

  • 结构体与变量声明(注意使用volatile)
/* 触摸按键状态结构体 */
typedef struct{
	vBOOL TouchKey_FLAG_IsPress;       //按键是否按下中断标志 volatile 
}TouchKeyStatus_st;             	 

static volatile TouchKeyStatus_st touchKeyStatusSt ={0,};  
  • 中断服务函数:如果触发中断,按下标志置1
/*******************************************
 * @brief TSM12_TouchKey_ISR()
 *   TSM12触摸按键中断服务函数
 * @param
 *     @arg:
 * @return
 * @note __STATIC_INLINE ; M_YES: 1 按下  
 *******************************************/

__STATIC_INLINE void TSM12_TouchKey_ISR(){
	if(TSM12_INT_IRQ_READIN() == M_RESET)			//中断低电平有效
	{
		if(touchKeyStatusStruct.TouchKey_FLAG_IsPress == 0)
		{
			touchKeyStatusStruct.TouchKey_FLAG_IsPress = M_YES;
		}
	}
}
  • 中断回调函数
/********************************************************
 * @brief HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
 *   GPIO中断的回调函数
 * @param
 *     @arg:
 * @return
 * @note gpio库文件中弱定义
 *********************************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
		switch(GPIO_Pin)
		{
			case TSM12_INT_IRQ_PIN:                      //PB15
				TSM12_TouchKey_ISR();
				break;
			default:
    			break;		
		}
}

5、配置寄存器函数封装

 上电初始化

  • 初始化流程图(有些顺序打乱没影响)

上电配置流程

  • 初始化前等待函数(TSM12初始化时不能有按键动作,不然会一段时间失灵)

static void TSM12_WaitInit(void){
	u16 timeOut = 300;
	while(TSM12_ReadTouchKeyCh() != 0)      //触摸键值不为0
	{
		 delay_ms(10);                	    //300*10ms
		 timeOut--;
		 if(timeOut == 0)
		 {break;}
	}
}
  • TSM12初始化函数
    打开休眠功能,一段时间未按键会自动进入休眠模式,功耗在4-8uA
void TSM12_TouchKey_Init(void){
	
	TSM12_WaitInit();                                             //等待按键释放
	delay_ms(100);  
	TSM12_EN_OUT_0();                                        //片选
	TSM12_I2C_WriteData(TSM12_CTRL2,0X0F);                    		 //软件复位和睡眠使能
//	TSM12_I2C_WriteData(TSM12_CTRL2,0X07);                    		 //失能软件复位和使能睡眠
	TSM12_I2C_WriteData(TSM12_Sensitivity1,TSM12_Sens_User);       //通道1,2灵敏度
	TSM12_I2C_WriteData(TSM12_Sensitivity2,TSM12_Sens_User);       //通道3,4灵敏度
	TSM12_I2C_WriteData(TSM12_Sensitivity3,TSM12_Sens_User);       //通道5,6灵敏度
	TSM12_I2C_WriteData(TSM12_Sensitivity4,TSM12_Sens_User);       //通道7,8灵敏度
	TSM12_I2C_WriteData(TSM12_Sensitivity5,TSM12_Sens_User);       //通道9,10灵敏度
	TSM12_I2C_WriteData(TSM12_Sensitivity6,TSM12_Sens_User);       //通道11,12灵敏度
	
	TSM12_I2C_WriteData(TSM12_CTRL2,0X03);                    	 //软件复位和睡眠失能
//	TSM12_I2C_WriteData(TSM12_CTRL1,0X3A);                //自动切换快慢模式/10s/高输出中断/响应时间4
	TSM12_I2C_WriteData(TSM12_Ch_hold1,0x00);            //打开1-8通道
	TSM12_I2C_WriteData(TSM12_Ch_hold2,0x00);            //打开9-12通道
 	TSM12_I2C_WriteData(TSM12_Ref_rst1,0xFF);            //通道1-8参考复位
 	TSM12_I2C_WriteData(TSM12_Ref_rst2,0x0F);            //通道9-12参考复位
	TSM12_I2C_WriteData(TSM12_Ref_rst1,0x00);            //失能通道1-8参考复位
    TSM12_I2C_WriteData(TSM12_Ref_rst2,0x00);            //失能通道9-12参考复位
	
//	TSM12_I2C_WriteData(TSM12_Cal_hold1,0x00);            //使能1-8通道感应矫正功能
//	TSM12_I2C_WriteData(TSM12_Cal_hold2,0x00);             //使能9-12通道感应矫正功能
	TSM12_I2C_WriteData(TSM12_CTRL2,0X07);                  //失能软件复位和使能睡眠
 
	TSM12_EN_OUT_1();                                     //结束TSM12发送数据
	TSM12_INT_IRQ_init();
}

 其他函数

以下函数建议连着电流表测试(不同应用程序不一样,仅给参考),要注意配置顺序,或者直接在上面函数使能就行

  • 进入休眠函数
void TSM12_EnterSleep(void){
	TSM12_EN_OUT_0(); 
	delay_us(200);
	TSM12_I2C_WriteData(TSM12_Ref_rst1,0x00);          //失能通道1-8参考复位
	TSM12_I2C_WriteData(TSM12_Ref_rst2,0x00);          //失能通道9-12参考复位
	TSM12_I2C_WriteData(TSM12_Ch_hold1,0x00);          //打开1-8通道
	TSM12_I2C_WriteData(TSM12_Ch_hold2,0x00);          //打开9-12通道
	TSM12_I2C_WriteData(TSM12_CTRL2,0x07);     		   //软件复位不使能,睡眠使能
	delay_us(200);
	TSM12_EN_OUT_1();
	TSM12_INT_IRQ_init();             //使能中断
}
  • 退出休眠函数
void TSM12_ExitSleep(void){
	TSM12_EN_OUT_0(); 
	delay_us(200);
	TSM12_I2C_WriteData(TSM12_CTRL2,0x03);     		 //睡眠失能
	delay_us(200);
	TSM12_EN_OUT_1();
	TSM12_INT_IRQ_init();           		 		 //使能中断
}
  • 打开或关闭按键通道函数
void TSM12_ChannelHold(BOOL isEnable){
	if(isEnable)
	{
		TSM12_I2C_WriteData(TSM12_Ch_hold1, 0x00);     //打开1~8所有通道
    	TSM12_I2C_WriteData(TSM12_Ch_hold2, 0x00);     //打开9~12所有通道
	}else{
		TSM12_I2C_WriteData(TSM12_Ch_hold1, 0xFF);     //关闭1~8所有通道
   		TSM12_I2C_WriteData(TSM12_Ch_hold2, 0x0F);     //关闭9~12所有通道
	}
}

四、应用层

应用层根据自己的产品功能需求,以下函数供参考

 读取按键值函数

/****************************************
 * @brief TSM12_ReadTouchKeyCh(void)
 *   TSM12读取触摸按键值
 * @param
 * @return u8 按键值
 *   
 * @note 
 *****************************************/

static u8 TSM12_ReadTouchKeyCh(void){
	u8 touchKeyValue = 0;								//触摸键值
	u8 pBuffer[3];										//存储3通道8位键值数组
	u8 *p = pBuffer;
	
	TSM12_EN_OUT_0();
	*p = TSM12_I2C_ReadData(TSM12_Output1);             //读通道1-4的u8_data
	*(p+1) = TSM12_I2C_ReadData(TSM12_Output2);			//读通道5-8的u8_data
	*(p+2) = TSM12_I2C_ReadData(TSM12_Output3);			//读通道9-12的u8_data
	TSM12_EN_OUT_1();
	
	if(0 == touchKeyValue)
	{
		switch(*p)             //OUTPUT1
		{
			case 0x03:
				touchKeyValue = M_TOUCHKEY_CH_01;
				break;
			case 0x0C:
				touchKeyValue = M_TOUCHKEY_CH_02;
				break;
			case 0x30:
				touchKeyValue = M_TOUCHKEY_CH_03;
				break;
			case 0xC0:
				touchKeyValue = M_TOUCHKEY_CH_04;
				break;
			default:
				touchKeyValue = 0;
				break;
		}
	}
	if(0 == touchKeyValue)
	{
		switch(*(p+1))          //OUTPUT2
		{
			case 0x03:
				touchKeyValue = M_TOUCHKEY_CH_05;
				break;
			case 0x0C:
				touchKeyValue = M_TOUCHKEY_CH_06;
				break;
			case 0x30:
				touchKeyValue = M_TOUCHKEY_CH_07;
				break;
			case 0xC0:
				touchKeyValue = M_TOUCHKEY_CH_08;
				break;
			default:
				touchKeyValue = 0;
				break;
		}
	}
	if(0 == touchKeyValue)
	{
		switch(*(p+2))          //OUTPUT3
		{
			case 0x03:
				touchKeyValue = M_TOUCHKEY_CH_09;
				break;
			case 0x0C:
				touchKeyValue = M_TOUCHKEY_CH_10;
				break;
			case 0x30:
				touchKeyValue = M_TOUCHKEY_CH_11;
				break;
			case 0xC0:
				touchKeyValue = M_TOUCHKEY_CH_12;
				break;
			default:
				touchKeyValue = 0;
				break;
		}
	}
	return touchKeyValue;
}

 读取键值优化函数

读取键值优化函数

/*************************************
 * @brief TSM12_TouchKey_Scan(void)
 *   触摸按键扫描函数
 * @param
 * @return
 *   u8 keyValue:按下的按键值
 * @note 消抖,扫描键盘有无按键
 **************************************/

u8 TSM12_TouchKey_Scan(void){
	#define KEY_JITTER_TIMES     2   //按键抖动次数
	u8 keyValue = 0;        				 //读取的按键值
	static u8 nullKeyCounts = 0;     //无效按键次数
	static u8 prevKeyValue = 0;      //前一次有效键值
	u8 returnKeyValue = 0;           //返回的键值
	
		if(touchKeyStatusSt.TouchKey_FLAG_IsPress)       //先读取键值,BOOL
		{
			touchKeyStatusSt.TouchKey_FLAG_IsPress = 0;    //初始化按下标志位
			keyValue = 	TSM12_ReadTouchKeyCh();
		}
		if(keyValue == 0)      				//无效键值
		{
			returnKeyValue = 0;
			if(nullKeyCounts <= KEY_JITTER_TIMES)
			{
				nullKeyCounts++;
			}
		}
		else if(keyValue != prevKeyValue)  					//有效键值且不同于上次按键
		{
			prevKeyValue = keyValue;   
			returnKeyValue = keyValue;
			nullKeyCounts = 0;      									//重置抖动计数
		}
		else if(nullKeyCounts > KEY_JITTER_TIMES)   //有效键值等于上次按键且超过抖动次数
		{
			prevKeyValue = keyValue;   
			returnKeyValue = keyValue;
			nullKeyCounts = 0;
		}
		else{																			  //有效键值等于上次按键但未超过抖动次数
			returnKeyValue = 0;
			if(nullKeyCounts <= KEY_JITTER_TIMES)
			{
				nullKeyCounts++;
			}
		}
					
		return returnKeyValue;
	#undef KEY_JITTER_TIMES
}

 其他应用函数

  • 16
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Diode丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值