如何快速调通华仕飞触摸按键驱动

针对智能家居、小家电、门禁考勤等触摸按键领域,深圳华仕飞科技推出一系列定制化的软硬件产品,产品不仅仅包括触摸按键领域,也包括一些小家电控制、特别是带触摸按键功能和强电开关控制领域的定制化软硬件产品。最近,华仕飞正在免费派送一款针对门禁考勤系统的12个数字按键的触摸按键HTK100。现在,针对该产品及驱动软件调试方法进行一些简要的讲解。

华仕飞的触摸按键采用的是专业的触摸驱动方案,具有高效的触摸按键算法处理和抗干扰算法处理,是行业内具有良好性价比的产品。HTK100硬件接口可以同时兼容I2C、UART、IR三种通讯接口,支持中断输出,但是,在软件上暂时只能任选其中一种通讯协议,也就是说,只能烧录其中任意一种协议的软件。市面上免费派送的的HTK100支持的是I2C协议。由于I2C协议的很多优点,可以满足绝大部分用户的需求。当然,如果用户需要其它的协议,也可以通过访问官网,联系他们烧录特殊功能的软件,或定制化软件。

针对HTK100,官方网站现在已经推出了基于I2C和UART通讯协议的驱动,该驱动基于华仕飞自身所推出基于STM32的演示评估板,在官方网站和网上其他很多地方都有下载。其中,I2C采用的是GPIO口模拟I2C,程序简单易懂,可移植性强。当然,某些第三方论坛,也可以找到完全的华仕飞评估板的软件包,感兴趣的朋友可以上网找找。

现在,以HTK100的I2C协议为例,简述一下HTK100驱动调试方法。

(1)从官方免费申请或从网上买1~2块HTK100触摸按键板。HTK100采用6PIN1.26mm的接线座。早期的HTK100没有配送对应的线材,后期的才有配送。如果没有配送,用户需要自己在网上购买对应的线,或者自己手动焊接其它对应的线。

(2)接线:将HTK100接上用户自己的主板。主板需要至少有I2C总线接口。如果没有,可以通过GPIO口模拟I2C。为避免主MCU频繁读取HTK100所造成的资源浪费,应采用外部中断方式读取HTK100的按键,所以,INT接口也应接。另外,为防止出在极其特殊情况下HTK100工作不正常的情况,复位引脚RST最好也接上MCU以便可以根据需要对MCU进行复位。当然,在资源不够时,RST可以悬空,或者通过一个大的电阻(推荐100K以)进行上接。HTK100内部既有软件看门狗,也有硬件看门狗。当程序出现异常跑飞的情况时,内部是可以自动复位的。

硬件接口典型电路如下图所示:

(3)IO口配置:

对于INT脚,配置为上升沿触发模式或者上升沿和下降沿双触发模式即可。

对于RST脚,配置为输出模式即可,可以为OD模式,无须上拉或下拉电阻。如果上拉或下拉,应接一个比较大的电阻。

I2C口配置的总线时钟应为200KHz以下;如果采用的是,每字节数据采用的是MSB在前方式传输,即数据位传输顺序为从高位在前。

如果采用的是GPIO模拟I2C的方式,则SDA最好配置为OD模式,这样SDA总线就无段通过软件频繁进行输入输出切换。如果您对芯片的这一功能不太放心,或者您没有这方面的经验,也可以通过软件进行输入输出切换。

一种比较简单的通过软件自动切换的代码实现方式如下所示:

void __Set_SDA(void)

{

if(__I2C_SDA_IsInputMode())

{

           __SetI2C_SDA_OutputMode();

}

SET_SDA;

}

void __Clr_SDA(void)

{

if(__I2C_SDA_IsInputMode())

{

           __SetI2C_SDA_OutputMode();

}

CLR_SDA;

}

这样,通过以上代码,就无需在GPIO口模拟I2C的驱动程序中频繁对SDA的输入输出方式进行切换了。

(4)I2C驱动程序的编写。由于GPIO口模拟I2C对硬件的依赖性比较低,软件简单可控,所以笔者推荐在条件许可的情况下,尽量使用GPIO口模拟I2C。以下为GPIO口模拟I2C的全部驱动程序。

void __I2C_start(void)

{

       __Set_SDA();

       __Set_SCL();

       __delay_us(5);

       __Clr_SDA();

       __delay_us(5);

       __Clr_SCL();

       __delay_us(5);

}

void __I2C_stop(void)

{

       __Clr_SDA();

       __delay_us(5);

       __Set_SCL();

       __delay_us(5);

       __Set_SDA();

}

void __I2C_get_ack(void)

{

       __Clr_SCL();

       __delay_us(2);

       __Clr_SDA();

       __delay_us(5);

       __Set_SCL();

       __delay_us(5);

       __Clr_SCL();

}

void __I2C_get_nack(void)

{

       __Clr_SCL();

       __delay_us(2);

       __Set_SDA();

       __delay_us(5);

       __Set_SCL();

       __delay_us(5);

       __Clr_SCL();

       __delay_us(2);

}

void __I2C_multi_read(BYTE *pDat,BYTE num)

{

       BYTEi;

       //receive the n-1 bytes

       for(i=0;i<num-1;i++)

       {

              *pDat= __I2C_byte_get();

              //send ack

              __I2C_get_ack();

              pDat++;

       }

       //receive the last byte

       *pDat= __I2C_byte_get();

       //send no ack

       __I2C_get_nack();

}

BYTE __I2C_byte_read(void)

{

       BYTEdat = 0;

       dat= __I2C_byte_get();

      

       __I2C_get_nack();

       __delay_us(2);

      

       returndat;

}

BYTE __I2C_byte_get(void)

{

       BYTEdat=0;

       BYTEbitcnt;

       //receive data; gpio4 is input

       for(bitcnt=0;bitcnt<8; bitcnt++)

       {

              __Clr_SCL();

              __delay_us(5);

              __Set_SCL();

              dat= dat<<1;

              if(__Get_SDA_Data())

              {

                     dat= dat+1;

              }

              __delay_us(5);

       }

       __Clr_SCL();

       __delay_us(5);

       returndat;

}

BOOL __I2C_send_byte(BYTE dat)

{

       BYTEbitcnt;

       BOOLret;

       //send data; gpio4 is output

       for(bitcnt=0;bitcnt<8; bitcnt++)

       {

              if((dat<<bitcnt)&0x80)

//            if((dat>>bitcnt)&0x01)

              {

                     __Set_SDA();

              }

              else

              {

                     __Clr_SDA();

              }

              __delay_us(2);

              __Set_SCL();

              __delay_us(5);

              __Clr_SCL();

              __delay_us(2);

       }

       __Set_SDA();

       __delay_us(2);

       __Set_SCL();

       __delay_us(5);

       if(__Get_SDA_Data())

       {

              ret= 0;

       }

       else

       {

              ret= 1;

       }

       __Clr_SCL();

       __delay_us(5);

      

       returnret;

//     return__I2C_send_ack();

}

//等待从机应答信号

//返回值:1接收应答成功

// 0 接收应答失败

BOOL __I2C_send_ack(void)

{

       UINTcnt=0;

       __Set_SDA();  //主机释放数据总线,等待从机产生应答信号

       __delay_us(5);

       __Set_SCL();

       __delay_us(5);

       //等待从机对数据总线的操作。低电平代表应答

#if 1

       while(__Get_SDA_Data())

       {

              cnt++;

              __delay_us(1);

              //这个属于软件延时,不一定准确。

              if(cnt> 5) //如果时间超时,没有应答就停止。

              {

                     __I2C_stop();

                     returnFALSE;  //没有响应的话返回1.

              }

       }

#endif    

       __Clr_SCL();

       returnTRUE; //如果有响应的话就返回1.

}

(5)HTK100驱动程序

由于HTK100主要是读取触摸按键值,故其驱动比较简单

以下为来自官方HTK100的全部驱动。由于HTK100事实上并没有手势功能,所以针对手势读取的那部分驱动事实上是无效的。

/**************************************************************************

Parameters:           

                     [OUT]:pKeyVal:最佳键值

Return:          

                     TRUE:读取成功;

                     FALSE:读取失败

Description:   

                     通过I2C读取最优触摸按键键值,即当有多个按键同时按下时,取最优键的键值

**************************************************************************/

BOOL__HTK_I2C_Read_optimal_touch_keyval(BYTE *pKeyVal)

{

       volatileint i = 0;

//     DBG_printf("\n\nI2C_start1\n");

       __I2C_start();

       __delay_us(5);

//     DBG_printf("(WRITE)DEV ADDR\n");

       if(!__I2C_send_byte((__HTK_DEVICE_ADDR<<1)|0) )         // 发送器件地址+写命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

       __delay_us(5);

//     DBG_printf("KEY_VALUE_CMD\n");

       if(!__I2C_send_byte(__HTK_TOUCH_KEY_VALUE_CMD))         //数据地址

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

       __delay_us(5);

//     DBG_printf("I2C_start2\n");

       __I2C_start();

       __delay_us(5);

//     DBG_printf("[READ]DEV ADDR\n");

       if(!__I2C_send_byte((__HTK_DEVICE_ADDR<<1)|1) )         // 发送器件地址+读命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

//     DBG_printf("READ DATA\n");

       __delay_us(100);

      

       *pKeyVal= __I2C_byte_read();

       if(*pKeyVal == 0)

       {

              i= 1;

       }

       __delay_us(5);

       __I2C_stop();

       returnTRUE;

}

/**************************************************************************

Parameters:           

                     [OUT]:pdwStatus:最佳键值

Return:          

                     TRUE:读取成功;

                     FALSE:读取失败

Description:   

                     通过I2C读取当前按键状态

                     *pdwStatus的BIT0~BIT31分别对应32个(如果按键数量不够,以实际按键数量为准)按键的状态

                     每个BIT的1表示按下,0:表示未按下

**************************************************************************/

BOOL__HTK_I2C_Read_touch_status(DWORD *pdwStatus)

{

       BYTEdat[4];

      

//     DBG_printf("\n\nI2C_start1\n");

       __I2C_start();

       __delay_us(5);

       if(!__I2C_send_byte((__HTK_DEVICE_ADDR<<1)|0) )         // 发送器件地址+读命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

       __delay_us(5);

       if(!__I2C_send_byte(__HTK_TOUCH_KEY_STATUS_CMD))        //读命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

//     DBG_printf("I2C_start2\n");

       __delay_us(5);

       __I2C_start();

       __delay_us(5);

//     DBG_printf("[READ]DEV ADDR\n");

       if(!__I2C_send_byte((__HTK_DEVICE_ADDR<<1)|1) )         // 发送器件地址+读命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

//     DBG_printf("READ DATA\n");

       __delay_us(100);

      

       __I2C_multi_read(dat,4);

      

       __I2C_stop();

       //如系统为小端模式,调用如下代码

       *pdwStatus= (((DWORD)dat[0]<<24) | ((DWORD)dat[1]<<16) |((DWORD)dat[2]<<8) | ((DWORD)dat[3]));

       //如系统为大端模式,调用如下代码

//     *pdwStatus= (((DWORD)dat[3]<<24) | ((DWORD)dat[2]<<16) |((DWORD)dat[1]<<8) | ((DWORD)dat[0]))

       returnTRUE;

}

/**************************************************************************

Parameters:           

                     [OUT]:pGesture:手势

Return:          

                     TRUE:读取成功;

                     FALSE:读取失败

Description:   

                     通过I2C读取当前的手势值

**************************************************************************/

BOOL __HTK_I2C_Read_gesture(BYTE*pGesture)

{

//     DBG_printf("\n\nI2C_start1\n");

       __I2C_start();

       __delay_us(5);

//     DBG_printf("(WRITE)DEV ADDR\n");

       if(!__I2C_send_byte((__HTK_DEVICE_ADDR<<1)|0) )         // 发送器件地址+写命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

       __delay_us(5);

//     DBG_printf("GESTURE_CMD\n");

       if(!__I2C_send_byte(__HTK_TOUCH_GESTURE_CMD))             //数据地址

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

       __delay_us(5);

//     DBG_printf("I2C_start2\n");

       __I2C_start();

       __delay_us(5);

//     DBG_printf("[READ]DEV ADDR\n");

       if(!__I2C_send_byte((__HTK_DEVICE_ADDR<<1)|1) )         // 发送器件地址+读命令

       {

              DBG_printf("FAIL\n");

              __I2C_stop();

              returnFALSE;

       }

//     DBG_printf("READ DATA\n");

       __delay_us(100);

      

       *pGesture= __I2C_byte_read();

       __delay_us(5);

       __I2C_stop();

       returnTRUE;

}

(6)驱动的挂载及系统联调

对于一般的单片机系统而言,通过中断方式读取HTK100键值及其它状态值即可。当然,考虑到中断需要一定的时间,而中断服务程序需要需要快速响应且尽快退出,可以考虑在中断服务程序中置个标志位,然后在中循环中再读取相庆的键值及其它状态值即可。程序可以参考如下代码:

/**************************************************************************

Parameters:           

                     void

Return:          

                     void

Description:   

       上升沿中断处理程序

       即当中断服务程序收到一个触摸按键的中断时,在主循环中调用该函数以读取键值

       由于中断服务程序不适合处理时间较长的工作,所以该函数不建议在中断服务程序中运行,而在主循环中运行

**************************************************************************/

void __HTK_proc(void)

{

       BYTEKeyVal = 0;

       BYTEGesture = 0;

       DWORDKeyStatus = 0;

       if(__isGetHtkIntr)

       {

//            DBG_printf("__isGetHtkIntr\n");

              if(GET_HTK_INTR)    // 识别是否为上升沿中断

              {

                     DBG_printf("Rising\n");

#if defined(IIC_KEY_CFG)

                     //读取最佳按键

                     DBG_printf("Readkey value \n");

#if 1

                     if(__HTK_I2C_Read_optimal_touch_keyval(&KeyVal))

                     {

                            DBG_printf("touchkey value:%02X\n\n", KeyVal);

                            SetKeyValLed(KeyVal);

                     }

                     else

                     {

                            SetKeyValLed(0);

                            DBG_printf("Nokey\n");

                     }

#endif

#if 0

                     DBG_printf("Readkey status \n");

                     if(__HTK_I2C_Read_touch_status(&KeyStatus))

                     {

                            DBG_printf("touchkey status:0x%08X\n", KeyStatus);

                     }

                     else

                     {

                            DBG_printf("Nokey\n");

                     }

#endif

#if 0

                     DBG_printf("Readgesture \n");

                     if(__HTK_I2C_Read_gesture(&Gesture))

                     {

                            DBG_printf("touchkey gesture:%d\n", Gesture);

                     }

                     else

                     {

                            DBG_printf("Nogesture\n");

                     }

#endif

#elif defined(UART_KEY_CFG)

                     //读取最佳按键

                     DBG_printf("Readkey value \n");

                     if(__HTK_Uart_Read_optimal_touch_keyval(&KeyVal))

                     {

                            DBG_printf("touchkey value:%02X\n", KeyVal);

                            SetKeyValLed(KeyVal);

                     }

                     else

                     {

                            DBG_printf("Nokey\n");

                            SetKeyValLed(0);

                     }

#if 0

                     DBG_printf("Readkey status \n");

                     if(__HTK_Uart_Read_touch_status(&KeyStatus))

                     {

                            DBG_printf("touchkey status:0x%08X\n", KeyStatus);

                     }

                     else

                     {

                            DBG_printf("Nokey\n");

                     }

                     DBG_printf("Readgesture \n");

                     if(__HTK_Uart_Read_gesture(&Gesture))

                     {

                            DBG_printf("touchkey gesture:%d\n", Gesture);

                     }

                     else

                     {

                            DBG_printf("Nogesture\n");

                     }

#endif

#endif

              }

              else

              {

                     SetKeyValLed(0);

              }

              __isGetHtkIntr= FALSE;

       }

}

/**************************************************************************

Parameters:           

                     void

Return:          

                     void

Description:   

              上升沿中断服务程序

                     当上升沿中断来到来时,表示有触摸按键被按下

**************************************************************************/

void __HTK_Intr_isr(void)

{

       if(__isGetHtkIntr)

       {

              return;

       }

      

       __isGetHtkIntr= TRUE;

}

(7)有关复位:

一般情况下,只需要主控板在上电时,通过软件上拉时即可。如果为了增强软件的可靠性,以预防各种可能出现的异常情况,可以在程序的某些地方增加一部分代码,即通过调用_HTK_I2C_Read_optimal_touch_keyval()函数无法读取数据时,即可以调用复位函数启动HTK100的硬件复位功能。但该复位函数不应在INT中断服务程序中调用,因为如果HTK100没有正常工作,同时也不会出现中断信号。一种比较可靠的办法就是定时调用_HTK_I2C_Read_optimal_touch_keyval()检测HTK100是否正常工作。如果工作不正常,即启动复位程序。

复位程序如下所示:

/**************************************************************************

Parameters:           

                     void

Return:          

                     void

Description:   

                     触摸按键复位

**************************************************************************/

void__HTK_reset(void)

{

       SET_HTK_RST;

       __delay_us(10);

       CLR_HTK_RST;

       __delay_us(200);

       SET_HTK_RST;

}

 

祝您早日调通和使用华仕飞触摸按键板。


猜你喜欢

转载自blog.csdn.net/lihwar/article/details/80047703