STM32-11-电容触摸按键

embedded/2024/9/22 23:50:28/

STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
STM32-10-定时器

STM32电容触摸按键

  • 电容触摸按键原理
    在这里插入图片描述
    在这里插入图片描述

    无手指触摸:上电时,电阻作用下,电容Cs进行充电,直到电容充满,这时候会有一个充电时间Tcs.

    有手指触摸:上电时,电阻作用下,电容CsCx进行充电,电容充满时间会变长,得到充电时间Tcx.
    在这里插入图片描述
    在这里插入图片描述

  • 检测电容触摸按键过程

    1. TPAD引脚设置为推挽输出,输出低电平,实现电容放电到地
    2. TPAD引脚设置为浮空输入(IO复位后的状态),电容开始充电
    3. 同时开启TPAD引脚的输入捕获功能,开始捕获高电平
    4. 等待充电过程中,上升沿触发(充电到Vth(上升沿的电压值))
    5. 计算充电时间(定时器捕获/比较寄存器获取)
  • 硬件结构图
    在这里插入图片描述

  • 代码实现

    • TPAD初始化函数

      uint8_t tpad_init(uint16_t psc)
      {uint16_t buf[10];uint16_t temp;uint16_t i,j;tpad_timx_cap_init(0XFFFF, psc - 1);//连续读取10次for(i = 0; i < 10; i++){buf[i] = tpad_get_val();delay_init(10);}for(i = 0; i < 9; i++){for(j = i + 1; j < 10; j++){if(buf[i] > buf[j]){temp = buf[i];buf[i] = buf[j];buf[j] = temp;}}}temp = 0;for(i = 2; i < 8; i++){temp += buf[i];}g_tpad_default_val = temp / 6;printf("g_tpad_default_val:%d\r\n", g_tpad_default_val);if (g_tpad_default_val > 0XFFFF / 2){return 1;                   /* 初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常! */}return 0;
      }
      
    • 触摸按键输入捕获设置

      void tpad_timx_cap_init(uint16_t arr, uint16_t psc)
      {GPIO_InitTypeDef gpio_init_struct;TIM_IC_InitTypeDef timx_ic_cap_chy;__HAL_RCC_GPIOA_CLK_ENABLE();  //初始化GPIOA时钟__HAL_RCC_TIM5_CLK_ENABLE();   //初始化TIM5时钟gpio_init_struct.Pin = GPIO_PIN_1;       //PA1gpio_init_struct.Mode = GPIO_MODE_INPUT; //输入gpio_init_struct.Pull = GPIO_PULLDOWN;   //下拉gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM; //中速HAL_GPIO_Init(GPIOA, &gpio_init_struct);  //初始化g_timx_cap_chy_handle.Instance = TIM5;      //定时器基地址g_timx_cap_chy_handle.Init.Prescaler = psc; //分频系数g_timx_cap_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;  //向上计数g_timx_cap_chy_handle.Init.Period = arr;    //自动重装载值g_timx_cap_chy_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  //时钟分频因子HAL_TIM_IC_Init(&g_timx_cap_chy_handle);timx_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING;     //上升沿捕获timx_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI; //映射到TI1timx_ic_cap_chy.ICPrescaler = TIM_ICPSC_DIV1;           //输入分频设置为不分频timx_ic_cap_chy.ICFilter = 0;                           //输入滤波设置为不滤波HAL_TIM_IC_ConfigChannel(&g_timx_cap_chy_handle, &timx_ic_cap_chy, TIM_CHANNEL_2);HAL_TIM_IC_Start(&g_timx_cap_chy_handle, TIM_CHANNEL_2);  //使能输入捕获和定时器
      }
      

      输入捕获映射到TI1通道,意味着PA1引脚的信号将被定时器的第一个输入捕获通道TI1处理。代码中指定了TIM_ICSELECTION_DIRECTTI,表示直接选择输入引脚作为捕获源,而不是通过其他中间信号。

      PA1引脚的信号映射到定时器通道1(TI1)的过程是通过硬件内部的多路复用器(multiplexer,简称MUX)实现的。

    • 获取捕获值

      uint16_t tpad_get_val(void)
      {tpad_reset();//等待捕获上升沿,捕获结束后标志位会置1while(__HAL_TIM_GET_FLAG(&g_timx_cap_chy_handle, TIM_CHANNEL_2) == 0){if(g_timx_cap_chy_handle.Instance->CNT > 0xFFFF - 500){return g_timx_cap_chy_handle.Instance->CNT;}}return TIM5->CCR2;
      } 
      
    • 复位TPAD

      void tpad_reset(void)
      {GPIO_InitTypeDef gpio_init_struct;gpio_init_struct.Pin = GPIO_PIN_1;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;gpio_init_struct.Pull = GPIO_PULLUP;gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOA, &gpio_init_struct);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);  //TPAD引脚输出0,放电delay_ms(5);g_timx_cap_chy_handle.Instance->SR = 0;   //清除标记g_timx_cap_chy_handle.Instance->CNT = 0;  //归零gpio_init_struct.Pin = GPIO_PIN_1;gpio_init_struct.Mode = GPIO_MODE_INPUT;gpio_init_struct.Pull = GPIO_NOPULL;gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOA, &gpio_init_struct);
      }
      
      1. 配置PA1为推挽输出模式,并且设置为上拉电阻。这样可以确保PA1在输出状态下可以稳定的输出高低电平信号。
      2. 设置PA1引脚为低电平,相当于对TPAD引脚进行放电操作。
      3. 延时5ms,确保放电操作完成。
      4. 清除定时器状态寄存器和计数器。
      5. 配置PA1引脚为输入模式,并且设置为无上下拉电阻,这样,TPAD引脚可以正常接收外部输入信号。

      在嵌入式系统中,尤其是在涉及触摸传感器或类似的硬件操作时,先将引脚设置为推挽输出模式再进行放电是一个常见的做法。这种方法可以确保引脚能够快速且有效地放电,从而为后续的操作(例如测量或重新配置引脚为输入模式)提供一个已知的初始状态。

      为什么要先设置为推挽输出模式再进行放电?

      1. 强制性放电
      • 推挽输出模式能够提供较强的驱动能力。通过将引脚设置为推挽输出模式并输出低电平,能够确保引脚上的电容或残留电荷能够迅速放电至0。这对于某些敏感的电路来说是必要的,确保电路在重新配置为输入模式之前没有残余电荷影响测量精度。
      1. 可靠的初始状态
      • 直接将引脚设置为低电平进行放电在某些情况下可能并不能保证完全的放电,特别是在引脚上有较大的寄生电容时。推挽模式可以提供更可靠的低电平输出,确保引脚电位完全放电至0。
      1. 硬件保护
      • 通过推挽输出模式放电,可以避免因高阻抗状态导致的浮动电平问题。高阻抗状态下,外界噪声可能会干扰引脚电平,从而影响后续的测量。
    • 扫描触摸按键

      uint8_t tpad_scan(uint8_t mode)
      {static uint8_t keyen = 0;   /* 0, 可以开始检测;  >0, 还不能开始检测; */uint8_t res = 0;uint8_t sample = 3;         /* 默认采样次数为3次 */uint16_t rval;if (mode){sample = 6;             /* 支持连按的时候,设置采样次数为6次 */keyen = 0;              /* 支持连按, 每次调用该函数都可以检测 */}rval = tpad_get_maxval(sample);if (rval > (g_tpad_default_val + 100))    /* 大于tpad_default_val+TPAD_GATE_VAL,有效 */{if (keyen == 0){res = 1;            /* keyen==0, 有效 */}//printf("r:%d\r\n", rval);   /* 输出计数值, 调试的时候才用到 */keyen = 3;              /* 至少要再过3次之后才能按键有效 */}if (keyen) keyen--;return res;
      }
      
    • 读取的数据取最大值

      uint16_t tpad_get_maxval(uint8_t n)
      {uint16_t temp = 0;uint16_t maxval = 0;while (n--){temp = tpad_get_val();  /* 得到一次值 */if (temp > maxval) maxval = temp;}return maxval;
      }
      
    • 主函数

      int main(void)
      {uint8_t t = 0;HAL_Init();                                 /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */delay_init(72);                             /* 延时初始化 */usart_init(115200);                         /* 串口初始化为115200 */led_init();                                 /* 初始化LED */tpad_init(6);while (1){if (tpad_scan(0))   /* 成功捕获到了一次上升沿(此函数执行时间至少15ms) */{LED1_TOGGLE();  /* LED1翻转 */}t++;if (t == 10){t = 0;LED0_TOGGLE();  /* LED0翻转 */}delay_ms(200);}
      }
      
  • 程序运行流程
    在这里插入图片描述

声明:资料来源(战舰STM32F103ZET6开发板资源包)

  1. Cortex-M3权威指南(中文).pdf
  2. STM32F10xxx参考手册_V10(中文版).pdf
  3. STM32F103 战舰开发指南V1.3.pdf
  4. STM32F103ZET6(中文版).pdf
  5. 战舰V4 硬件参考手册_V1.0.pdf

http://www.ppmy.cn/embedded/43647.html

相关文章

常见排序算法之插入排序

目录 一、直接插入排序 1.1 什么是插入排序 1.2 代码思路 1.3 C语言源码 二、希尔排序 2.0 插入排序的弊端 2.1 什么是希尔排序&#xff1f; 2.2 排序思路 2.3 C语言源码 一、直接插入排序 1.1 什么是插入排序 插入排序是一种简单直观的排序算法&#xff0c;它通过构…

图像上下文学习|多模态基础模型中的多镜头情境学习

【原文】众所周知&#xff0c;大型语言模型在小样本上下文学习&#xff08;ICL&#xff09;方面非常有效。多模态基础模型的最新进展实现了前所未有的长上下文窗口&#xff0c;为探索其执行 ICL 的能力提供了机会&#xff0c;并提供了更多演示示例。在这项工作中&#xff0c;我…

elasticdump和ESM

逐个执行如下命令&#xff1b; 1.拷贝analyzer如分词&#xff08;需要分词器&#xff0c;可能不成功&#xff0c;不影响复制&#xff09; ./elasticdump --inputhttp://[来源IP地址]:9200/[来源索引] --outputhttp://[目标IP地址]:9200/[目标索引] --typeanalyzer 2.拷贝映射…

unity 制作app实现底部导航栏和顶部状态栏

前段时间在用unity制作一个app&#xff0c;发现有个问题用unity制作的app&#xff0c;他默认是没有顶部状态栏的&#xff0c;也没有底部的导航栏&#xff0c;是一个全部覆盖的状态。但仔细观察可以发现&#xff0c;正常app&#xff0c;顶部状态栏是有的&#xff0c;而且是透明的…

HBase安装

安装HBase 提示&#xff1a;需要安装好hadoop和zookeeper 安装zookeeper可参考 一、确定HBase版本 去网站确认 https://hbase.apache.org/book.html#hadoop二、下载HBase安装包 去清华大学镜像站下载 https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/三、安装HBase …

Java | Leetcode Java题解之第103题二叉树的锯齿形层序遍历

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> ans new LinkedList<List<Integer>>();if (root null) {return ans;}Queue<TreeNode> n…

HCIP的学习(24)

第七章&#xff0c;VLAN—虚拟局域网 ​ 通过在交换机上部署VLAN技术&#xff0c;将一个规模较大的广播域在逻辑上划分成若干个不同的、规模较小的广播域。 ​ IEEE 802.1Q标准----虚拟桥接局域网标准----Dot1Q标准 标签协议标识符&#xff1a;0x8011&#xff08;代表数据帧是8…

BookxNote Pro 宝藏 PDF 笔记软件

一、简介 1、BookxNote Pro 是一款专为电子书阅读和学习笔记设计的软件&#xff0c;支持多种电子书格式&#xff0c;如PDF和EPUB&#xff0c;能够帮助用户高效地管理和阅读电子书籍&#xff0c;同时具备强大的笔记功能&#xff0c;允许用户对书籍内容进行标注、摘录和思维导图绘…