STM32學習和實踐筆記(32):電容觸摸按鍵實驗

1.電容觸摸按鍵原理介紹

? 觸摸按鍵與傳統的機械按鍵相比,不僅美觀而且耐用、壽命長,它顛覆了傳統意義上的機械按鍵控制,只要輕輕觸摸,就可以實現按鍵開關的控制、量化調節甚至方向控制。觸摸按鍵已廣泛應用于手機、DVD、洗衣機等消費類電子產品中。本章我們就介紹一種簡單的觸摸按鍵:電容式觸摸按鍵。

我們PZ6806D開發板上的電容觸摸按鍵其實就是一小塊覆銅區域,也稱之為觸摸感應區。

? 通常我們會將四周的銅片與電路板地信號連通,觸摸感應區設計成方便手指觸摸大小,并將其連接在輸入捕獲通道上。??

觸摸感應區與四周的銅片區域就形成了一個電容,通過檢測電容充放

電時間即可判斷是否有觸摸。實現原理

電容充放電公式:Vc=V0*(1-e^(-t/RC))

在上圖中,R是外接電阻,開關就是STM32管腳的內部開關。CS是觸摸感應區與電路板GND之間的雜散電容。當手指按到觸摸區時,等于增加了一個CX電容并到CS上,所以電源通過RC對電容的充電時間就會變長。

本實驗中,使用TIM5的通道2(PA1管腳)來檢測觸摸按鍵是否按下。具體步驟是:

1)在每次檢測前,我們需要先將電容Cs(或 Cs+Cx)放電,即配置PA1引腳為推挽輸出模式,輸出一個低電平,才能使電容放電。這等效于上圖中的開關閉合。

2)然后配置PA1 為浮空輸入模式,利用外部上拉電阻給電容 Cs(Cs+Cx)充電,同時開啟TIM5_CH2的輸入捕獲,配置極性為上升沿,當檢測到上升沿的時候,就認為電容充電完

成了,完成一次捕獲檢測? 每次系統重啟時,我們執行一次捕獲檢測(可認為沒有觸摸),記錄此時捕獲到上升沿時,需要多少時間即TCS的值。

3)在后續的捕獲檢測中,即不斷重復上面的第1步和第2步,我們就可以通過與記錄的值進行對比,判斷是否發生觸摸。很明顯,如果沒有發生觸摸,每次捕獲發生的時間是基本上相等的,如果有觸摸,那么時間必然明顯延長。這樣,就知道了是否發生觸摸了

這就是電容觸摸工作的原理!搞清楚了就很簡單。

2.編寫電容觸摸按鍵控制程序

? 本實驗所要實現的功能是:通過TIM5的通道2(PA1)捕獲電容觸摸按鍵輸入信號的高電平脈寬,根據捕獲到的高電平時間長短,來判斷是否有按鍵按下,如果有按下,則翻轉D2指示燈的狀態以提示檢測到了一次按下。同時D1指示燈不斷閃爍表示系統正常運行。程序框架如下:

(1)初始化PA1管腳為TIM5通道2輸入捕獲功能,設置上升沿捕獲等

(2)讀取一次捕獲高電平的值

(3)電容觸摸按鍵初始化

(4)檢測電容觸摸按鍵是否按下

(5)編寫主函數

main.c

#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "usart.h"
#include "input.h"
#include "touch_key.h"int main()
{u8 i=0;SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中斷優先級分組LED_Init();USART1_Init(9600);Touch_Key_Init(6);//72M 6分頻后12Mwhile(1){if((Touch_Key_Scan(0)==1))//判斷觸摸是否有效{led2=led2;//有效則翻轉指示燈}i++;if(i%20 ==0){led1=!led1;//LED1閃,用來指示主程序循環是否運行}delay_ms(50);}
}

touch_key.c

#include "touch_key.h"
#include "SysTick.h"
#include "usart.h"#define Touch_ARR_MAX_Value 0xffff
u16 touch_default_value =0;void TIM5_CH2_Input_Init(u16 period,u16 prescaler)
{GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//結構體變量聲明TIM_ICInitTypeDef TIM_ICInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5時鐘GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	//GPIO_Init(GPIOA,&GPIO_InitStructure);TIM_TimeBaseInitStructure.TIM_Period=period;   //裝入函數傳過來的自動裝載值TIM_TimeBaseInitStructure.TIM_Prescaler=prescaler; //裝入函數傳過來的分頻系數TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//1分頻(沒有分頻)TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //設置向上計數模式:從0開始計數到自動重載值后溢出產生中斷TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);//初始化TIM5各參數:自動重裝值、分頻系統、計數方式等TIM_ICInitStructure.TIM_Channel=TIM_Channel_2; //通道2TIM_ICInitStructure.TIM_ICFilter=0x00; //無濾波TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕獲極性設為上升沿TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分頻系數TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1TIM_ICInit(TIM5,&TIM_ICInitStructure);TIM_Cmd(TIM5,ENABLE );//使能定時器}void Touch_Reset()
{GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//先設為輸出模式以方便輸出低電平GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	//GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_ResetBits(GPIOA,GPIO_Pin_1);//將IO口輸出低電平以將觸摸按鍵的電容放電delay_ms(5);TIM_ClearFlag(TIM5,TIM_FLAG_Update|TIM_FLAG_CC2);//清除定時器的狀態標志TIM_SetCounter(TIM5,0); //設定定時器初值為0以重新計數GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//重新改為浮空模式以對電容充電GPIO_Init(GPIOA,&GPIO_InitStructure);}u16 Touch_Get_Value()
{Touch_Reset();while(TIM_GetFlagStatus(TIM5,TIM_FLAG_CC2)==0)//{if(TIM_GetCounter(TIM5)>Touch_ARR_MAX_Value-500){return TIM_GetCounter(TIM5);//如果沒有發生捕獲事件,計數器計到最大值-500后返回當前計數器的值}}return TIM_GetCapture2(TIM5);//如果發生了捕獲事件,則返回捕獲發生時的計數器值}u8 Touch_Key_Init(u8 psc)
{u8 i,j;u16 buf[10];u16 temp;TIM5_CH2_Input_Init(Touch_ARR_MAX_Value,psc);//定時器5通道2輸入捕獲初始化for (i=0; i<10;i++){buf[i]= Touch_Get_Value();//得到10個值delay_ms(10);}//將得到的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;}}//去掉最小的兩個,去掉最大的兩個,余下的6個取平均值temp=0;for(i=2; i<8;i++){temp+=buf[i];}touch_default_value = temp/6;printf("touch_default_value=%d\r\n",touch_default_value);if(touch_default_value>touch_default_value/2)//這個判斷條件是通過實際調試測試決定的return 1;//如果這個值大于最大值的一半,也就對應前面的沒有發生捕獲的情況,那么認為初始化失敗//返回1 表明初始化失敗return 0; //返回0表示初始化成功,得到了沒有觸摸時的缺省充電時間}u16 Touch_Get_MaxVal(u8 n)//得到n次捕獲中的最大值
{u16 temp=0;u16 max=0;while(n--){temp=Touch_Get_Value();if(temp>max)max=temp;}return max;}//mode =0 單次掃描,mode =1,連續掃描
//返回Touch_Status,其值為1則表示觸摸有效
#define TOUCH_GATE_VAL 100
u8 Touch_Key_Scan(u8 mode)
{u8 Touch_Status;u8 sample =3;u16 MaxVal =0;static u8 keyen =0;if(mode)//mode如為1,則表示連續掃描,因此,每次調用Touch_Key_Scan時都將keyen=0,所以每次都能得到觸摸值{				//反之,因為keyen后續=3,所以需要三次之后,才能降為0,才能得到觸摸值sample =6;keyen=0;}MaxVal=Touch_Get_MaxVal(sample);//得到三次采樣中的最大值if(MaxVal>(touch_default_value+TOUCH_GATE_VAL)&&MaxVal<(10*touch_default_value)){if((keyen==0)&&(touch_default_value+TOUCH_GATE_VAL)){Touch_Status=1;}}printf("觸摸后捕獲高電平值為:%d\r\n",MaxVal);keyen=3;if(keyen) keyen--;return Touch_Status;}

? ?touch_key.h

#ifndef _touch_key_H
#define _touch_key_H#include "system.h"void TIM5_CH2_Input_Init(u16 period,u16 prescaler);
u8 Touch_Key_Init(u8 psc);
u8 Touch_Key_Scan(u8 mode);#endif

這個程序因為只能在PZ6806D開發板上才可以運行,而我手上的是PZ6806L,所以沒有實際燒錄測試,但原理我是完全理解的。

因此,如果在PZ6806L上接出一塊小的觸摸板,這實驗是可以做成功的,這沒有什么疑問。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20004.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20004.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20004.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

宿舍管理系統帶文檔java項目基于springboot+vue的宿舍管理系統

文章目錄 宿舍管理系統一、項目演示二、項目介紹三、八千字項目文檔四、部分功能截圖五、部分代碼展示六、底部獲取項目源碼和8000字論文參考&#xff08;9.9&#xffe5;帶走&#xff09; 宿舍管理系統 一、項目演示 宿舍管理系統 二、項目介紹 基于springbootvue的前后端分…

MVC、MVP 和 MVVM 架構總結

MVC、MVP 和 MVVM 是常見的軟件架構模式&#xff0c;主要用于組織應用程序的結構&#xff0c;特別是在用戶界面和業務邏輯之間進行分離。以下是對它們的詳細解釋&#xff0c;包括它們的差異、優缺點。 MVC&#xff08;Model-View-Controller&#xff09; 結構 Model&#xf…

C++的繼承(十一):私有繼承和受保護的繼承

但凡用過C的人都知道&#xff1a;私有繼承的成員在派生類里均為私有&#xff0c;受保護的繼承公有和受保護的成員在派生類里為受保護。另外C不對私有繼承和受保護的繼承的派生類指針自動轉化為基礎類。 #include <stdio.h> struct X {int a;X():a(9) {}int sqare() {ret…

5.nginx平滑升級

nginx平滑升級 一、nginx平滑升級1、下載新版本的安裝包2、以之前的安裝參數來編譯新版本軟件3、將新版本的nginx拷貝到安裝目錄4、啟動新版本進程5、平緩關閉舊工作進程6、清理舊版本的nginx 一、nginx平滑升級 USR2 啟動新版本進程 WINCH 平緩關閉舊工作進程 1、下載新版本…

分層注入的設計模式-上下層文件相互包含解決辦法

現象&#xff1a;上下層文件相互包含 寫代碼時&#xff0c;會不會遇到&#xff0c;業務層內容要在底層硬件程序里寫&#xff0c; 例如&#xff1a;一個外部按鍵&#xff0c;按鍵中斷要觸發一個應用層業務。 業務就要寫道IO中斷里&#xff0c;這個代碼就要用到上層一些函數和變…

在長窗口時代,RAG技術是否仍然必要?

自從谷歌推出 Gemini 1.5 Pro&#xff0c;行業內部對于 RAG 的討論就不絕于耳。 Gemini 1.5 Pro 的性能確實令人矚目。根據谷歌公布的技術文檔&#xff0c;該系統能夠穩定處理長達 100 token 的內容&#xff0c;相當于一小時的視頻、十一小時的音頻、超過三萬行的代碼或七十萬…

【VTKExamples::Utilities】第十七期 ZBuffer

很高興在雪易的CSDN遇見你 VTK技術愛好者 QQ:870202403 公眾號:VTK忠粉 前言 本文分享VTK樣例ZBuffer,并解析接口vtkWindowToImageFilter,希望對各位小伙伴有所幫助! 感謝各位小伙伴的點贊+關注,小易會繼續努力分享,一起進步! 你的點贊就是我的動力(^U^)ノ…

24 _ 分層和合成機制:為什么CSS動畫比JavaScript高效?

在上一篇文章中我們分析了CSS和JavaScript是如何影響到DOM樹生成的&#xff0c;今天我們繼續沿著渲染流水線向下分析&#xff0c;來聊聊DOM樹之后所發生的事情。 在前面《05 | 渲染流程&#xff08;上&#xff09;&#xff1a;HTML、CSS和JavaScript文件&#xff0c;是如何變成…

linux下can-utils的使用以及can接口的配置(以ubuntu20.04為例)

linux下can-utils的使用以及can接口的配置&#xff08;以ubuntu20.04為例&#xff09; can-utils是什么 can-utils 是一套用于Linux操作系統的開源工具&#xff0c;專門用來處理與CAN&#xff08;Controller Area Network&#xff09;總線相關的任務。CAN總線廣泛應用于汽車和…

C語言文件操作:打開關閉,讀寫

程序文件 源程序文件&#xff08;后綴為.c&#xff09; 目標文件&#xff08;Windows環境后綴為.obj&#xff09; 可執行文件&#xff08;Windows環境后綴為.exe&#xff09; fputc FILE* pf fopen("test.txt","w");if (pf NULL){printf("%s\n"…

深入理解Qt計算器應用的構建過程

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、數字按鈕的信號與槽函數連接 二、運算符按鈕的信號與槽函數連接 三、特殊按鈕的信號與…

紅外超聲波雷達測距(water)

文章目錄 一 RS-232二 RS485三 Modbus四 stm32多路超聲波測距4.1 設計方案4.2 代碼 參考資料總結 實驗要求 一. 采用stm32F103和HC-SR04超聲波模塊&#xff0c; 使用標準庫或HAL庫 定時器中斷&#xff0c;完成1或2路的超聲波障礙物測距功能。 1&#xff09;測試數據包含噪聲&am…

Bezier Python 用法:深入探索與實用指南

Bezier Python 用法&#xff1a;深入探索與實用指南 在數字圖形學和計算機編程中&#xff0c;貝塞爾曲線&#xff08;Bezier Curves&#xff09;是一種重要的參數曲線&#xff0c;被廣泛應用于二維圖形應用程序中&#xff0c;如字體輪廓、矢量圖形和動畫等。Python作為一種功能…

EukRep:區分真核和原核序列

https://github.com/patrickwest/EukRep 安裝 conda create -y -n eukrep-env -c bioconda scikit-learn0.19.2 eukrep mamba install -c conda-forge numpy1.19.5 使用 EukRep -i <Sequences in Fasta format> -o <Eukaryote sequence output fasta file>

【Linux】線程ID

大致草稿—————————— 思維導圖 學習目標 一、線程ID的理解 1.1 引出對tid的理解 我們先來創建一個線程復習一下線程的函數&#xff1a; pthread_t tid; // 創建一個線程 pthread_create(&tid, nullptr, threadrun, (void*)"thread-1"); // 打印出…

二分查找學習:優雅的二分查找——“Leetcode 35. 搜索插入位置”

例題 給定一個排序數組和一個目標值&#xff0c;在數組中找到目標值&#xff0c;并返回其索引。如果目標值不存在于數組中&#xff0c;返回它將會被按順序插入的位置。 請必須使用時間復雜度為 O(log n) 的算法。 示例 1: 輸入: nums [1,3,5,6], target 5 輸出: 2 示例 2…

怎么花草識別?方法有三種!

怎么花草識別&#xff1f;在這個五彩斑斕的世界里&#xff0c;花草是我們生活中不可或缺的一部分。它們點綴著我們的環境&#xff0c;為我們帶來無盡的美麗與驚喜。然而&#xff0c;面對眾多的花草種類&#xff0c;你是否曾感到困惑和迷茫&#xff0c;不知道如何識別它們&#…

VIO System 丨適用于控制器開發前期的測試系統

VIO綜述 嵌入式軟件的HIL測試需要復雜的測試系統及完整的ECU硬件&#xff0c;這導致通常只能在開發流程的后期階段進行測試。全新推出的低成本解決方案VIO System&#xff0c;使得在開發前期不僅可以進行總線通訊測試&#xff0c;也可以同時進行I/O信號測試。 該系統旨在通過…

用 Vim 打造舒適高效的編程體驗

作為程序員,Vim 無疑是最常使用的編輯器之一。它之所以如此受歡迎,得益于其強大的功能和高度可定制的特性。今天,讓我帶大家一起探索如何通過簡單的 .vimrc 配置,打造一個個性化的 Vim 編程環境。 啟用語法高亮 我們首先要確保 Vim 能夠正確地識別和高亮代碼語法。只需在 .vi…

LabVIEW版本控制

LabVIEW作為一種流行的圖形化編程環境&#xff0c;在軟件開發中廣泛應用。有效地管理版本控制對于確保軟件的可靠性和可維護性至關重要。LabVIEW提供了多種方式來管理VI和應用程序的修訂歷史&#xff0c;以滿足不同規模和復雜度的項目需求。 LabVIEW中的VI修訂歷史 LabVIEW內置…