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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

判断按键值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验...

發(fā)布時(shí)間:2023/12/1 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 判断按键值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1)實(shí)驗(yàn)平臺(tái):ALIENTEK NANO STM32F411 V1開發(fā)板2)摘自《正點(diǎn)原子STM32F4 開發(fā)指南(HAL 庫(kù)版》關(guān)注官方微信號(hào)公眾號(hào),獲取更多資料:正點(diǎn)原子

第十六章電容觸摸按鍵實(shí)驗(yàn)
上一章,我們介紹了 STM32F4 的輸入捕獲功能及其使用。這一章,我們將向大家介紹如
何通過輸入捕獲功能,來做一個(gè)電容觸摸按鍵。在本章中,我們將用 TIM3 的通道 4(PB1)來
做輸入捕獲,并實(shí)現(xiàn)一個(gè)簡(jiǎn)單的電容觸摸按鍵,通過該按鍵控制 DS5 的亮滅。從本章分為如下
幾個(gè)部分:
16.1 電容觸摸按鍵簡(jiǎn)介
16.2 硬件設(shè)計(jì)
16.3 軟件設(shè)計(jì)
16.4 下載驗(yàn)證16.1 電容觸摸按鍵簡(jiǎn)介
觸摸按鍵相對(duì)于傳統(tǒng)的機(jī)械按鍵有壽命長(zhǎng)、占用空間少、易于操作等諸多優(yōu)點(diǎn)。大家看看
如今的手機(jī),觸摸屏、觸摸按鍵大行其道,而傳統(tǒng)的機(jī)械按鍵,正在逐步從手機(jī)上面消失。本
章,我們將給大家介紹一種簡(jiǎn)單的觸摸按鍵:電容式觸摸按鍵。
我們將利用 NANO STM32 開發(fā)板上的觸摸按鍵(TPAD),來實(shí)現(xiàn)對(duì) DS5 的亮滅控制。這
里 TPAD 其實(shí)就是 NANO STM32 開發(fā)板上的一小塊覆銅區(qū)域,實(shí)現(xiàn)原理如圖 16.1.1 所示:

圖 16.1.1 電容觸摸按鍵原理
這里我們使用的是檢測(cè)電容充放電時(shí)間的方法來判斷是否有觸摸,圖中 R 是外接的電容充
電電阻,Cs 是沒有觸摸按下時(shí) TPAD 與 PCB 之間的雜散電容。而 Cx 則是有手指按下的時(shí)候,
手指與 TPAD 之間形成的電容。圖中的開關(guān)是電容放電開關(guān)(由實(shí)際使用時(shí),由 STM32 的 IO
代替)。
先用開關(guān)將 Cs(或 Cs+Cx)上的電放盡,然后斷開開關(guān),讓 R 給 Cs(或 Cs+Cx)充電,
當(dāng)沒有手指觸摸的時(shí)候,Cs 的充電曲線如圖中的 A 曲線。而當(dāng)有手指觸摸的時(shí)候,手指和 TPAD
之間引入了新的電容 Cx,此時(shí) Cs+Cx 的充電曲線如圖中的 B 曲線。從上圖可以看出,A、B
兩種情況下,Vc 達(dá)到 Vth 的時(shí)間分別為 Tcs 和 Tcs+Tcx。
其中,除了 Cs 和 Cx 我們需要計(jì)算,其他都是已知的,根據(jù)電容充放電公式:
Vc=V0*(1-e^(-t/RC))
其中 Vc 為電容電壓,V0 為充電電壓,R 為充電電阻,C 為電容容值,e 為自然底數(shù),t 為
充電時(shí)間。根據(jù)這個(gè)公式,我們就可以計(jì)算出 Cs 和 Cx。利用這個(gè)公式,我們還可以把戰(zhàn)艦開
發(fā)板作為一個(gè)簡(jiǎn)單的電容計(jì),直接可以測(cè)電容容量了,有興趣的朋友可以搗鼓下。
在本章中,其實(shí)我們只要能夠區(qū)分 Tcs 和 Tcs+Tcx,就已經(jīng)可以實(shí)現(xiàn)觸摸檢測(cè)了,當(dāng)充電
時(shí)間在 Tcs 附近,就可以認(rèn)為沒有觸摸,而當(dāng)充電時(shí)間大于 Tcs+Tx 時(shí),就認(rèn)為有觸摸按下(Tx
為檢測(cè)閥值)。
本章,我們使用 PB1(TIM3_CH4)來檢測(cè) TPAD 是否有觸摸,在每次檢測(cè)之前,我們先配置
PB1 為推挽輸出,將電容 Cs(或 Cs+Cx)放電,然后配置 PB1 為浮空輸入,利用外部上拉電
阻給電容 Cs(Cs+Cx)充電,同時(shí)開啟 TIM3_CH4 的輸入捕獲,檢測(cè)上升沿,當(dāng)檢測(cè)到上升沿的
時(shí)候,就認(rèn)為電容充電完成了,完成一次捕獲檢測(cè)。
在 MCU 每次復(fù)位重啟的時(shí)候,我們執(zhí)行一次捕獲檢測(cè)(可以認(rèn)為沒觸摸),記錄此時(shí)的
值,記為 tpad_default_val,作為判斷的依據(jù)。在后續(xù)的捕獲檢測(cè),我們就通過與 tpad_default_val
的對(duì)比,來判斷是不是有觸摸發(fā)生。
關(guān)于輸入捕獲的配置,在上一章我們已經(jīng)有詳細(xì)介紹了,這里我們就不再介紹。至此,電
容觸摸按鍵的原理介紹完畢。16.2 硬件設(shè)計(jì)
本實(shí)驗(yàn)用到的硬件資源有:
1) 指示燈 DS0 和 DS5
2) 定時(shí)器 TIM3
3) 觸摸按鍵 TPAD
前面兩個(gè)之前均有介紹,我們需要通過 TIM3_CH4(PB1)采集 TPAD 的信號(hào),所以本實(shí)
驗(yàn)需要用跳線帽短接多功能端口(P3)的 TPAD 和 ADC,以實(shí)現(xiàn) TPAD 連接到 PB1。如圖 16.2.1
所示:

圖 16.2.1 TPAD 與 STM32 連接原理圖
硬件設(shè)置(用跳線帽短接多功能端口的 ADC 和 TPAD 即可)好之后,下面我們開始軟件
設(shè)計(jì)。16.3 軟件設(shè)計(jì)
軟件設(shè)置我們?cè)谥暗霉こ躺厦嬖黾?#xff0c;由于本章我們用不到 timer.c,所以先刪除 timer.c。
然后再 HARDWARE 文件夾下新建 TPAD 得文件夾。然后打開 USER 文件夾下的工程,新建一
個(gè) tpad.c 的文件和 tpad.h 得頭文件,保存再 TPAD 文件夾下,并將 TPAD 文件夾加入頭文件包
含路徑。
我們?cè)?tpad.c 里輸入了如下代碼:
TIM_HandleTypeDef TIM3_Handler;
//定時(shí)器 3 句柄
#define TPAD_ARR_MAX_VAL 0XFFFF//最大的 ARR 值(TIM3 是 16 位定時(shí)器)
vu16 tpad_default_val=0;
//空載的時(shí)候(沒有手按下),計(jì)數(shù)器需要的時(shí)間
//初始化觸摸按鍵
//獲得空載的時(shí)候觸摸按鍵的取值.
//psc:分頻系數(shù),越小,靈敏度越高.
//返回值:0,初始化成功;1,初始化失敗
u8 TPAD_Init(u8 psc)
{
u16 buf[10];
u16 temp;
u8 j,i;
TIM3_CH4_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//設(shè)置分頻系數(shù)
for(i=0;i<10;i++)//連續(xù)讀取 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 個(gè)數(shù)據(jù)進(jìn)行平均
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 的數(shù)值,不正常!
return 0;
}
//復(fù)位一次
//釋放電容電量,并清除定時(shí)器的計(jì)數(shù)值
void TPAD_Reset(void)
{
GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_1;
//PB1
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出
GPIO_Initure.Pull=GPIO_PULLDOWN;
//下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH;
//高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //PB1 輸出 0,放電
delay_ms(5);
__HAL_TIM_CLEAR_FLAG(&TIM3_Handler,TIM_FLAG_CC4|TIM_FLAG_UPDATE);
//清除標(biāo)志位
__HAL_TIM_SET_COUNTER(&TIM3_Handler,0); //計(jì)數(shù)器值歸 0
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
//推挽復(fù)用
GPIO_Initure.Pull=GPIO_NOPULL;
//不帶上下拉
GPIO_Initure.Alternate=GPIO_AF2_TIM3;
//PB1 復(fù)用為 TIM3 通道 4
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}
//得到定時(shí)器捕獲值
//如果超時(shí),則直接返回定時(shí)器的計(jì)數(shù)值.
//返回值:捕獲值/計(jì)數(shù)值(超時(shí)的情況下返回)
u16 TPAD_Get_Val(void)
{
TPAD_Reset();
while(__HAL_TIM_GET_FLAG(&TIM3_Handler,TIM_FLAG_CC4)==RESET)
//等待捕獲上升沿
{
if(__HAL_TIM_GET_COUNTER(&TIM3_Handler)>TPAD_ARR_MAX_VAL-500)
return __HAL_TIM_GET_COUNTER(&TIM3_Handler);
//超時(shí)了,直接返回 CNT 的值
};
return HAL_TIM_ReadCapturedValue(&TIM3_Handler,TIM_CHANNEL_4);
}
//讀取 n 次,取最大值
//n:連續(xù)獲取的次數(shù)
//返回值:n 次讀數(shù)里面讀到的最大讀數(shù)值
u16 TPAD_Get_MaxVal(u8 n)
{
u16 temp=0;
u16 res=0;
u8 lcntnum=n*2/3;//至少 2/3*n 的有效個(gè)觸摸,才算有效
u8 okcnt=0;
while(n--)
{
temp=TPAD_Get_Val();//得到一次值
if(temp>(tpad_default_val*5/4))okcnt++;//至少大于默認(rèn)值的 5/4 才算有效
if(temp>res)res=temp;
}
if(okcnt>=lcntnum)return res;//至少 2/3 的概率,要大于默認(rèn)值的 5/4 才算有效
else return 0;
}
//掃描觸摸按鍵
//mode:0,不支持連續(xù)觸發(fā)(按下一次必須松開才能按下一次);
1,支持連續(xù)觸發(fā)(可以一直按下)
//返回值:0,沒有按下;1,有按下;
#define TPAD_GATE_VAL 30 //觸摸的門限值,也就是必須大于
tpad_default_val+TPAD_GATE_VAL,才認(rèn)為是有效觸摸.
u8 TPAD_Scan(u8 mode)
{
static u8 keyen=0; //0,可以開始檢測(cè);>0,還不能開始檢測(cè)
u8 res=0;
u8 sample=3;
//默認(rèn)采樣次數(shù)為 3 次
u16 rval;
if(mode)
{
sample=6;
//支持連按的時(shí)候,設(shè)置采樣次數(shù)為 6 次
keyen=0;
//支持連按
}
rval=TPAD_Get_MaxVal(sample);
if(rval>(tpad_default_val+TPAD_GATE_VAL))//大于
tpad_default_val+TPAD_GATE_VAL,有效
{
if(keyen==0)res=1; //keyen==0,有效
//printf("r:%drn",rval);
keyen=3;
//至少要再過 3 次之后才能按鍵有效
}
if(keyen)keyen--;
return res;
}
//定時(shí)器 3 通道 4 輸入捕獲配置
//arr:自動(dòng)重裝值(TIM3 是 16 位的!!)
//psc:時(shí)鐘預(yù)分頻數(shù)
void TIM3_CH4_Cap_Init(u32 arr,u16 psc)
{
TIM_IC_InitTypeDef TIM3_CH4Config;
TIM3_Handler.Instance=TIM3;
//通用定時(shí)器 3
TIM3_Handler.Init.Prescaler=psc;
//分頻
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
//向上計(jì)數(shù)器
TIM3_Handler.Init.Period=arr;
//自動(dòng)裝載值
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //分頻因子
HAL_TIM_IC_Init(&TIM3_Handler);
TIM3_CH4Config.ICPolarity=TIM_ICPOLARITY_RISING;
//上升沿捕獲
TIM3_CH4Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//映射到 TI1 上
TIM3_CH4Config.ICPrescaler=TIM_ICPSC_DIV1;
//配置輸入分頻,不分頻
TIM3_CH4Config.ICFilter=0;
//配置輸入濾波器,不濾波
HAL_TIM_IC_ConfigChannel(&TIM3_Handler,&TIM3_CH4Config,
TIM_CHANNEL_4);//配置 TIM3 通道 4
HAL_TIM_IC_Start(&TIM3_Handler,TIM_CHANNEL_4); //開始捕獲 TIM3 的通道 4
}
//定時(shí)器 3 底層驅(qū)動(dòng),時(shí)鐘使能,引腳配置
//此函數(shù)會(huì)被 HAL_TIM_IC_Init()調(diào)用
//htim:定時(shí)器 3 句柄
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_TIM3_CLK_ENABLE();
//使能 TIM3 時(shí)鐘
__HAL_RCC_GPIOB_CLK_ENABLE();
//開啟 GPIOB 時(shí)鐘
GPIO_Initure.Pin=GPIO_PIN_1;
//PB1
GPIO_Initure.Mode=GPIO_MODE_AF_INPUT; //推挽復(fù)用輸入
GPIO_Initure.Pull=GPIO_NOPULL;
//不帶上下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH;
//高速
GPIO_Initure.Alternate=GPIO_AF2_TIM3;
//PB1 復(fù)用為 TIM3 通道 4
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}
函數(shù) TIM3_CH4_Cap_Init 函數(shù),該函數(shù)和上一章的輸入捕獲函數(shù)基本一樣,不同的是上一
章實(shí)驗(yàn)最后調(diào)用得是函數(shù) HAL_TIM_IC_Start_IT,使能駛?cè)氩东@通道的同時(shí)開啟了輸入捕獲中
斷,而該函數(shù)最后調(diào)用的函數(shù)是 HAL_TIM_IC_Start,只是開啟了輸入捕獲通道,并沒有開啟
輸入捕獲中斷。
函數(shù) HAL_TIM_IC_MspInit 是輸入捕獲通用 MSP 回調(diào)函數(shù),該函數(shù)的作用是使能定時(shí)器
和 GPIO 時(shí)鐘,配置 GPIO。該函數(shù)功能和輸入捕獲實(shí)驗(yàn)中該函數(shù)作用基本類似。
函數(shù) TPAD_Get_Val 用于得到定時(shí)器的一次捕獲值。該函數(shù)先調(diào)用 TPAD_Reset,將電容放
電,同時(shí)通過程序__HAL_TIM_SET_COUNTER(&TIM3_Handler,0)將計(jì)數(shù)值 TIM3_CNT 寄存器
為 0,然后死循環(huán)等待發(fā)生上升沿捕獲(或計(jì)數(shù)溢出),將捕獲到的值(或溢出值)作為返回
值返回。
函數(shù) TPAD_Init 用于初始化輸入捕獲,并獲取默認(rèn)的 TPAD 值。該函數(shù)有一個(gè)參數(shù),用來
傳遞定時(shí)器分頻系數(shù),其實(shí)是為了配置 TIM3_CH4_Cap_Init 為 1us 計(jì)數(shù)周期。在該函數(shù)中連續(xù)
10 次讀取 TPAD 值,將這些值升序排列后取中間 6 個(gè)值再做平均(這樣做的目的是盡量減少誤
差),并賦值給 tpad_default_val,用于后續(xù)觸摸判斷的標(biāo)準(zhǔn)。
最后,我們來看看 TPAD_Scan 函數(shù),該函數(shù)用于掃描 TPAD 是否有觸摸,該函數(shù)的參數(shù)
mode,用于設(shè)置是否支持連續(xù)觸發(fā)。返回值如果是 0,說明沒有觸摸,如果是 1,則說明有觸
摸。該函數(shù)同樣包含了一個(gè)靜態(tài)變量,用于檢測(cè)控制,類似第八章的 KEY_Scan 函數(shù)。所以該
函數(shù)同樣是不可重入的。在函數(shù)中,我們通過連續(xù)讀取 3 次(不支持連續(xù)按的時(shí)候)TPAD 的值,
取這他們的最大值,和 tpad_default_val+TPAD_GATE_VAL 比較,如果大于則說明有觸摸,如
果小于,則說明無觸摸。其中 tpad_default_val 是我們?cè)谡{(diào)用 TPAD_Init 函數(shù)的時(shí)候得到的值,
而 TPAD_GATE_VAL 則是我們?cè)O(shè)定的一個(gè)門限值(這個(gè)大家可以通過實(shí)驗(yàn)數(shù)據(jù)得出,根據(jù)實(shí)際
情況選擇適合的值就好了),這里我們?cè)O(shè)置為 30。該函數(shù),我們還做了一些其他的條件限制,
讓觸摸按鍵有更好的效果,這個(gè)就請(qǐng)大家看代碼自行參悟了。
函數(shù) TPAD_Reset 顧名思義,是進(jìn)行一次復(fù)位操作。先設(shè)置 PB1 輸出低電平,電容放電,
同時(shí)清除中斷標(biāo)志位并且計(jì)數(shù)器值清零,然后配置 PB1 位復(fù)用功能浮空輸入,利用外部上拉電
阻給電容 Cs(Cs+Cx)充電,同時(shí)開啟 TIM3_CH4 的輸入捕獲。
函數(shù) TPAD_Get_MaxVal 就非常簡(jiǎn)單了,它通過 n 此調(diào)用函數(shù) TPAD_GetVal 采集捕獲值,
然后進(jìn)行比較后獲取 n 次采集中的最大值。
接下來,我們看看主程序里面的 main 函數(shù)如下:
int main(void)
{
u8 t=0;
HAL_Init();
//初始化 HAL 庫(kù)
Stm32_Clock_Init(96,4,2,4);
//設(shè)置時(shí)鐘,96Mhz
delay_init(96);
//初始化延時(shí)函數(shù)
uart_init(115200);
//初始化串口
LED_Init();
//初始化 LED
TPAD_Init(6);
//初始化觸摸按鍵
while(1)
{
if(TPAD_Scan(0)) //成功捕獲到了一次上升沿(此函數(shù)執(zhí)行時(shí)間至少 15ms)
{
LED5=!LED5;
//LED5 取反
}
t++;
if(t==15)
{
t=0;
LED0=!LED0;
//LED0 取反,提示程序正在運(yùn)行
}
delay_ms(10);
}
}
該 main 函數(shù)比較簡(jiǎn)單,TPAD_Init(6)函數(shù)執(zhí)行之后,就開始觸摸按鍵的掃描,當(dāng)有觸摸的
時(shí)候,對(duì) DS5 取反,而 DS0 則有規(guī)律的間隔取反,提示程序正在運(yùn)行。
這里還要提醒一下大家,不要把 uart_init(115200);去掉,因?yàn)樵?TPAD_Init 函數(shù)里面,我們
有用到 printf,如果你去掉了 uart_init,就會(huì)導(dǎo)致 printf 無法執(zhí)行,從而死機(jī)。
至此,我們的軟件設(shè)計(jì)就完成了。16.4 下載驗(yàn)證
在完成軟件設(shè)計(jì)之后,將我們將編譯好的文件下載到 NANO STM32F4 V1 上,可以看到
DS0 慢速閃爍,此時(shí),我們用手指觸摸開發(fā)板上的 TPAD(右下角的白色頭像),就可以控制
DS5 的亮滅了。不過你要確保 TPAD 和 ADC 的跳線帽連接上了哦!如圖 16.4.1 所示:

圖 16.4.1 觸摸區(qū)域和跳線帽短接方式示意圖
同時(shí)大家可以打開串口調(diào)試助手,每次復(fù)位的時(shí)候,會(huì)收到 tpad_default_val 的值,一般為
15 左右。

總結(jié)

以上是生活随笔為你收集整理的判断按键值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。