日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

正点原子stm32f429 pcb_正点原子【STM32-F407探索者】第十六章 电容触摸按键实验

發布時間:2025/3/21 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 正点原子stm32f429 pcb_正点原子【STM32-F407探索者】第十六章 电容触摸按键实验 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1)資料下載:點擊資料即可下載

2)對正點原子Linux感興趣的同學可以加群討論:935446741

3)關注正點原子公眾號,獲取最新資料更新

http://weixin.qq.com/r/hEhUTLbEdesKrfIv9x2W (二維碼自動識別)

上一章,我們介紹了 STM32F4 的輸入捕獲功能及其使用。這一章,我們將向大家介紹如

何通過輸入捕獲功能,來做一個電容觸摸按鍵。在本章中,我們將用 TIM2 的通道 1(PA5)來

做輸入捕獲,并實現一個簡單的電容觸摸按鍵,通過該按鍵控制 DS1 的亮滅。從本章分為如下

幾個部分:

16.1 電容觸摸按鍵簡介

16.2 硬件設計

16.3 軟件設計

16.4 下載驗證

16.1 電容觸摸按鍵簡介

觸摸按鍵相對于傳統的機械按鍵有壽命長、占用空間少、易于操作等諸多優點。大家看看

如今的手機,觸摸屏、觸摸按鍵大行其道,而傳統的機械按鍵,正在逐步從手機上面消失。本

章,我們將給大家介紹一種簡單的觸摸按鍵:電容式觸摸按鍵。

我們將利用探索者 STM32F4 開發板上的觸摸按鍵(TPAD),來實現對 DS1 的亮滅控制。

這里 TPAD 其實就是探索者 STM32F4 開發板上的一小塊覆銅區域,實現原理如圖 16.1.1 所示:

圖 16.1.1 電容觸摸按鍵原理

這里我們使用的是檢測電容充放電時間的方法來判斷是否有觸摸,圖中 R 是外接的電容充

電電阻,Cs 是沒有觸摸按下時 TPAD 與 PCB 之間的雜散電容。而 Cx 則是有手指按下的時候,

手指與 TPAD 之間形成的電容。圖中的開關是電容放電開關(由實際使用時,由 STM32F4 的

IO 代替)。

先用開關將 Cs(或 Cs+Cx)上的電放盡,然后斷開開關,讓 R 給 Cs(或 Cs+Cx)充電,

當沒有手指觸摸的時候,Cs 的充電曲線如圖中的 A 曲線。而當有手指觸摸的時候,手指和 TPAD

之間引入了新的電容 Cx,此時 Cs+Cx 的充電曲線如圖中的 B 曲線。從上圖可以看出,A、B

兩種情況下,Vc 達到 Vth 的時間分別為 Tcs 和 Tcs+Tcx。

其中,除了 Cs 和 Cx 我們需要計算,其他都是已知的,根據電容充放電公式:

Vc=V0*(1-e^(-t/RC))

其中 Vc 為電容電壓,V0 為充電電壓,R 為充電電阻,C 為電容容值,e 為自然底數,t 為

充電時間。根據這個公式,我們就可以計算出 Cs 和 Cx。利用這個公式,我們還可以把探索者

開發板作為一個簡單的電容計,直接可以測電容容量了,有興趣的朋友可以搗鼓下。

在本章中,其實我們只要能夠區分 Tcs 和 Tcs+Tcx,就已經可以實現觸摸檢測了,當充電時間在 Tcs 附近,就可以認為沒有觸摸,而當充電時間大于 Tcs+Tx 時,就認為有觸摸按下(Tx

為檢測閥值)。

本章,我們使用 PA5(TIM2_CH1)來檢測 TPAD 是否有觸摸,在每次檢測之前,我們先配置

PA5 為推挽輸出,將電容 Cs(或 Cs+Cx)放電,然后配置 PA5 為浮空輸入,利用外部上拉電阻

給電容 Cs(Cs+Cx)充電,同時開啟 TIM2_CH1 的輸入捕獲,檢測上升沿,當檢測到上升沿的時

候,就認為電容充電完成了,完成一次捕獲檢測。

在 MCU 每次復位重啟的時候,我們執行一次捕獲檢測(可以認為沒觸摸),記錄此時的值,

記為 tpad_default_val,作為判斷的依據。在后續的捕獲檢測,我們就通過與 tpad_default_val 的

對比,來判斷是不是有觸摸發生。

關于輸入捕獲的配置,在上一章我們已經有詳細介紹了,這里我們就不再介紹。至此,電

容觸摸按鍵的原理介紹完畢。

16.2 硬件設計

本實驗用到的硬件資源有:

1) 指示燈 DS0 和 DS1

2) 定時器 TIM2

3) 觸摸按鍵 TPAD

前面兩個之前均有介紹,我們需要通過 TIM2_CH1(PA5)采集 TPAD 的信號,所以本實

驗需要用跳線帽短接多功能端口(P12)的 TPAD 和 ADC,以實現 TPAD 連接到 PA5。如圖 16.2.1

所示:

圖 16.2.1 TPAD 與 STM32F4 連接原理圖

硬件設置(用跳線帽短接多功能端口的 ADC 和 TPAD 即可)好之后,下面我們開始軟件

設計。

16.3 軟件設計

軟件設計方面,相比上一實驗,我們刪掉了timer.c和timer.h文件,同時新建了tpad.c和tpad.h

文件。因為 tpad 我們也是使用的定時器輸入捕獲來實現,所以我們相比上個實驗并沒有增加任

何庫函數相關的文件。

接下來我們看看 tpad.c 文件代碼:

#include "tpad.h"

#include "delay.h"

#include "usart.h"

TIM_HandleTypeDef TIM2_Handler; //定時器 2 句柄

#define TPAD_ARR_MAX_VAL 0XFFFFFFFF //最大的 ARR 值(TIM2 是 32 位定時器)

vu16 tpad_default_val=0;

//空載的時候(沒有手按下),計數器需要的時間

//初始化觸摸按鍵

//獲得空載的時候觸摸按鍵的取值.

//psc:分頻系數,越小,靈敏度越高.

//返回值:0,初始化成功;1,初始化失敗

u8 TPAD_Init(u8 psc)

{

u16 buf[10];

u16 temp;

u8 j,i;

TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//設置分頻系數

for(i=0;i<10;i++)//連續讀取 10 次

{

buf[i]=TPAD_Get_Val();

delay_ms(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];//取中間的 8 個數據進行平均

tpad_default_val=temp/6;

printf("tpad_default_val:%drn",tpad_default_val);

if(tpad_default_val>(vu16)TPAD_ARR_MAX_VAL/2)return 1;

//初始化遇到超過 TPAD_ARR_MAX_VAL/2 的數值,不正常!

return 0;

}

//復位一次

//釋放電容電量,并清除定時器的計數值

void TPAD_Reset(void)

{

GPIO_InitTypeDef GPIO_Initure;

GPIO_Initure.Pin=GPIO_PIN_5; //PA5

GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出

GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉

GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速

HAL_GPIO_Init(GPIOA,&GPIO_Initure);

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); //PA5 輸出 0,放電

delay_ms(5);

__HAL_TIM_CLEAR_FLAG(&TIM2_Handler,TIM_FLAG_CC1|

TIM_FLAG_UPDATE);

//清除標志位

__HAL_TIM_SET_COUNTER(&TIM2_Handler,0);

//計數器值歸 0

GPIO_Initure.Mode=GPIO_MODE_AF_PP;

//推挽復用

GPIO_Initure.Pull=GPIO_NOPULL;

//不帶上下拉

GPIO_Initure.Alternate=GPIO_AF1_TIM2;

//PA5 復用為 TIM2 通道 1

HAL_GPIO_Init(GPIOA,&GPIO_Initure);

}

//得到定時器捕獲值

//如果超時,則直接返回定時器的計數值.

//返回值:捕獲值/計數值(超時的情況下返回)

u16 TPAD_Get_Val(void)

{

TPAD_Reset();

while(__HAL_TIM_GET_FLAG(&TIM2_Handler,TIM_FLAG_CC1)==RESET)

//等待捕獲上升沿

{

if(__HAL_TIM_GET_COUNTER(&TIM2_Handler)>TPAD_ARR_MAX_VAL-

500)

return __HAL_TIM_GET_COUNTER(&TIM2_Handler);

//超時了,直接返回 CNT 的值

};

return HAL_TIM_ReadCapturedValue(&TIM2_Handler,TIM_CHANNEL_1);

}

//讀取 n 次,取最大值

//n:連續獲取的次數

//返回值:n 次讀數里面讀到的最大讀數值

u16 TPAD_Get_MaxVal(u8 n)

{

u16 temp=0;

u16 res=0;

u8 lcntnum=n*2/3;//至少 2/3*n 的有效個觸摸,才算有效

u8 okcnt=0;

while(n--)

{

temp=TPAD_Get_Val();//得到一次值

if(temp>(tpad_default_val*5/4))okcnt++;//至少大于默認值的 5/4 才算有效

if(temp>res)res=temp;

}

if(okcnt>=lcntnum)return res;//至少 2/3 的概率,要大于默認值的 5/4 才算有效

else return 0;

}

//掃描觸摸按鍵

//mode:0,不支持連續觸發(按下一次必須松開才能按下一次);

//1,支持連續觸發(可以一直按下)

//返回值:0,沒有按下;1,有按下;

u8 TPAD_Scan(u8 mode)

{

static u8 keyen=0; //0,可以開始檢測;>0,還不能開始檢測

u8 res=0;

u8 sample=3; //默認采樣次數為 3 次

u16 rval;

if(mode)

{

sample=6;

//支持連按的時候,設置采樣次數為 6 次

keyen=0; //支持連按

}

rval=TPAD_Get_MaxVal(sample);

if(rval>(tpad_default_val*4/3)&&rval<(10*tpad_default_val))

//大于 tpad_default_val+(1/3)*tpad_default_val,且小于 10 倍 tpad_default_val,則有效

{

if(keyen==0)res=1; //keyen==0,有效

//printf("r:%drn",rval);

keyen=3;

//至少要再過 3 次之后才能按鍵有效

}

if(keyen)keyen--;

return res;

}

//定時器 2 通道 1 輸入捕獲配置

//arr:自動重裝值(TIM2 是 32 位的!!)

//psc:時鐘預分頻數

void TIM2_CH1_Cap_Init(u32 arr,u16 psc)

{

TIM_IC_InitTypeDef TIM2_CH1Config;

TIM2_Handler.Instance=TIM2;

//通用定時器 3

TIM2_Handler.Init.Prescaler=psc;

//分頻

TIM2_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;

//向上計數器

TIM2_Handler.Init.Period=arr;

//自動裝載值

TIM2_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;

HAL_TIM_IC_Init(&TIM2_Handler);

TIM2_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING;

//上升沿捕獲

TIM2_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//映射到 TI1 上

TIM2_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //配置輸入分頻,不分頻

TIM2_CH1Config.ICFilter=0; //配置輸入濾波器,不濾波

HAL_TIM_IC_ConfigChannel(&TIM2_Handler,&TIM2_CH1Config,

TIM_CHANNEL_1);//配置 TIM2 通道 1

HAL_TIM_IC_Start(&TIM2_Handler,TIM_CHANNEL_1); //開始捕獲 TIM2 的通道 1

}

//定時器 2 底層驅動,時鐘使能,引腳配置

//此函數會被 HAL_TIM_IC_Init()調用

//htim:定時器 2 句柄

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)

{

GPIO_InitTypeDef GPIO_Initure;

__HAL_RCC_TIM2_CLK_ENABLE();

//使能 TIM2 時鐘

__HAL_RCC_GPIOA_CLK_ENABLE();

//開啟 GPIOA 時鐘

GPIO_Initure.Pin=GPIO_PIN_5;

//PA5

GPIO_Initure.Mode=GPIO_MODE_AF_PP;

//推挽復用

GPIO_Initure.Pull=GPIO_NOPULL; //不帶上下拉

GPIO_Initure.Speed=GPIO_SPEED_HIGH;

//高速

GPIO_Initure.Alternate=GPIO_AF1_TIM2;

//PA5 復用為 TIM2 通道 1

HAL_GPIO_Init(GPIOA,&GPIO_Initure);

}

函數TIM2_CH1_Cap_Init和上一章輸入捕獲實驗中函數TIM5_CH1_Cap_Init的配置過程幾

乎是一模一樣的,不同的是上一章實驗開 TIM5_CH1_Cap_Init 函數最后調用的是函數

HAL_TIM_IC_Start_IT,使能輸入捕獲通道的同事開啟了輸入捕獲中斷,而該函數最后調用的

函數是 HAL_TIM_IC_Start,只是開啟了輸入捕獲通道,并沒有開啟輸入捕獲中斷。

函數 HAL_TIM_IC_MspInit 是輸入捕獲通用 MSP 回調函數,該函數的作用是使能定時器

和 GPIO 時鐘,配置 GPIO 復用映射關系。該函數功能和輸入捕獲實驗中該函數作用基本類似。

函數 TPAD_Get_Val 用于得到定時器的一次捕獲值。該函數先調用 TPAD_Reset,將電容放

電,同時設置通過程序__HAL_TIM_SET_COUNTER(&TIM2_Handler,0)將計數值 TIM2_CNT 設

置為 0,然后死循環等待發生上升沿捕獲(或計數溢出),將捕獲到的值(或溢出值)作為返回

值返回。

函數 TPAD_Init 用于初始化輸入捕獲,并獲取默認的 TPAD 值。該函數有一個參數,用來

傳遞分頻系數,其實是為了配置 TIM2_CH1_Cap_Init 的計數周期。在該函數中連續 10 次讀取

TPAD 值,將這些值升序排列后取中間 6 個值再做平均(這樣做的目的是盡量減少誤差),并賦

值給 tpad_default_val,用于后續觸摸判斷的標準。

函數 TPAD_Scan 用于掃描 TPAD 是否有觸摸,該函數的參數 mode,用于設置是否支持連

續觸發。返回值如果是 0,說明沒有觸摸,如果是 1,則說明有觸摸。該函數同樣包含了一個靜

態變量,用于檢測控制,類似第七章的 KEY_Scan 函數。所以該函數同樣是不可重入的。在函

數中,我們通過連續讀取 3 次(不支持連續按的時候)TPAD 的值,取最大值和 tpad_default_val*4/3

比較,如果大于則說明有觸摸,如果小于,則說明無觸摸。其中 tpad_default_val 是我們在調用

TPAD_Init 函數的時候得到的值,然后取其 4/3 為門限值。該函數,我們還做了一些其他的條件

限制,讓觸摸按鍵有更好的效果,這個就請大家看代碼自行參悟了。

函數 TPAD_Reset 顧名思義,是進行一次復位操作。先設置 PA5 輸出低電平,電容放電,

同時清除中斷標志位并且計數器值清零,然后配置 PA5 為復用功能浮空輸入,利用外部上拉電

阻給電容 Cs(Cs+Cx)充電,同時開啟 TIM2_CH1 的輸入捕獲。

函數 TPAD_Get_MaxVal 就非常簡單了,它通過 n 次調用函數 TPAD_Get_Val 采集捕獲值,

然后進行比較后獲取 n 次采集值中的最大值。

tpad.h 頭文件部分代碼比較簡單,這里不做介紹。

接下來我們看看主函數代碼如下:

int main(void)

{

u8 t=0;

HAL_Init(); //初始化 HAL 庫

Stm32_Clock_Init(336,8,2,7); //設置時鐘,168Mhz

delay_init(168); //初始化延時函數

uart_init(115200); //初始化 USART

LED_Init();

//初始化 LED

TPAD_Init(8); //初始化觸摸按鍵

while(1)

{

if(TPAD_Scan(0)) //成功捕獲到了一次上升沿(此函數執行時間至少 15ms)

{

LED1=!LED1;

//LED1 取反

}

t++;

if(t==15)

{

t=0; LED0=!LED0;

//LED0 取反,提示程序正在運行

}

delay_ms(10);

}

}

該 main 函數比較簡單,TPAD_Init(8)函數執行之后,就開始觸摸按鍵的掃描,當有觸摸的

時候,對 DS1 取反,而 DS0 則有規律的間隔取反,提示程序正在運行。注意在修改 main 函數

之后,還需要在 main.c 里面添加 tpad.h 頭文件,否則會報錯哦。

這里還要提醒一下大家,不要把 uart_init(115200);去掉,因為在 TPAD_Init 函數里面,我們

有用到 printf,如果你去掉了 uart_init,就會導致 printf 無法執行,從而死機。

至此,我們的軟件設計就完成了。

16.4 下載驗證

在完成軟件設計之后,將我們將編譯好的文件下載到探索者 STM32F4 開發板上,可以看

到 DS0 慢速閃爍,此時,我們用手指觸摸 ALIENTEK 探索者 STM32F4 開發板上的 TPAD(右

下角的白色頭像),就可以控制 DS1 的亮滅了。不過你要確保 TPAD 和 ADC 的跳線帽連接上了

哦!如圖 16.4.1 所示:

圖 16.4.1 觸摸區域和跳線帽短接方式示意圖

同時大家可以打開串口調試助手,每次復位的時候,會收到 tpad_default_val 的值,一般為

250 左右。

總結

以上是生活随笔為你收集整理的正点原子stm32f429 pcb_正点原子【STM32-F407探索者】第十六章 电容触摸按键实验的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: www.com在线观看| 欧美韩一区二区 | 用力挺进新婚白嫩少妇 | 国内视频自拍 | 男女那个视频 | 国产人成免费视频 | 瑟瑟av | 久操精品视频 | 一本色道久久综合亚洲二区三区 | 北条麻妃在线一区二区 | a视频在线| 亚洲精品高清在线 | 在线免费看av片 | 国产精品福利电影 | 在线免费观看av网 | 欧美福利在线 | 精品一区二区在线视频 | 男女做爰猛烈高潮描写 | 男人和女人插插 | 99免费在线观看 | 好姑娘在线观看高清完整版电影 | 优优色综合 | 亚洲精品久久久久中文字幕二区 | 性生生活大片又黄又 | 色亚洲欧美 | 成年人福利网站 | 天天插天天操天天干 | 久青草视频在线观看 | 日韩免费一区二区三区 | 国产成人毛毛毛片 | 欧美日韩免费做爰视频 | 一区二区三区久久久久 | 日韩一区二区三区四区 | 日本一区免费 | 特级西西人体444www高清 | 丝袜在线一区 | 国产乱淫av片免费 | 中文字幕乱码免费 | 香蕉手机网 | 日韩精品免费播放 | www.欧美色图| 日本黄色高清 | 聚色屋| 高清乱码免费 | 久热国产精品视频 | 免费激情视频网站 | 国产午夜精品久久久久久久 | 日韩一区欧美一区 | 亚洲影视在线 | 男人激烈吮乳吃奶爽文 | 日韩欧美中文字幕一区二区 | 色婷婷av一区二区三 | 国产情侣小视频 | 国产我不卡 | 三级视频在线看 | 国产第四页 | 国产精品sm调教免费专区 | 亚洲成av人片在线观看无码 | 少妇高潮久久久久久潘金莲 | 高清国产午夜精品久久久久久 | 五月婷婷六月综合 | 国产精品黄色 | 成人软件在线观看 | 色av色| 黑人3p波多野结衣在线观看 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲一区欧美一区 | 日韩激情视频在线观看 | 91爱国产| 深夜在线免费视频 | 香蕉久久av一区二区三区 | 性欧美丰满熟妇xxxx性仙踪林 | 国产高清免费在线观看 | youjizz自拍| 成人在线观看网 | 亚洲色图综合网 | 久久精品人人 | 亚洲中文字幕无码爆乳av | 亚洲图片另类小说 | 999久久久精品 | 亚洲激情午夜 | 在线视频污 | 卡一卡二av | 日日日噜噜噜 | 91打屁股| 久久性片| 亚洲熟女少妇一区二区 | 伊人影视网 | 国产精品熟妇一区二区三区四区 | 五月婷婷综合网 | 超碰520| 操日本女人 | 国产三级在线免费观看 | 日本在线视频免费 | 成人免费看毛片 | 夜夜导航 | av成人亚洲 | 久久久久久久久福利 | 日色网站 |