本帖最后由 yang_alex 于 2018-4-24 23:21 编辑
通过阅读CH554器件手册,可以了解到CH554 芯片提供了电容检测模块及相关的定时器,具有 6 个输入通道,自电容方式可以支持最多6个触摸按键,互电容方式可以支持最多15个触摸按键。
新评估板的电容触摸按键例程是通过自电容方式检测按键。使用了P14、P15、P16、P17四个通道。对应输入通道如下表。
器件手册的第17章第3节描述了电容触摸按键的检测步骤,电容触摸按键例程也是按此编写程序的。
使用一个MCU的功能,首先要对它进行初始化。电容触摸按键初始化函数在TouchKey.C文件中。
照前面电容触摸按键的检测步骤要求,被选择的输入通道,其所在 GPIO 引脚必须设置为高阻输入模式、或者开漏输出模式并且处于输出 1 的状态(相当于高阻输入),Pn_DIR_PU[x]=0。所以在电容触摸按键初始化函数
UINT8 TK_Init( UINT8 channel , UINT8 queryFreq, UINT8 ie )
中,把相关引脚设置成高阻输入模式、或者开漏输出模式
- P1_DIR_PU &= ~channel;
- P1_MOD_OC &= ~channel;
复制代码
电容检测定时器的周期选择有2种,通过Touch-Key 控制寄存器(TKEY_CTRL)的bTKC_2MS 位选择:0-1mS;1-2mS。
在程序中就是通过电容触摸按键初始化函数的参数 queryFreq来设置(0-1mS;1-2mS)。
- UINT8 TK_Init( UINT8 channel , UINT8 queryFreq, UINT8 ie )
复制代码
在初始化过程中,对使用的电容触摸按键通道采样初始值,这个初始值是采样几次进行平均。
- /* Get Key_FreeBuf. Save the data in flash or macro define. */
- /* DO NOT get Key_FreeBuf in Mass Production. */
- for ( i = 0; i < TOUCH_NUM; i++ )
- {
- sum = 0;
- j = SAMPLE_TIMES;
- TK_SelectChannel( i );
- // TKEY_CTRL |= TK_Code[i];[/i]
- while( j-- )
- {
- OverTime = 0;
- while( ( TKEY_CTRL & bTKC_IF ) == 0 )
- {
- if( ++OverTime == 0 )
- {
- return FAIL;
- }
- }
- sum += TKEY_DAT; /* */
- }
- Key_FreeBuf = sum / SAMPLE_TIMES;
- printf( "Key_FreeBuf[%d]=%d\t", (UINT16)(i), (UINT16)Key_FreeBuf );
- }
复制代码
采样次数SAMPLE_TIMES在TouchKey.H头文件中定义
- #define SAMPLE_TIMES (0x05)
复制代码
电容触摸按键是使用中断模式工作的,所以在初始化函数末尾,打开电容触摸按键中断。
- if( ie != 0 ) /* Enable interrupt ? */
- {
- IE_TKEY = 1;
- }
复制代码
至此,电容触摸按键初始化工作完成。
接下来,确定我们使用那几个通道。参见第一个表格
- UINT8 TK_SelectChannel( UINT8 ch )
- {
- if ( ch <= TOUCH_NUM )
- {
- TKEY_CTRL = ( TKEY_CTRL & 0XF8) | TK_Code[ch];
- return SUCCESS;
- }
- return FAIL;
- }
复制代码
这里的 TOUCH_NUM 是在下面这里定义的。
- UINT8 TK_Code[TOUCH_NUM] = { /* Arrange the input channel */
- // 0x01, 0x02, /* CH0 CH1 */
- 0x03, 0x04, /* CH2 CH3 */
- 0x05, 0x06 /* CH4 CH5 */
- };
复制代码
电容触摸按键是使用中断模式工作的,所以接下来记得把中断打开。
- EA = 1; /* Enable global interrupt. */
复制代码 CH554检测到电容触摸按键的中断后,进入电容触摸按键中断服务程序,里边把检测到的值和门槛值进行比较,(这里要注意两点。1、前面讲到的电容检测步骤第4条:进入中断程序中,首先从 TKEY_DAT 中读取当前通道的电容数据,并屏蔽最高位 bTKD_CHG,该
数据是相对值,与电容量成反比,当触摸按键按下时的数据比未按下时的数据小。2、用步骤(4)读取的 TKEY_DAT 数据与之前保存的该通道无按键时的数据比较,判断是否电容变化和是否有按键被按下。),并选择下一通道以便继续扫描按键。
- void TK_int_ISR( void ) interrupt INT_NO_TKEY using 1
- {
- static UINT8 ch = 0;
- UINT16 KeyData;
- KeyData = TKEY_DAT;
-
- if( KeyData < ( Key_FreeBuf[ch] - TH_VALUE ) )
- {
- Touch_IN |= 1 << ( TK_Code[ch] - 1 );
- }
-
- // printf( "ch[%d]=%d\t", (UINT16)(TK_Code[ch] - 1), (UINT16)KeyData );
- if( ++ch >= TOUCH_NUM )
- {
- // printf("\n");
- ch = 0;
- }
- TK_SelectChannel( ch );
- }
复制代码
主程序在死循环中判断哪个通道发生按键动作:
- while ( 1 )
- {
- // if( TK_Measure() != SUCCESS ) /* For Query Mode. */
- // {
- // printf("ERROR\n");
- // }
-
- if( Touch_IN != 0 )
- {
- if( Touch_IN & CH0 )
- {
- printf("CH0 is pressed.\n");
- }
- if( Touch_IN & CH1 )
- {
- printf("CH1 is pressed.\n");
- }
- if( Touch_IN & CH2 )
- {
- printf("CH2 is pressed.\n");
- }
- if( Touch_IN & CH3 )
- {
- printf("CH3 is pressed.\n");
- }
- if( Touch_IN & CH4 )
- {
- printf("CH4 is pressed.\n");
- }
- if( Touch_IN & CH5 )
- {
- printf("CH5 is pressed.\n");
- }
- Touch_IN = 0;
- }
- }
复制代码
这里有几个地方需要注意一下:1、由于在电容触摸按键初始化时检测了按键上电容的初始值,并在后续检测中进行比较。所以要注意上电时,电容触摸按键要保持和后续检测按键时一样的状态。换句话说就是不要在上电时在电容触摸按键上覆盖东西,但在使用按键检测是,这个东西又被移走了。
2、电容触摸按键的门槛值是可以设置的。门槛值TH_VALUE在TouchKey.H头文件中定义
运行结果如下:
看样子需要加个去重复按键的机制
此内容由EEWORLD论坛网友yang_alex原创,如需转载或用于商业用途需征得作者同意并注明出处