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

目录

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 */

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

echarts柱状图的背景动态效果

这里的动态效果实现原理&#xff0c;就是相当于柱状图多了一组同系列数据&#xff0c;其值与数组展示数据一致&#xff08;类似下图&#xff09; 即&#xff0c;柱形图的每一个柱体都有它对应的另外一个柱体 其中白色柱体要与展示柱体重合&#xff0c;效果类似与给柱体做背景…

Linux---网络相关配置

文章目录 目录 文章目录 前言 一.查看网络信息 二.修改网络配置信息 总结 前言 一台主机需要配置必要的网络信息&#xff0c;才可以连接到互联网&#xff0c;需要的配置网络信息包括IP&#xff0c;子网掩码&#xff0c;网关和DNS。 一.查看网络信息 查看IP信息可以通过ifcon…

用单链表实现集合

一、实验题目 &#xff08;1&#xff09;实验题目 用单链表实现集合 &#xff08;2&#xff09;问题描述 用有序单链表实现集合的判等、交、并和差等基本运算。 二、实验内容 &#xff08;1&#xff09;采用有序单链表存储集合&#xff1b; &#xff08;2&#xff09;实现交…

IntelliJ IDEA智能编程插件AI Assistant

IntelliJ IDEA集成开发工具最新版本提供了人工智能AI编程助手的插件&#xff0c;AI Assistant使用手册的文档地址是AI Assistant | IntelliJ IDEA Documentation AI Assistant提供以下的编程能力以及工具特性&#xff1a; 与AI Assistant聊天&#xff0c;提问与项目相关或者与…

DNF手游辅助职业推荐:魔道学者云手机辅助玩法攻略!

在DNF手游中&#xff0c;魔道学者是一个独特且强力的辅助职业&#xff0c;深受玩家喜爱。她不仅能提供强大的辅助效果&#xff0c;还拥有丰富的技能机制。本文将简要介绍魔道学者的辅助玩法&#xff0c;推荐适合的装备和技能搭配&#xff0c;帮助玩家更好地掌握这一职业。 魔道…

LeetCode25_K个一组翻转链表

. - 力扣&#xff08;LeetCode&#xff09; 一、题目描述 二、过程模拟 1. 第一步 2. 第二步&#xff1a;子链表分组 3. 第三步&#xff1a;断开前后两组 4. 第四步&#xff1a;翻转start到end的部分 5. 第五步&#xff1a;连接翻转好的前半部分和未翻转的后半部分&#xff…

IEAD常用快捷键

如题 网页图片不清晰&#xff0c;可下载后查看

mac Network: use --host to expose

本地启动无法访问&#xff0c;这个不是权限问题是mac 主机端口安全策略&#xff0c;现在我们只需要开启端口自动检测就可以 npm run dev --host 网络&#xff1a;未暴露 方案一 1、执行 npm run dev -- --host 方案二 1、请在 vite.config.js server: {host: true } 1…

【SpringBoot】SpringBoot同时可以处理多少请求

目录 问题Web三大容器三者区别TomcatJetty小结 最大连接数和最大等待数同时处理请求数拓展&#xff1a;设置Web容器设置容器为Jetty设置容器为Undertow 问题 之前看到过一个面试题&#xff1a;SpringBoot同时可以处理多少请求&#xff1f; 准确的来说&#xff0c;Spring Boot…

Android Studio的Gradle面板里不显示task,build ,assemble 无法出aar包

按照以下方式把对应开关打开就可以正常进行build/assemble进行aar的生成了

景源畅信数字:抖音直播人气品类有哪些?

随着短视频平台的兴起&#xff0c;抖音成为了人们日常生活中不可或缺的娱乐方式之一。而抖音直播作为平台的重要组成部分&#xff0c;吸引了大量的观众和主播参与。那么&#xff0c;在抖音直播中&#xff0c;哪些品类能够吸引更多的人气&#xff0c;成为观众们关注的焦点呢?接…

运维工具 - SFTP 和 FTP 的区别?

SFTP 和 FTP 的区别有三点 连接方式 SFTP 是在客户端和服务器之间通过 SSH 协议建立的安全连接来传输文件&#xff0c;而 FTP 则是 TCP 端口 21 上的控制连接建立连接。 安全性 SFTP 使用加密传输认证信息来传输数据&#xff0c;因此 SFTP 相对于 FTP 更安全的。 效率 SF…

计算机英文教材太难啃?Higress 和通义千问帮你!

作者&#xff1a;张添翼&#xff08;澄潭&#xff09; 计算机相关英文教材的中译本质量堪忧&#xff0c;对于计算机专业的学生来说&#xff0c;应该深有体会。因为大部分教材的译者本人可能未必完全吃透书中技术内容&#xff0c;又或者是领域技术大拿&#xff0c;但并不擅长英…

C语言(结构体)

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

面向长文本处理的键值缓存压缩技术:智能压缩,无损性能,免微调

随着输入长度的增加&#xff0c;大型语言模型&#xff08;LLMs&#xff09;中的键值&#xff08;KV&#xff09;缓存需要存储更多的上下文信息以维持性能&#xff0c;这导致内存消耗和计算时间急剧上升。KV缓存的增长对内存和时间效率的挑战主要表现在两个方面&#xff1a;一是…

【Python数据预处理系列】精通Pandas:数据清洗中的字符串分割技巧(例子:如何将籍贯列中的横线替换为省份和市区)

本文将深入探讨Pandas库在数据清洗中的应用&#xff0c;特别是字符串分割技巧。 在数据分析的预处理步骤中&#xff0c;有效地处理和准备原始数据是至关重要的一步。我们将通过具体示例&#xff0c;展示如何使用Pandas中的 .str.split() 函数来对数据集中的字符串进行分割&…

关于文件上传失败问题的排查思路

问题场景&#xff1a; 最近公司的app有很多用户反馈上传文件失败了。业务路径就是简单的app前端调用后端文件上传接口&#xff0c;所以发生上传失败的可能因素可能是&#xff1a;1、文件大小/文件类型等是否有问题&#xff0c;公司用的是七牛的文件服务器&#xff0c;对文件上…

纷享销客BI智能分析平台常见问题QA

Q1在驾驶舱中查看图表时&#xff0c;图表间有什么动态交互吗? A&#xff1a;驾驶舱支持图表本身下钻&#xff0c;图表间联动&#xff0c;并且支持图表下钻的同时联动&#xff0c;可以基于驾驶舱的这个功能&#xff0c;实现图表间的动态交互。 Q2基于客户主题创建的统计图&…

PSO-LSSVM-Adaboost分类模型,粒子群算法优化基于最小二乘支持向量机结合Adaboost的数据分类-附代码

PSO-LSSVM-Adaboost是一种结合PSO-LSSVM和AdaBoost两种机器学习技术的方法&#xff0c;旨在提升模型的性能和鲁棒性。具体来说&#xff0c;AdaBoost是一种集成学习方法&#xff0c;通过组合多个弱分类器来形成一个强分类器&#xff0c;每个分类器针对不同的数据集和特征进行训练…

人脸识别——OpenCV

人脸识别 创建窗口创建按钮设置字体定义标签用于显示图片选择并显示图片检测图片中的人脸退出程序返回主界面 创建窗口 导入tkinter库&#xff0c;创建窗口&#xff0c;设置窗口标题和窗口大小。 import tkinter as tkwin tk.Tk() win.title("人脸识别") win.geom…