STM32f4————電容觸摸按鍵實(shí)驗(yàn)代碼(02)
//定時(shí)器 2通道2 輸入捕獲配置
//arr:自動(dòng)重裝值
//psc:時(shí)鐘預(yù)分頻數(shù)
void TIM2_CH1_Cap_Init(u32 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM2_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM2時(shí)鐘使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA時(shí)鐘
GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2); //PA5復(fù)用位定時(shí)器2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復(fù)用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//速度 100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//不帶上下拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA5
//初始化 TIM2
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)定計(jì)數(shù)器自動(dòng)重裝值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //預(yù)分頻器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 初始化定時(shí)器2
//初始化通道 1
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇輸入端 IC1映射到TIM2
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置輸入分頻,不分頻
TIM2_ICInitStructure.TIM_ICFilter = 0x00;//IC2F=0000 配置輸入濾波器 不濾波
TIM_ICInit(TIM2, &TIM2_ICInitStructure);//初始化 TIM2 IC1
TIM_Cmd(TIM2,ENABLE ); //使能定時(shí)器 2
}
此部分代碼包含 6 個(gè)函數(shù),我們將介紹其中 4 個(gè)比較重要的函數(shù):TIM2_CH1_Cap_Init、TPAD_Get_Val、TPAD_Init和 TPAD_Scan。
首先介紹TIM2_CH1_Cap_Init函數(shù),該函數(shù)和上一章的輸入捕獲函數(shù)基本一樣,不同的是,這里我們?cè)O(shè)置的是 TIM2 上一章是 TIM5。通過(guò)該函數(shù)的設(shè)置,我們將可以捕獲 PA5 上的上升沿,同樣TIM2也是 32 位定時(shí)器。
我們?cè)賮?lái)看看 TPAD_Get_Val 函數(shù),該函數(shù)用于得到定時(shí)器的一次捕獲值。該函數(shù)先調(diào)用TPAD_Reset,將電容放電,同時(shí)設(shè)置通過(guò)調(diào)用函數(shù)TIM_SetCounter(TIM2,0)將計(jì)數(shù)值TIM2_CNT設(shè)置為 0,然后死循環(huán)等待發(fā)生上升沿捕獲(或計(jì)數(shù)溢出),將捕獲到的值(或溢出值)作為返回值返回。
接著我們介紹 TPAD_Init 函數(shù),該函數(shù)用于初始化輸入捕獲,并獲取默認(rèn)的 TPAD 值。該函數(shù)有一個(gè)參數(shù),用來(lái)傳遞系統(tǒng)時(shí)鐘,其實(shí)是為了配置 TIM2_CH1_Cap_Init 為 1us 計(jì)數(shù)周期。在該函數(shù)中連續(xù) 10 次讀取TPAD 值,將這些值升序排列后取中間 6 個(gè)值再做平均(這樣做的目的是盡量減少誤差),并賦值給tpad_default_val,用于后續(xù)觸摸判斷的標(biāo)準(zhǔn)。
最后,我們來(lái)看看 TPAD_Scan 函數(shù),該函數(shù)用于掃描 TPAD 是否有觸摸,該函數(shù)的參數(shù)mode,用于設(shè)置是否支持連續(xù)觸發(fā)。返回值如果是 0,說(shuō)明沒(méi)有觸摸,如果是 1,則說(shuō)明有觸摸。該函數(shù)同樣包含了一個(gè)靜態(tài)變量,用于檢測(cè)控制,類似第八章的KEY_Scan 函數(shù)。所以該函數(shù)同樣是不可重入的。在函數(shù)中,我們通過(guò)連續(xù)讀取 3 次(不支持連續(xù)按的時(shí)候)TPAD 的值,取這他們的最大值,和tpad_default_val+TPAD_GATE_VAL 比較,如果大于則說(shuō)明有觸摸,如果小于,則說(shuō)明無(wú)觸摸。其中tpad_default_val 是我們?cè)谡{(diào)用 TPAD_Init 函數(shù)的時(shí)候得到的值,而TPAD_GATE_VAL則是我們?cè)O(shè)定的一個(gè)門(mén)限值(這個(gè)大家可以通過(guò)實(shí)驗(yàn)數(shù)據(jù)得出,根據(jù)實(shí)際情況選擇適合的值就好了),這里我們?cè)O(shè)置為 100。該函數(shù),我們還做了一些其他的條件限制,
讓觸摸按鍵有更好的效果,這個(gè)就請(qǐng)大家看代碼自行參悟了。
tpad.h 頭文件部分代碼比較簡(jiǎn)單,這里不做介紹。
接下來(lái)我們看看主函數(shù)代碼如下:
int main(void)
{
u8 t=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設(shè)置系統(tǒng)中斷優(yōu)先級(jí)分組2
delay_init(168); //初始化延時(shí)函數(shù)
uart_init(115200); //初始化串口波特率為115200
LED_Init(); //初始化 LED
TPAD_Init(8); //初始化觸摸按鍵,以 84/4=21Mhz頻率計(jì)數(shù)
while(1)
{
if(TPAD_Scan(0)) //成功捕獲到了一次上升沿(此函數(shù)執(zhí)行時(shí)間至少15ms)
{
LED1=!LED1; //LED1取反
}
t++;
if(t==15)
{
t=0; LED0=!LED0; //LED0取反,提示程序正在運(yùn)行
}
delay_ms(10);
}
}
該 main函數(shù)比較簡(jiǎn)單,TPAD_Init(8)函數(shù)執(zhí)行之后,就開(kāi)始觸摸按鍵的掃描,當(dāng)有觸摸的時(shí)候,對(duì)DS1 取反,而DS0 則有規(guī)律的間隔取反,提示程序正在運(yùn)行。注意在修改main函數(shù)之后,還需要在main.c里面添加tpad.h頭文件,否則會(huì)報(bào)錯(cuò)哦。
這里還要提醒一下大家,不要把uart_init(115200);去掉,因?yàn)樵赥PAD_Init函數(shù)里面,我們有用到 printf,如果你去掉了uart_init,就會(huì)導(dǎo)致printf無(wú)法執(zhí)行,從而死機(jī)。
至此,我們的軟件設(shè)計(jì)就完成了。