最简单的TSI应用实例:
——软件触发轮询采样闪灯
2015-05
前文曾经提到关于KL26的ADC模块的驱动设计模型,其IP设计使用了多通道时分复用一个转换器的思路,转换之后将量化的转换结果保存到同一个结果寄存器中。作为另一个模拟输入转换模块,KL26上的TSI(Touch Sensor Interface)模块的IP也是使用了同ADC模块相同的设计思路,这让我们不得不感叹,“不是一家人,还真不进一家门”啊。
相对于ADC使用逐次比较的方式将从输入通道获取的采样电压量化成数字,TSI也是通过使用参考震荡信号对输入通道的电极板上充放电的计数,从而将输入通道电极板的电容量化成数字。 对于软件编程来看,TSI的功能寄存器是我们能够直接操作的对象。同ADC类似,TSI也有配置当前转换通道的寄存器字段TSIx_DATA[TSICH]及保存转换结果的寄存器字段TSIx_DATA[TSICNT]。不过在软件触发模式下,TSI需要显式地写TSIx_DATA[SWTS]字段才能实现触发,而ADC在配置通道时就可以触发了。 图1
在另外两个寄存器TSIx_GENCS和TSIx_TSHD中,后者只有两个字段,专门为范围检测设定高低两个阈值的,而前者包含了几乎所有配置转换器的选项(只漏了一个关于启动DMA触发的字段在TSIx_DATA寄存器)和状态标志位。关于状态标志为,TSI可以触发两种事件,扫描结束和及扫描结果超出设定阈值范围,对应有中断开关和标志位,标志位还是典型的写1清零方式。整个TSI模块的数字接口(寄存器安排)中规中矩,简单明了,但模块本身可玩性强(可以实现触摸感应呢),实在是一个不可多得的好模块。
我根据设计ADC驱动的思路照猫画虎,很快的地实现了TSI的驱动程序,源代码及样例工程已经包含在附件中,大家感兴趣可以下载代码瞅一眼。
后来,我打算在YL-KL26Z板子上写了一个使用TSI模块的最简单的演示工程。刚好YL-KL26Z板子上设计了三个触摸板子和三个内嵌式的LED灯:
图2
图3
我就寻思着要不把触摸板搞成触摸按键吧,摸一下(好猥琐一说,不是按一下),对应的小灯就切换一次开关状态(其实还可以让喇叭叫一下的,嘿嘿,自己写写看吧)。 应用程序执行的逻辑在main函数中,贴出来代码看一眼。
- #include "app_inc.h"
-
- static void init_LED(void);
- static void init_PAD(void);
-
- #define APP_TSI_PAD_COUNT (3U)
- static uint32_t gPadIdxArray[APP_TSI_PAD_COUNT] =
- {
- BSP_TSI_PAD1_CHN, BSP_TSI_PAD2_CHN, BSP_TSI_PAD3_CHN
- };
- static uint32_t gLedPortArray[APP_TSI_PAD_COUNT] =
- {
- BSP_GPIO_LED1_PORT, BSP_GPIO_LED2_PORT, BSP_GPIO_LED3_PORT
- };
- static uint32_t gLedPinArray[APP_TSI_PAD_COUNT] =
- {
- BSP_GPIO_LED1_PIN, BSP_GPIO_LED2_PIN, BSP_GPIO_LED3_PIN
- };
-
- static uint32_t gPadBaseVal[APP_TSI_PAD_COUNT];
- static uint32_t gPadPreVal[APP_TSI_PAD_COUNT];
- static void APP_TSI_Calibration(void);
-
- int main(void)
- {
- uint32_t i;
-
- init_board();
-
- printf("\r\nHello, Board.\r\n");
- printf("Compiled at %s on %s\r\n", __TIME__, __DATE__);
-
- printf("initializing...\r\n");
-
- /* Initialize the system. */
- init_LED();
- init_PAD();
-
- APP_TSI_Calibration();
-
- printf("system ready.\r\n");
-
- while (1)
- {
- Systick_DelayTicksBlocking(4U);
- //GPIO_TogglePinLogic(BSP_GPIO_LED1_PORT, BSP_GPIO_LED1_PIN);
- for (i = 0U; i < APP_TSI_PAD_COUNT; i++)
- {
- if (gPadPreVal[i] >= gPadBaseVal[i])
- {
- gPadPreVal[i] = TSI_GetConvValueBlocking(BSP_TSI_IDX, gPadIdxArray[i]);
- if (gPadPreVal[i] < gPadBaseVal[i])
- {
- GPIO_TogglePinLogic(gLedPortArray[i], gLedPinArray[i]);
- }
- }
- else
- {
- gPadPreVal[i] = TSI_GetConvValueBlocking(BSP_TSI_IDX, gPadIdxArray[i]);
- }
- }
- }
- }
-
- static void init_LED(void)
- {
- BSP_ConfigPinForGPIO_LED();
- GPIO_SetPinLogic(BSP_GPIO_LED1_PORT, BSP_GPIO_LED1_PIN, true);
- GPIO_SetPinLogic(BSP_GPIO_LED2_PORT, BSP_GPIO_LED2_PIN, true);
- GPIO_SetPinLogic(BSP_GPIO_LED3_PORT, BSP_GPIO_LED3_PIN, true);
- GPIO_SetPinDir(BSP_GPIO_LED1_PORT, BSP_GPIO_LED1_PIN, true);
- GPIO_SetPinDir(BSP_GPIO_LED2_PORT, BSP_GPIO_LED2_PIN, true);
- GPIO_SetPinDir(BSP_GPIO_LED3_PORT, BSP_GPIO_LED3_PIN, true);
- }
-
- static void init_PAD(void)
- {
- TSI_ConverterConfig_T mTsiConvConfigStruct = TSI_CONVERTER_CONFIG_DEFAULT;
-
- SIM_EnableClockForTSI(BSP_TSI_IDX, true);
- BSP_ConfigPinForTSI_PAD();
-
- TSI_ResetConverter(BSP_TSI_IDX);
- TSI_ConfigConverter(BSP_TSI_IDX, &mTsiConvConfigStruct);
- TSI_EnableConverter(BSP_TSI_IDX, true);
- }
-
- static void APP_TSI_Calibration(void)
- {
- uint32_t i;
-
- /* Learn the base value. */
- printf("Keep nothing on the PADs, press any key to study the base TSI values ...\r\n");
- getchar();
- for (i = 0U; i < APP_TSI_PAD_COUNT; i++)
- {
- gPadBaseVal[i] = TSI_GetConvValueBlocking(BSP_TSI_IDX, gPadIdxArray[i]);
- printf("Pad %d: %5d\t", i, gPadBaseVal[i]);
- }
- printf("\r\n");
-
- /* Learn the threshold value. */
- printf("Put your finger to cover all the PADs, press any key to study the upper TSI value ...\r\n");
- getchar();
- for (i = 0U; i < APP_TSI_PAD_COUNT; i++)
- {
- gPadBaseVal[i] += TSI_GetConvValueBlocking(BSP_TSI_IDX, gPadIdxArray[i]);
- gPadBaseVal[i] /= 2;
- printf("Pad %d: %5d\t", i, gPadBaseVal[i]);
- }
- printf("\r\n");
-
- printf("TSI Calibration Done.\r\n");
- }
-
- /* EOF. */
复制代码
编译成功后,下载程序,运行。 首先要让KL26学一下没有摸上TSI触摸板时TSI的采样值。
图4
根据提示,不要摸触摸板,然后在终端中随便属于一个字符,KL26就学到了一组初始的值。
图5
从终端输出可以看到,在没有摸上触摸板时,三个TSI通道的采样值是1439、1516和1697。然后提示说要用手按住三个触摸板,让TSI感受一下被触摸的“感觉”。
图6
在手放在触摸板上的同时,在中断输入字符,此时输出学习后的触摸按键触发阈值。
图7
可以看到,三个触摸板学习的触摸阈值分别是4411、4231和3679。这组值将被用于判断手接触按键的状态。
在应用程序中使用最简单的方式扫描按键,并且省略掉了消除抖动的处理,只为最简单地演示TSI实例的用法。
软件上,除了配置TSI用到的:TSI_ResetConverter,TSI_ConfigConverter和TSI_EnableConverter,在使用时,以最简单的软件触发轮询等待方式读取TSI通道值只用了一个TSI_GetConvValueBlocking就可以搞定,这个工程中为TSI实现的驱动程序用起来也是非常不错的。
图8
实际玩起来的时候有点想是“打地鼠”,如果再多加一点控制逻辑,比如预先安排一个输出状态序列,再不断采集TSI检测的状态序列,加上时间控制,还真就可以实现一个“打地鼠”的游戏呢。童鞋们要不要试试呢? --- End
附件: |