目錄
電容觸摸按鍵實驗 電容觸摸按鍵的基本原理(原理圖層面)
新電容的產生與作用
我們學過模電的同學知道:我們的手其實相當于一塊可以存儲感應電荷的金屬板觸摸電容,當我們的手靠近屏幕時,我們的手與屏幕下的金屬板Cx構成了一個平行電容板,這個電容與Cs雜散電容相并聯(lián),“并聯(lián)電容C=C1+C2”。
充放電性能的變化
我們看見“VCC是一定的;電容C越大代表一定電壓下,存儲的電荷數(shù)量越多(Q=CU),反之,充電到U所花費的時間也更多;電阻R的值一定代表著對電荷的阻礙作用是固定的”。
充電到V=Vth,花費時間TA明顯小于TB;我們真實情況下的矩形脈沖如下圖所示:
脈沖如何被捕獲
當電容從0充電到Vth時,就相當于一個上升沿脈沖。其實這個充放電過程很快,我們一般用的RC充放電電路是為了觀察現(xiàn)象因此將時間常數(shù)做的很大,但是現(xiàn)實的話我們要快速識別必須將時間常數(shù)縮小到一定范圍內才OK。
原理圖層面的連接
STM_ADC其實只是這個引腳功能的其中一個,我們這里并不是用的引腳的ADC功能,以下為該引腳的復用:
我們這里使用的是PA1的TIM5_CH2功能,用于快速捕獲TPAD的有效脈沖沿變化。
硬件配置的大致流程
第一步
TPAD引腳的電壓先置零,進行電容Cs的放電
第二步
TPAD引腳設置為浮空輸入(由于TPAD與PA1接在了一起,因此就是將PA1置為浮空輸入模式,為了識別有效的脈沖沿)
第三步
TIM5計數(shù)器初始值置0并開啟上升沿計數(shù)模式
第四步
開啟TIM5_CH2的輸入捕獲模式
第五步
等待充電完成,讀取此時的捕獲值,“脈沖沿持續(xù)時間 = (捕獲值-初始值)*單位遞增時間”
注:沒有按下的時候,充電時間為T1(default)。按下TPAD,電容變大,所以充電時間為T2。我們可以通過檢測充放電時間,來判斷是否按下。如果T2-T1大于某個值,就可以判斷
有按鍵按下。
電容觸摸按鍵的基本原理(軟件配置層面)
函數(shù)名稱
返回值類型
函數(shù)功能
TPAD_Init()
void
用于捕獲無接觸情況下的電容充電時間,并且配置TIM5_CH2引腳的初始屬性
TPAD_Get_Val()
int
獲取一次電容充電時間
TPAD_Get_MaxVal()
int
獲取4次讀取“電容充電時間”的最大值
TPAD_Scan()
char(true or false)
用于掃描判斷TPAD是否動作
TPAD_Reset()
void
重置計數(shù)器與捕獲值(將前一次讀取結果重置)
函數(shù)說明 TPAD_InitConfig()函數(shù)
void?TPAD_InitConfig()?//?讀取默認電容充電時間??
{??
????u16?RecordChargeTime[10]?=?{0};??
????u8?i?=?0,?temp?=?0;??
??????
????uart_init(115200);?//?初始化USART1??
????TIM_CAP_InitConfig(0xFFFF,?72-1);?//?初始化TIM5_CH2的輸入配置??
??????
????for(;?i<10;?i++)??
????{??
????????RecordChargeTime[i]?=?TPAD_GetValue();?//?連續(xù)計算10次默認充電時間??
????}??
for(i=0; i<9; i++)
{
if(RecordChargeTime[i] < RecordChargeTime[i+1]) // 冒泡排序(大->小)
{
temp = RecordChargeTime[i];
RecordChargeTime[i] = RecordChargeTime[i+1];
RecordChargeTime[i+1] = temp;
}
}?
????for(i=1,?temp=0;?i<9;?i++)??
????{??
????????temp?+=?RecordChargeTime[i];?//?去掉MAX與MIN求平均充電時間??
????}??
????TPAD_DefaultValue?=?temp/8;?//?求出TPAD無動作時的默認充電時間??
????printf("Default:%dus\r\n",TPAD_DefaultValue);?//?向串口打印未觸摸時的電容充電時長??
}??
TPAD_Reset()函數(shù)
這里值得注意的是:PA1端口輸入輸出模式的變化以及TIM_ClearFlag()函數(shù)的使用。
PA1端口輸入輸出模式的變化:
我們會疑問“PA1端口為何要變化輸入輸出模式?”,在我們上述流程中提及過,我們要對電容充電所造成的上升沿重新計數(shù)就必須先將TPAD(PA1)端口置0進行充分的放電。那我們如何放電呢?
在圖中,PA1與TPAD通過跳線帽連接在一起,然后為了讀取TPAD中產生的上升沿,我們必須將PA1設置為TIM5_CH2的功能,此時PA1為浮空輸入模式,但是我們讀取完有效的脈沖沿之后,若繼續(xù)讀取必須先進行放電才可以。此時,我們配置PA1為推挽輸出模式觸摸電容,放完電后再變成浮空輸入模式。
TIM_ClearFlag()庫函數(shù)的含義:
我們使用庫函數(shù)的同學會有些疑問:TIM_ClearFlag()函數(shù)與 TIM_ClearITPendingBit()函數(shù)的區(qū)別在哪里?這里我來解說一下。
TIM_ClearFlag()函數(shù)是用于“清除標志位的”,比如:當檢測到上升沿脈沖(有效的脈沖沿),相應的TIM_IT_CC2標志會出現(xiàn),其實這些標志位和TIM_ClearITPendingBit ()函數(shù)中的中斷標志位是一摸一樣的,只不過由于未開啟中斷,事件一旦發(fā)生僅僅會使得標志位置1,不會觸發(fā)中斷。 其實如下的程序中我們就是想清除標志位,因此也可以使用TIM_ClearITPendingBit(TIM5, TIM_IT_CC2),這兩個函數(shù)的功能就是去除相應的標志位,功能相同可以相互轉換使用。
TIM_ClearFlag()與TIM_ClearITPendingBit()的函數(shù)體對比
TIM_ClearFlag()函數(shù)體
void?TIM_ClearITPendingBit(TIM_TypeDef*?TIMx,?uint16_t?TIM_IT)??
{??
??/*?Check?the?parameters?*/??
??assert_param(IS_TIM_ALL_PERIPH(TIMx));??
??assert_param(IS_TIM_IT(TIM_IT));??
??/*?Clear?the?IT?pending?Bit?*/??
??TIMx->SR?=?(uint16_t)~TIM_IT;??// 操作SR寄存器
}??
TIM_ClearITPendingBit()的函數(shù)體
void?TIM_ClearFlag(TIM_TypeDef*?TIMx,?uint16_t?TIM_FLAG)??
{????
??/*?Check?the?parameters?*/??
??assert_param(IS_TIM_ALL_PERIPH(TIMx));??
??assert_param(IS_TIM_CLEAR_FLAG(TIM_FLAG));??
?????
??/*?Clear?the?flags?*/??
??TIMx->SR?=?(uint16_t)~TIM_FLAG;??// 操作SR寄存器
}??
我們從TIM_ClearFlag()與TIM_ClearITPendingBit()的函數(shù)體對比發(fā)現(xiàn),完全一摸一樣,可以互換使用。
//復位一次??
void?TPAD_Reset(void)??
{??
????GPIO_InitTypeDef??GPIO_InitStructure;???
????RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,?ENABLE);????//使能PA端口時鐘??
??????
????//設置GPIOA.1為推挽使出??
????GPIO_InitStructure.GPIO_Pin?=?GPIO_Pin_1;????????????????//PA1?端口配置??
????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);????????????????????????//PA.1輸出0,放電??
??
????delay_ms(5);??// 給予充足的時間進行放電
??
????TIM_SetCounter(TIM5,0);?????//計數(shù)器的初始計數(shù)值置零
????TIM_ClearFlag(TIM5,?TIM_IT_CC2);???// 清除TIM5_CH2的上升沿標志位
????//重新設置GPIOA.1為浮空輸入??
????GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;??//浮空輸入??
????GPIO_Init(GPIOA,?&GPIO_InitStructure);???
}?
上一篇:麥克風電容 動圈和電容的區(qū)別 教你怎么選合適自己的麥克風