STM32作业实现(八)触摸按键TPAD

news2025/7/18 21:27:41

目录

STM32作业设计
STM32作业实现(一)串口通信
STM32作业实现(二)串口控制led
STM32作业实现(三)串口控制有源蜂鸣器
STM32作业实现(四)光敏传感器
STM32作业实现(五)温湿度传感器dht11
STM32作业实现(六)闪存保存数据
STM32作业实现(七)OLED显示数据
STM32作业实现(八)触摸按键TPAD
STM32作业实现(九)驱动舵机
源码位置

编写Tpad驱动文件(控制舵机开关)

在这里插入图片描述
在这里插入图片描述

开启所需引脚
在这里插入图片描述
开启中断模式
在这里插入图片描述
tpad.h

#ifndef __TPAD_H__
#define __TPAD_H__

#include "main.h"
#include "tim.h"

void tpad_init(void); // 初始化tapd默认值
uint8_t tpad_scan(uint8_t mode);// 获取tpad是否有触摸

#endif

tpad.c

#include "tpad.h"

uint16_t temp = 0;             // 每次读取数据后存放
uint16_t flag = 0;             // 中断标志位
uint16_t tpad_default_val = 0; // 无接触的值

/*
复位 TPAD

将TPAD按键看作是一个电容,手指按下和不按下电容值有变化
先将GPIO设置为推挽输出,输出0,进行放电,
在设置为GPIO为浮空输入,等待电容充电,并且捕获上拉
*/
void tpad_reset(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  // 将PA1设置为开漏输出
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉电阻
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  // 将PA1设置0,对电容进行放电
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);

  htim5.Instance->SR = 0;  // 清除标记
  htim5.Instance->CNT = 0; // 归零

  // 将PA1设置为输入模式,进行捕获
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  // 设置为上沿捕获
  __HAL_TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
  // 开启定时器捕获中断
  HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_2);
}

/*
重写捕获比较中断回调函数
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  // 为了读数准确 关闭捕获定时器
  HAL_TIM_IC_Stop(&htim5, TIM_CHANNEL_2);

  // 读取值后存储到temp中
  temp = HAL_TIM_ReadCapturedValue(&htim5, TIM_CHANNEL_2);
  // flag置1,表示完成
  flag = 1;
}
/*
读取单次PA1函数
函数功能:读取PA1, 多次读取取平均值或最大值
参数:无
返回值:无
*/
void tpad_get_val(void)
{
  // 复位引脚函数
  tpad_reset();
  // 阻塞等待中断完成
  while (flag == 0)
  {
    HAL_Delay(1); // 防止刷新过快
  }
  // 完成后标志位置0
  flag = 0;
}

/*
读取最大PA1函数
函数功能:读取PA1, 多次读取取平均值或最大值
参数:读取次数
返回值:uint16_t
*/
uint16_t tpad_get_maxval(uint8_t i)
{
  uint16_t maxval = 0; // 存放最大值

  while (i--)
  {
    // 获取数据
    tpad_get_val();
    // 取最大值
    if (temp > maxval)
      maxval = temp;
  }
  return maxval;
}

/*
触摸按键初始化函数
函数功能:获取无接触的值
参数:无
返回值: 无
*/
void tpad_init(void)
{
  // 获取无接触值
  uint16_t buf[10];
  uint16_t m;
  uint8_t i, j;

  for (i = 0; i < 10; i++) // 获取10个数据
  {
    tpad_get_val();
    buf[i] = temp;
  }

  for (i = 0; i < 9; i++) // 进行排序
  {
    for (j = i + 1; j < 10; j++)
    {
      if (buf[i] < buf[j])
      {
        m = buf[i];
        buf[i] = buf[j];
        buf[j] = m;
      }
    }
  }
  m = 0;
  for (i = 2; i < 8; i++) // 取中间的6个数据
  {
    m += buf[i];
  }

  tpad_default_val = m / 6; // 求平均值作为没有触摸时的值
}

/**
 * @brief  扫描触摸按键
 * @param  mode : 扫描模式
 * @arg    0, 不支持连续触摸(按下一次必须松开才能按下一次)
 * @arg    1, 支持连续触发(可以一直按下)
 * @retval 0, 没有按下; 1, 有按下;
 */
uint8_t tpad_scan(uint8_t mode)
{
  uint8_t res = 0; // 返回值
  uint16_t rval = 0;
  uint8_t sample = 3;       /* 默认采样次数为 3 次 */
  static uint8_t keyen = 0; /* 0, 可以开始检测; >0, 还不能开始检测; */

  if (mode) // mode = 1 为扫描模式
  {
    sample = 6; // 支持连续按的时候,设置采样次数为 6 次
    keyen = 0;  // 支持连按,每次调用该函数都可以检测
  }
  // 获取PA1的值
  rval = tpad_get_maxval(sample); // 获取读取的值

  // 比较
  if (rval > (tpad_default_val + 15))
  {
    if (keyen == 0)
      res = 1; // 返回1代表有触摸
    keyen = 3;
  }
  if (keyen)
    keyen--;
  return res; // 返回0代表无触摸
}

阶段性mian文件

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "dht11.h"
#include "w25q128.h"
#include "oled.h"
#include "tpad.h"
/* USER CODE END Includes */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define MAXSIZE 256 // 数组长度
/* USER CODE END PD */


/* USER CODE BEGIN PV */
uint8_t uart_data = 0;               // 处理不定长参数
char uart_buf[MAXSIZE] = "";         // 保存不定长命令
uint16_t uart_flag = 0;              // 高位 字节用做标志位 低位 字节记录数组使用空间
uint16_t light_adc_dma_buf[2] = {0}; // 接收光敏数据
char msg[MAXSIZE] = "";              // 测试用
char write_data[MAXSIZE] = "";       // 写入w25q128闪存数据, 4字节数据位 + 数据
char read_data[MAXSIZE] = "";        // 读取w25q128闪存数据, 4字节数据位 + 数据
extern uint8_t dht11_data[5];
int dj_flag = 0; // 启动舵机标识 0未启动 1启动
/* USER CODE END PV */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void SSD1306_Init(void);
/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_ADC3_Init();
  MX_TIM1_Init();
  MX_SPI2_Init();
  MX_TIM2_Init();
  MX_I2C1_Init();
  MX_TIM5_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, &uart_data, 1);         // 处理不定长数据
  HAL_ADCEx_Calibration_Start(&hadc3);                 // 校准光敏
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); // w25q128 使用模式3 初始拉高片选引脚电压
  int times = 0;                                       // 写入频率
  int len = 0;
  SSD1306_Init(); // iic初始化显示文字
  tpad_init();    // 初始化tpad默认值
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if (tpad_scan(0)) // 如果按下启动舵机
    {
      dj_flag = !dj_flag;
    }

    times++;
    len = 0;
    memset(msg, 0, sizeof(msg));
    if (DHT_read())
    {
      len = sprintf(msg, "sd=%d wd=%d ", dht11_data[0], dht11_data[2]);
    }
    HAL_ADC_Start_DMA(&hadc3, (uint32_t *)light_adc_dma_buf, 1); // dma模式获取光亮数值
    sprintf(msg + len, "light=%d", light_adc_dma_buf[0]);
    HAL_Delay(1000);

    // 每5秒写入一次
    if (times == 5)
    {
      times = 0;
      memset(write_data, 0, sizeof(write_data));
      sprintf(write_data, "%04d%s", strlen(msg), msg); // 组包写入闪存
      W25QXX_Write((uint8_t *)write_data, 0x00, strlen(write_data));

      HAL_Delay(500);

      memset(read_data, 0, sizeof(read_data));
      // 先读出4个字节获取数据长度
      W25QXX_Read((uint8_t *)read_data, 0x00, 4);
      len = atoi(read_data);
      W25QXX_Read((uint8_t *)read_data, 0x04, len);
      // 输出读取到的数据
      sprintf(msg, "read data: %s", read_data);
      HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), 1000);
      HAL_Delay(1000);
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // 重写回调函数
{
  if ((0x8000 & uart_flag) == 0) // 未收到\n结束
  {
    if (0x4000 & uart_flag) // 如果标志位当前是\r
    {
      // 判断本次字符是不是\r
      if (uart_data == '\n')
      {
        uart_flag |= 0x8000; // 如果收到\n更新标志位
      }
      else
      {
        uart_flag = 0; // \r后不是\n结束符不合法,重置数据
      }
    }
    else
    {
      if (uart_data == '\r') // 如果收到了\r更新标志位
      {
        uart_flag |= 0x4000;
      }
      else
      {
        // 正常数据存储到字符数组中
        uart_buf[uart_flag & 0x0fff] = uart_data;
        uart_flag++; // 下标偏移
      }
    }
  }

  if (0x8000 & uart_flag) // 收到完整的指令后
  {
    // 回显指令
    HAL_UART_Transmit(&huart1, (uint8_t *)uart_buf, uart_flag & 0x0fff, 1000);
    if (strncmp(uart_buf, "led:on", 6) == 0)
    {
      HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET);
    }
    else if (strncmp(uart_buf, "led:off", 7) == 0)
    {
      HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);
    }
    else if (strncmp(uart_buf, "buzzer:on", 9) == 0) // 打开蜂鸣器
    {
      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
    }
    else if (strncmp(uart_buf, "buzzer:off", 10) == 0) // 关闭蜂鸣器
    {
      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
    }
    uart_flag = 0; // 处理完命令清空数据
    memset(uart_buf, 0, sizeof(uart_buf));
  }

  HAL_UART_Receive_IT(&huart1, &uart_data, 1); // 重新开启中断接收
}

void SSD1306_Init(void)
{
  OLED_Init(); // 初始化oled
  // 显示默认字样
  OLED_ShowCN(0, 0, 0);                   // 速
  OLED_ShowCN(16, 0, 1);                  // 度
  OLED_ShowStr(32, 0, (uint8_t *)":", 2); // :
  OLED_ShowStr(64, 0, (uint8_t *)"0", 2); // 0

  OLED_ShowCN(0, 2, 2);                   // 光
  OLED_ShowCN(16, 2, 3);                  // 照
  OLED_ShowStr(32, 2, (uint8_t *)":", 2); // :
  OLED_ShowStr(64, 2, (uint8_t *)"0", 2); // 0

  OLED_ShowCN(0, 4, 5);                   // 温
  OLED_ShowCN(16, 4, 6);                  // 度
  OLED_ShowStr(32, 4, (uint8_t *)":", 2); // :
  OLED_ShowStr(64, 4, (uint8_t *)"0", 2); // 0

  OLED_ShowCN(0, 6, 4);                   // 湿
  OLED_ShowCN(16, 6, 6);                  // 度
  OLED_ShowStr(32, 6, (uint8_t *)":", 2); // :
  OLED_ShowStr(64, 6, (uint8_t *)"0", 2); // 0
}
/* USER CODE END 4 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1790528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vscode中选择pytorch虚拟环境中库没有导入报错,但是本机命令行下载过了

这是下载成功的结果 这个时候你会发现matplotlib的库是下载过的&#xff0c;没法下载 这个的原因是你的matplotlib库是下载到本机的python上但是pytorch框架上的是没有这个库的&#xff0c;此时应该打开ananconda promopt 然后输入activate pytorch转换成pytorch环境 然后pip…

gitlabcicd-k8s部署runner

一.环境信息 存储使用nfs挂载持久化 k8s环境 helm安装 建议helm 3 二.部署gitlab-runner 1.查看gitlab版本 进入容器可通过执行&#xff1a;gitlab-rake gitlab:env:info rootgitlab-647f4bd8b4-qz2j9:/# gitlab-rake gitlab:env:info System information System: Current Us…

zimo221软件和PCtoLCD2002软件的使用

Zimo221软件和PCtoLCD2002软件的使用 在没有字库时&#xff0c;我们可能需要自建汉字库&#xff0c;这时&#xff0c;汉字取模软件就会变得很重要。 一、zimo221取模方式&#xff1a; 1、打开软件 2、点击“基本操作” 3、一定要先点击“新建图像”按钮&#xff0c;见下图…

vue3中 window绑定scroll事件滚动页面获取不到e.target.scrollTop

遇到的问题 vue3项目 onMounted(() > {window.addEventListener(scroll, (e) > {console.log(e.target.scrollTop)}) })想要监听页面中的滚动&#xff0c;然后获取滚动距离实现一些功能&#xff0c;发现event参数中获取不到e.target.scrollTop&#xff08;印象中以前使…

NSIS 安装包默认支持的参数

NSIS 安装包默认支持的参数 NSIS 制作的安装包默认支持 /NCRC、/S、/D 三个参数&#xff0c;详见下文 3.2 Installer Usage&#xff08;来自 Command Line Usage&#xff09;。 以上三个参数对应的功能分别为禁止 CRC 校验、静默安装、设置安装路径&#xff0c;这三个功能不需…

JAVA家政系统小程序源码,家政系统源码,支持店铺入驻接单,师傅入驻接单:专业团队自主研发的一套上门家政APP系统成品源码,支持商用

JAVA家政系统小程序源码&#xff0c;家政系统源码&#xff0c;支持店铺入驻接单&#xff0c;师傅入驻接单&#xff1a;专业团队自主研发的一套上门家政APP系统成品源码&#xff0c;支持商用 家政系统是一套可提供上门家政的系统&#xff0c;可在线预约开荒保洁、上门维修、美容…

使用 Node.js 和 Azure Function App 自动更新 Elasticsearch 索引

作者&#xff1a;来自 Elastic Jessica Garson 维护最新数据至关重要&#xff0c;尤其是在处理频繁变化的动态数据集时。这篇博文将指导你使用 Node.js 加载数据&#xff0c;并通过定期更新确保数据保持最新。我们将利用 Azure Function Apps 的功能来自动执行这些更新&#xf…

Vue中引入elementUI中的container组件失效

1.不用修改官网中任何css或者html 2.按需引入&#xff0c;不是只是引入官网的就可以 import Vue from vue import Router from vue-router import HelloWorld from /components/HelloWorld import First from /components/views/First import Second from /components/views/…

操作失败——后端

控制台观察&#xff0c;页面发送的保存菜品的请求 返回的response显示&#xff1a; ---------- 我开始查看明明感觉都挺正常&#xff0c;没啥错误&#xff0c;就是查不出来。结果后面电脑关机重启后&#xff0c;隔一天看&#xff0c;就突然可以了。我觉着可能是浏览器的缓存没…

基本算法——位运算

a^b 原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目描述 运行代码 #include<iostream> using namespace std; long long a,b,c,t1; int main() {cin>>a>>b>>c;for(;b;b/2){if(b&1)tt*a%c;aa*a%c;}cout<<t%c; } 代码思路…

HTML5+CSS3+JS小实例:网格图库

实例:网格图库 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0&…

俄罗斯ozon平台计算器,ozon定价计算器

在数字化飞速发展的今天&#xff0c;电商平台已成为商家们展示产品、吸引顾客的重要窗口。而在俄罗斯这一广阔的市场中&#xff0c;Ozon平台以其独特的优势&#xff0c;成为了众多电商卖家的首选。然而&#xff0c;想要在Ozon平台上脱颖而出&#xff0c;除了优质的产品和服务外…

C语言(结构体)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸各位能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎~~ &#x1f4a5;个人主页&#xff1a;小羊在奋斗 &#x1f4a5;所属专栏&#xff1a;C语言 本系列文章为个人学习笔记&#xff0c;在这里撰写成文一…

基于数据帧进行SQL查询

本教程将通过一个具体的案例来演示如何在Spark SQL中基于数据帧进行SQL查询。我们将从创建临时视图开始&#xff0c;然后使用spark对象执行SQL查询&#xff0c;包括投影、选择、统计和排序等操作。 具体步骤如下&#xff1a; 基于数据帧创建临时视图&#xff1a; 命令格式&…

MySQL中所有常见知识点汇总

存储引擎 这一张是关于整个存储引擎的汇总知识了。 MySQL体系结构 这里是MySQL的体系结构图&#xff1a; 一般将MySQL分为server层和存储引擎两个部分。 其实MySQL体系结构主要分为下面这几个部分&#xff1a; 连接器&#xff1a;负责跟客户端建立连 接、获取权限、维持和管理…

MFC 教程-文本框失去焦点处理

【1】增加窗口的消息处理函数 void CTESTMFCDlg::OnKillFocus(CWnd* pNewWnd) {//CDialogEx::OnKillFocus(pNewWnd);//首先使用true将数据从控件传入成员变量中UpdateData(true);//校验成员变量m_data中的数据是否符合要求&#xff0c;如果不符合&#xff0c;修改后将它显示在控…

windows10 安装子linux系统(WSL安装方式)

在 windows 10 平台采用了WSL安装方式安装linux子系统 1 查找自己想要安装的linux子系统 wsl --list --online 2 在线安装 个人用Debian比较多&#xff0c;这里选择Debian&#xff0c;如下图&#xff1a; wsl --install -d Debian 安装完成&#xff0c;如下&#xff1a; 相关…

【kubernetes】探索k8s集群的pod控制器详解(Deployment、StatefulSet、DaemonSet、Job、CronJob)

目录 一、Pod控制器及其功用 二、pod控制器有多种类型 2.1ReplicaSet 2.1.1ReplicaSet主要三个组件组成 2.2Deployment 2.3DaemonSet 2.4StatefulSet 2.5Job 2.6Cronjob 三、Pod与控制器之间的关系 3.1Deployment 3.2SatefulSet 3.2.1StatefulSet三个组件 3.2.2为…

人事管理系统有哪些优势?5大人事管理系统大盘点!

本人研究企业数字化转型10余年&#xff0c;为企业软件选型、数字化提供咨询服务&#xff01;目前重点研究低代码数字化转型玩法&#xff0c;力争为各家企业探索出一条更具性价比的数字化方式。 人事管理系统有哪些优势&#xff1f;如何选择&#xff1f;又该怎样部署&#xff1…

从分布式训练到大模型训练

要了解大模型训练难&#xff0c;我们得先看看从传统的分布式训练&#xff0c;到大模型的出现&#xff0c;需要大规模分布式训练的原因。接着第二点去了解下大规模训练的挑战。 从分布式训练到大规模训练 常见的训练方式是单机单卡&#xff0c;也就是一台服务器配置1块AI芯片&a…