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); // 防止刷新过快}// 完成后标志位置0flag = 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{// 判断本次字符是不是\rif (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); // 0OLED_ShowCN(0, 2, 2);                   // 光OLED_ShowCN(16, 2, 3);                  // 照OLED_ShowStr(32, 2, (uint8_t *)":", 2); // :OLED_ShowStr(64, 2, (uint8_t *)"0", 2); // 0OLED_ShowCN(0, 4, 5);                   // 温OLED_ShowCN(16, 4, 6);                  // 度OLED_ShowStr(32, 4, (uint8_t *)":", 2); // :OLED_ShowStr(64, 4, (uint8_t *)"0", 2); // 0OLED_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.mzph.cn/pingmian/20908.shtml

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

相关文章

C语言编程训练图:解锁编程之路的迷宫与宝藏

C语言编程训练图&#xff1a;解锁编程之路的迷宫与宝藏 在编程的世界里&#xff0c;C语言如同一张错综复杂的训练图&#xff0c;它既是迷宫&#xff0c;也是宝藏图。只有那些勇敢而智慧的探险者&#xff0c;才能在其中找到通往编程大师的道路。本文将带领你一起探索这张神秘的…

Tika介绍

Apache Tika 是一个开源的Java库&#xff0c;用于检测和提取各种文件格式的内容。它能够识别超过1000种文件格式&#xff0c;并从中提取文本、元数据和结构化信息。Tika 是 Apache Software Foundation 的一个项目&#xff0c;它提供了一个简单的API&#xff0c;可以轻松地集成…

26 _ 虚拟DOM:虚拟DOM和实际的DOM有何不同?

虚拟DOM是最近非常火的技术&#xff0c;两大著名前端框架React和Vue都使用了虚拟DOM&#xff0c;所以我觉得非常有必要结合浏览器的工作机制对虚拟DOM进行一次分析。当然了&#xff0c;React和Vue框架本身所蕴含的知识点非常多&#xff0c;而且也不是我们专栏的重点&#xff0c…

VBA字典与数组第十五讲:多行多列数组与同列数单行数组间的运算规则

《VBA数组与字典方案》教程&#xff08;10144533&#xff09;是我推出的第三套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;字典是VBA的精华&#xff0c;我要求学员必学。7.1.3.9教程和手册掌握后&#xff0c;可以解决大多数工作中遇到的实际问题。…

C语言编程代码软件:深入探索与实战应用

C语言编程代码软件&#xff1a;深入探索与实战应用 在编程的广袤领域中&#xff0c;C语言以其独特的魅力吸引着无数编程爱好者。作为一种基础且强大的编程语言&#xff0c;C语言在软件开发、系统编程、嵌入式系统等领域发挥着不可替代的作用。而要想熟练掌握C语言&#xff0c;…

LabVIEW齿轮调制故障检测系统

LabVIEW齿轮调制故障检测系统 概述 开发了一种基于LabVIEW平台的齿轮调制故障检测系统&#xff0c;实现齿轮在恶劣工作条件下的故障振动信号的实时在线检测。系统利用LabVIEW的强大图形编程能力&#xff0c;结合Hilbert包络解调技术&#xff0c;对齿轮的振动信号进行精确分析…

Stream API实践,string转 List<Long>

需求背景: 有个工具接口要求入参是List&#xff0c;但我的数据是string (string ruleId"1234)。 可以通过创建一个List容器&#xff0c;再把元素转成Long添进去&#xff0c;但太繁琐了。而且后面如果要改成多个元素&#xff0c;还要加个遍历。 但用 stream API一行解决。具…

【手撕面试题】Vue(高频知识点三)

每天10道题&#xff0c;100天后&#xff0c;搞定所有前端面试的高频知识点&#xff0c;加油&#xff01;&#xff01;&#xff01;在看文章的同时&#xff0c;希望不要直接看答案&#xff0c;先思考一下自己会不会&#xff0c;如果会&#xff0c;自己的答案是什么&#xff1f;想…

55、试除法判定质数

试除法判定质数 题目描述 给定n个正整数ai&#xff0c;判定每个数是否是质数。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含一个正整数ai。 输出格式 共n行&#xff0c;其中第 i 行输出第 i 个正整数ai 是否为质数&#xff0c;是则输出“Yes”&#xff…

高考后的赚钱新路径:千行赏金助你开启财富之旅

一、兼职背景与需求 随着高考的落幕&#xff0c;众多学子迎来了人生中的一大转折点。在迈向大学校园的门槛之前&#xff0c;许多学生希望利用这段空闲时间做些兼职&#xff0c;既能够充实自己的暑假生活&#xff0c;又能为家庭减轻经济负担&#xff0c;甚至为自己积累一些宝贵…

基于django | 创建app,并启动django

1、删除系统默认的目录路径&#xff1a;BASE_DIR / templetes 2、在终端输入命令&#xff1a; python manage.py startapp app01 # 这里的app01是我创建app的名称 3、如果没有创建成功&#xff0c;手动点击 Creat App , 4、在 setting.py 中找到 INSTALLED_APPS ,添加 ap…

pycharm简易使用码云gitee

文章目录 参考文献官网地址安装插件第一个选项报错了不可&#xff0c;第二个选项&#xff0c;可以了新库上传到主分支&#xff0c;push改进实验新建分支&#xff0c;上传为新分支&#xff1a;做另一种改进&#xff0c;选择回退主分支&#xff0c;另建一个分支 使用对于一个新项…

非线性系统:相平面法

非线性系统&#xff1a;相平面法 非线性系统的相平面法是一种重要的分析工具&#xff0c;用于研究系统的动力学行为。通过相平面法&#xff0c;可以直观地观察系统状态变量的变化&#xff0c;分析系统的稳定性、周期性和其他动力学特性。本文将详细介绍相平面法的基本思想、步…

[NOIP2015 提高组] 子串

题目背景 NOIP2015 Day2T2 题目描述 有两个仅包含小写英文字母的字符串 A A A 和 B B B。 现在要从字符串 A A A 中取出 k k k 个互不重叠的非空子串&#xff0c;然后把这 k k k 个子串按照其在字符串 A A A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少…

Tree——输出项目的文件结构(Linux)

输出项目中的文件结构可以使用tree命令。tree是一个用于以树状结构显示目录内容的命令行工具。它非常适合快速查看项目的文件结构。安装&#xff1a; sudo apt-get install tree 使用&#xff1a; 在命令行中导航到项目的根目录&#xff0c;输出文件结构。 tree 也可以将结构输…

【30天精通Prometheus:一站式监控实战指南】第13天:graphite_exporter从入门到实战:安装、配置详解与生产环境搭建指南,超详细

亲爱的读者们&#x1f44b;   欢迎加入【30天精通Prometheus】专栏&#xff01;&#x1f4da; 在这里&#xff0c;我们将探索Prometheus的强大功能&#xff0c;并将其应用于实际监控中。这个专栏都将为你提供宝贵的实战经验。&#x1f680;   Prometheus是云原生和DevOps的…

网关(Gateway)- 自定义过滤器工厂

自定义过滤工厂类 DemoGatewayFilterFactory package com.learning.springcloud.custom;import org.apache.commons.lang.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChai…

Java 自定义异常

自定义异常 自定义异常的必要 Java中不同的异常类&#xff0c;分别表示着某一种具体的异常情况。那么在开发中总是有些异常情况是核心类库中没有定义好的&#xff0c;此时我们需要根据自己业务的异常情况来定义异常类。 自定义异常类 自定义异常类可以参照lang包中系统提供的异…

Vue3中的常见组件通信之props和自定义事件

Vue3中的常见组件通信 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs4. 默认…

第十二章 创建Web客户端

文章目录 第十二章 创建Web客户端SOAP向导的概述使用SOAP向导 第十二章 创建Web客户端 web客户端是访问web服务的软件。web客户端提供了一组代理方法&#xff0c;每个方法对应于web服务的一个方法。代理方法使用与它所对应的web服务方法相同的签名&#xff0c;并在被请求时调用…