首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

NucleoF429 基础应用3:GPIO Touch Key(触摸按键)-2

NucleoF429 基础应用3:GPIO Touch Key(触摸按键)-2

我做了两次滤波:1、间隔100us进行一次充放电采集,连续采集12个点,将这12个点进行从大到小排序,之后去掉队首最大的4个值和队尾最小的4个值,取中间的4个值做平均,通过这样将一段时间内的数据累加平均为一个点,能有效去掉脉冲干扰。
/*----------------------------------------------------------------------------*/uint16_t Touch_Heap(void){  uint8_t i,j;  uint8_t DataTemp;  uint32_t DataSum = 0;  for(i=0; i<Heap_Num-1;i++)  {  for(j=0;j<Heap_Num-i;j++)  {  if(Data_Buffer[j]<Data_Buffer[j+1])  {  DataTemp = Data_Buffer[j];  Data_Buffer[j] = Data_Buffer[j+1];  Data_Buffer[j+1] = DataTemp;  }  }  }  for(i=Dis_Num;i<Heap_Num-Dis_Num;i++)  {  DataSum += Data_Buffer;  }  DataSum = DataSum/(Heap_Num-2*Dis_Num);  return (uint16_t) DataSum;}
2、间隔10ms进行一次连续的采集,采集后的点再进行平滑滤波,我这里采用了一个一阶低通滤波器,通过调整滤波系数能调节波形的延时和滤波效果。(ST提供了各种滤波器函数,效率高效果好,有兴趣的同学可以深入研究一下)
/*----------------------------------------------------------------------------*//*  LPF: Y(n) = α*X(n)+(1-α)*Y(n-1)  Y[n]:  = Y[n-1] + α * (X[n] - Y[n-1]) LPF_Yn[0:1] = Yn-1:Yn  */ uint16_t IIR_LowPass_Filter(uint16_t LPF_Data){  float LPF_Temp;  LPF_Temp = LPF_Pre_Data+ LPF_Alpha*(LPF_Data - LPF_Pre_Data);  LPF_Pre_Data = LPF_Temp;  return (uint16_t)LPF_Temp;}
经过两次滤波后,充放电数据波形改善很多。
3、Touch Key 状态判断:
     这里是指判断按下和释放,通常的做法是设置一个阈值,高于多少或者低于多少就认为是按下或释放,有些程序会做到动态追踪最低点等等,对于元件一致性好的产品,误差都在可控范围内,这样做通常没有太大问题。但对于一些成本敏感,元器件误差较大的产品,问题就会比较明显,因为每一个产品的元件都有误差,这些误差的范围有可能已超过了你的阈值范围,无论你阈值设置过大或过小,总有一部分产品会有问题,即使是同一个产品,不同的环境也会导致阈值超出范围,比如Touch Pad受到灰尘、磨损等改变了自身的等效电容,电阻阻值随温度进行变化等等。
     我这里采用数据变化的“趋势”来判断Touch 按下或释放,如图:
把数据点放入队列,依次计算前后两个点的差值,判断数值是增大还是减小,通过计数符合差值的点的次数,判断Touch按下还是释放,这也能有效排除干扰,最重要的是,这种方法受外界因素的影响比较小,元器件之间的差异被排除,因为这里只判断增量而非绝对值。
/*----------------------------------------------------------------------------*/// 按下时:符合差值的计数增减,释放时,符合差值的计数减小。void Check_Touch_State(void){  uint8_t i;  uint8_t Touch_DebCnt = Data_Num; //数据点个数  int8_t Touch_D_Value = 0;  for(i=0;i<Data_Num;i++)  {  Touch_Data_Buffer = Touch_Data_Buffer[i+1]; //队列左移  }  Touch_Data_Buffer = IIR_LowPass_Filter(Touch_Heap()); //最新数据点补在队列尾部  if(Touch_POR_Deb > 200) //上电先做采集不判断按键状态,防止上电时数据为0,被误判为按下。  {  for(i=0;i<Data_Num;i++)  {  Touch_D_Value = Touch_Data_Buffer - Touch_Data_Buffer[i+1];  if(Touch_D_Value > Release_Sen_Value)  {  Touch_DebCnt--;  }  else if(Touch_D_Value < Press_Sen_Value )  {  Touch_DebCnt++;  }  }  if(Touch_DebCnt > (Data_Num+3)) //判断递增次数(Press)  {  Press_Flag = 0x01;  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);  }  else if(Touch_DebCnt < (Data_Num-3)) //判断递减次数(Release)  {  Press_Flag = 0xF1;  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);  }  }  else  {  Touch_POR_Deb++;  }}
以上是Touch Key的实现过程,作为一个原理性的Demo,还有很多细节工作未作,如果采用这种方式到产品中,还需要仔细优化和调试,如防止放电超时,功耗等问题,以上Demo是用NucleoF429上完成的,原理较为简单,可以方便移植到其他MCU上完成,(事实上我先是用NucleoF031K6完成之后再移植到F429上的)。
     以上Demo没有写关于CubeMX的部分,因为只需要一个或者两个中断,并不局限于具体的MCU。另外此文中的所有参数都是针对我的电路的,可以按照具体的电路和应用来调整参数。
返回列表