本帖最后由 dirty 于 2024-2-22 09:38 编辑
开发板FM33FT056A MCU集成了触摸检测功能,官方提供了完整TSI触摸解决方案,且有防液体误触、抑制电磁干扰、支持覆盖触摸、自动调优算法等优势特点。通过软硬件协同,可应用在汽车电子触摸领域,如车窗、车灯、中控面板等的触控应用。本篇讲述实现TSI按键触摸和滑条触摸及位置功能。
一.硬件原理
开发板板载两个触摸按键BT0、BT1 和一个触摸滑条SLDER,原理图及硬件部分如下
图1:触摸按键与滑条
TSI 模块使用自电容的方法来检测触摸行为。复旦微在TSI方面有齐全资料介绍,其集成了自有算法及配备调试工具TSITuner,一方面节约了成本,另一方面在方案应用上完整闭环,这一块做的挺不错。
二.代码准备
官方提供了TSIDemo,这里做些解读与完善修改及应用。
1.关于TSI软件库介绍
(1). tsi.c, tsi.h:包含库的运行控制函数(启动、停止等);
(2). tsi_baseline.c, tsi_baseline.h: 包含基准线算法相关实现;
(3). tsi_calibration.c, tsi_calibration.h: 包含触摸硬件参数自动校准算法的相关实现;
(4). tsi_conf.h:用户配置文件, TSI 软件库的一些可配参数都罗列于此。我们仅提供对应该文件的模板 tsi_conf_template.h, 用户修改后重新命名为 tsi_conf.h 即可使用;
(5). tsi_def.h: 包含库所需的一些定义,包括一些配置可选参数值的定义;
(6). tsi_filter.c, tsi_filter.h: 包含 RawCount 滤波器的实现;
(7). tsi_interrupt.c: 包含 TSI 模块的中断服务程序;
(8). tsi_objects.c, tsi_objects.h: tsi_objects.c 包含全部的 TSI 模块控件定义和参数(触摸引脚TSI_Pins及通道TSI_ChannelSensorMap等),tsi_objects.h 包含全部 TSI 软件库数据结构定义; tsi_objects.c 我们仅提供对应的模板 tsi_objects_template.c, 用户修改后重新命名为 tsi_objects.h 即可使用;
(9). tsi_sensor.c, tsi_sensor.h:包含传感器使用的配置、初始化、更新状态函数;
(10). tsi_widget.c, tsi_widget.h:包含控件使用的配置、初始化、更新状态函数;
2.代码修改
(1)main函数去除TSI_DEBUG_xxx,添加前面已讲述调试串口打印,并添加按键、滑条触摸及位置检测,代码如下
int main(void)
{
/* 使能IWDT */
IWDT_Init(FL_IWDT_PERIOD_4000MS);
/* Init FL driver library */
FL_Init();
/* 使能SVD, 阈�?.157V(falling)~4.257V(rising) */
SVD_Init(SVD_MONTIOR_VDD, FL_SVD_WARNING_THRESHOLD_GROUP11, FL_SVD_REFERENCE_1P0V);
/* 确认SVD监测结果是否高于阈值,如否则持续等�?*/
while(false == SVD_Result_Confirmed(SVD_HIGHER_THRESHOLD, 2000U/*us*/));
/* 使能BOR */
RMU_BOR_Init(FL_RMU_BOR_THRESHOLD_2P00V);
/* Init system clock */
SystemClockInit();
/* USER CODES AREA 1 BEGIN */
/* USER CODES AREA 1 END */
MF_Config_Init();
/* Init TSI */
TSI_Init();
printf("TSI Init \r\n");
/* Enable all widgets */
TSI_Widget_EnableAll();
/* Feed watchdog */
FL_IWDT_ReloadCounter(IWDT);
/* Start TSI */
TSI_Start();
printf("TSI Start \r\n");
/* Feed watchdog */
FL_IWDT_ReloadCounter(IWDT);
/* Init and start TSI debug */
// TSI_Debug_Init();
// TSI_Debug_Start();
/* USER CODES AREA 2 BEGIN */
/* USER CODES AREA 2 END */
while(1)
{
/* USER CODES AREA 3 BEGIN */
/* USER CODES AREA 3 END */
/* Feed watchdog */
FL_IWDT_ReloadCounter(IWDT);
/* 电源掉电监测处理 */
PowerDownMonitoring();
/* Handle debug event */
TSI_Debug_Handler();
/* USER CODES AREA 4 BEGIN */
/* USER CODES AREA 4 END */
/* Wait until a scan sequence has completed */
if(TSI_GETSTAT_SCAN_CPLT())
{
TSI_CLRSTAT_SCAN_CPLT();
/* Update all widgets */
TSI_Widget_UpdateAll();
if(TSI_WidgetList.bt0.buttonStatus==1)
{
printf("bt0 is touched\r\n");
}
if(TSI_WidgetList.bt1.buttonStatus==1)
{
printf("bt1 is touched\r\n");
}
if(TSI_WidgetList.slider.sliderStatus==1)
{
printf("silder is touched,position:%d--[range:0-255]\n",TSI_WidgetList.slider.centerPos);
}
/* Update debug interface trace buffer */
// TSI_Debug_UpdateTrace();
/* USER CODES AREA 5 BEGIN */
/* USER CODES AREA 5 END */
}
/* USER CODES AREA 6 BEGIN */
/* USER CODES AREA 6 END */
}
}
(2)调试仿真时发现滑条触发状态没有置位,官方代码有点bug.修改TSI_Widget_UpdateSlider,添加sliderWidget->sliderStatus=sliderWidget->base.status;完整函数如下:
void TSI_Widget_UpdateSlider(TSI_SliderWidgetTypeDef* sliderWidget)
{
if(sliderWidget->base.status == 1U)
{
int i;
uint8_t peakIndex = 0U;
uint16_t peakSignalVal = 0U;
uint16_t centroidCalcData[3];
uint16_t threshold = sliderWidget->base.activeTh - sliderWidget->base.activeHys;
int32_t centroid;
const TSI_MetaWidgetTypeDef *metaWidget = sliderWidget->base.meta;
TSI_SensorTypeDef* sensor = metaWidget->sensors;
int32_t mul = (TSI_SLIDER_RESOLUTION / (metaWidget->sensorCnt - 1)) << 8U;
/*
Calculate the slider postion using centroid algorithm:
1. Find the sensor X with the highest signal, which is the center of the touched area;
2. Calcuate centroid using X's neighbour sensor;
*/
/* Find peak value and corresponding sensor */
for (i = 0; i < metaWidget->sensorCnt; i++)
{
if(sensor->diffCount > threshold && sensor->diffCount > peakSignalVal)
{
peakIndex = i+1;
peakSignalVal = sensor->diffCount;
}
sensor++;
}
if(peakIndex != 0)
{
/* Get neighbour sensors signal value */
sensor = metaWidget->sensors;
if(peakIndex == 1)
{
centroidCalcData[0] = 0;
centroidCalcData[1] = peakSignalVal;
centroidCalcData[2] = (int32_t)sensor[1].diffCount;
}
else if(peakIndex == metaWidget->sensorCnt)
{
centroidCalcData[0] = sensor[peakIndex-2].diffCount;
centroidCalcData[1] = peakSignalVal;
centroidCalcData[2] = 0;
}
else
{
centroidCalcData[0] = sensor[peakIndex-2].diffCount;
centroidCalcData[1] = peakSignalVal;
centroidCalcData[2] = sensor[peakIndex].diffCount;
}
/* Calculate centroid */
centroid = ((int32_t)centroidCalcData[2]
- (int32_t)centroidCalcData[0]) * mul /
((int32_t)centroidCalcData[0]
+ (int32_t)centroidCalcData[1]
+ (int32_t)centroidCalcData[2]);
centroid += (peakIndex-1) * mul;
centroid >>= 8U;
sliderWidget->centerPos = centroid;
}
}
//fix bug:sliderStatus not setted when touched or released
sliderWidget->sliderStatus=sliderWidget->base.status;
}
代码准备完毕,编译烧录。
三.测试
打开串口,触摸BT0,BT1可看到触摸按键被触发;滑条位置从右至左(USB TYPE-C朝左)位置为0-255,可点触或者滑动触摸。完整日志如下
图2:触摸日志
至此,触摸功能得以应用实现,效果不错,触摸灵敏且滑条位置准确。