PIC单片机 电容式触摸检测
目錄
- ADC觸摸檢測原理
- ADC的使用
- 觸摸檢測程序設計
ADC觸摸檢測原理
??ADC內部電容Chold與外部引腳所接電容Csensor并聯,等效電容為二者之和。首先將內部電容Chold充電,將外接電容Csensor放電,然后連接二者,將二者電荷量Q保持為恒定值。根據電容公式 Q = CU 可知,當手觸摸外部電容Csensor導致其電容增大時,等效電容隨之增大,而電荷量Q恒定所以電壓U下降。測量得出觸摸與未觸摸時電壓的閾值后就可以根據電壓變化來判斷是否觸摸。
?
?
ADC的使用
1、引腳PORT配置
TRISx寄存器控制引腳數據傳輸方向,ANSELx寄存器控制引腳數據類型為模擬信號還是數字信號。
?
2、CHANNEL 選擇
ADPCH寄存器決定channel。
注意,在改變channel后要delay一會兒才能開始下一次轉換。
?
3、選取參考電壓
ADREF的ADPREF位選擇正參考電壓,ADREF的ADNREF位選擇負參考電位。
?
4、CLOCK 選擇
通過ADCON0寄存器的ADCS位和ADCLK寄存器來選擇。
?
5、輸出格式控制
ADC轉換結果保存為10bit數據存入ADRES,有兩種對齊方式,ADCON0的ADFRM0位決定result的左 / 右對齊。
?
6、開啟ADC
把ADCON0的ADON位置1
?
7、預充電和采樣
只有外接電容,使用CVD方法實現觸摸檢測時才進行預充電,作用是對Chold和Csensor充/放電,但是僅僅是進行AD轉換則不需要預充電。可通過ADPRE寄存器控制預充電時長。采樣是在AD轉換之前進行的,時長由ADACQ寄存器設置。必須等待采樣結束才能開始AD轉換。
?
8、開啟AD轉換
把ADCON0的ADGO位置1時開啟AD轉換,轉換結束時ADGO自動清0。應當循環或者定時判斷ADGO是否等于0,重復開啟AD轉換。
?
9、讀取結果
AD轉換結果保存在ADRES0L和ADRES0H寄存器,對齊方式在上面已提到。
?
?
觸摸檢測程序設計
實現效果:
??按下按鍵,4位數碼管<2:0>顯示“YES”,未按下時顯示“NO”;數碼管<3>顯示按下次數,最多記到16次;按下按鍵時LED燈閃亮。
引腳使用:
??PORTA<3:0>為數碼管片選位,PORTC<7:0>為數碼管段選位;PORTB<7>為LED燈位。
?
設計思路:
??ADC模塊循環預充電、采樣、AD轉換,獲取電壓變化并與閾值比較判斷是否觸摸;定時器5ms中斷一次,判斷ADC是否轉換完成,計數并把ADRES中的轉換結果同步到數碼管的顯示緩沖區,隨后再次預充電、采樣并開啟AD轉換。
?
基于PIC16F18854單片機的cC語言源代碼:
#include <xc.h> #ifndef BOOTLOADER//配置段// PIC16F18854 Configuration Bit Settings// 'C' source line config statements// CONFIG1 #pragma config FEXTOSC = OFF // External Oscillator mode selection bits (Oscillator not enabled) #pragma config RSTOSC = HFINT1 // Power-up default value for COSC bits (HFINTOSC (1MHz)) #pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2) #pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (FSCM timer disabled)// CONFIG2 #pragma config MCLRE = ON // Master Clear Enable bit (MCLR pin is Master Clear function) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config LPBOREN = OFF // Low-Power BOR enable bit (ULPBOR disabled) #pragma config BOREN = ON // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices) #pragma config ZCD = OFF // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.) #pragma config PPS1WAY = OFF // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)// CONFIG3 #pragma config WDTCPS = WDTCPS_31 // WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS) #pragma config WDTE = SWDTEN // WDT operating mode (WDT enabled/disabled by SWDTEN bit in WDTCON0) #pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits (window always open (100%); software control; keyed access not required) #pragma config WDTCCS = SC // WDT input clock selector (Software Control)// CONFIG4 #pragma config WRT = WRT_upper // UserNVM self-write protection bits (0x0000 to 0x01FF write protected) #pragma config SCANE = not_available // Scanner Enable bit (Scanner module is not available for use) #pragma config LVP = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)// CONFIG5 #pragma config CP = OFF // UserNVM Program memory code protection bit (Program Memory code protection enabled) #pragma config CPD = OFF // DataNVM code protection bit (Data EEPROM code protection disabled)// #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #endifunsigned char seq_table[16] = {0b00111111, //00b00000110, //10b01011011, //20b01001111, //30b01100110, //40b01101101, //50b01111101, //60b00000111, //70b01111111, //80b01101111, //90b01110111, //a0b01111100, //b0b00111001, //c0b01011110, //d0b01111001, //e0b01110001 //f }; //段碼表unsigned char code_table[4] = {0b11110111,0b11111011,0b11111101,0b11111110}; //位碼表unsigned char display_table[4]; //顯示緩沖區 int touch_count; //按動次數計時器 int touch_flag; //按動記錄標志位 int mode = 0; //mode == 0 means print "yes" or "no"; mode == 1 means print voltage ADC numbervoid __interrupt() ISR(void); void seq_code_sel(int i); void Init(); void Init_timer(); void Init_ADC();void main(void) {unsigned char i = 0;touch_count = 0;touch_flag = 0;Init();while (1){seq_code_sel(i);i = (i + 1) % 4;} }void __interrupt() ISR(void) {PIR0bits.TMR0IF = 0; //clear the signal bitTMR0H = 0x3c;TMR0L = 0xb0;if (mode){if (ADRES){display_table[0] = touch_count;display_table[1] = (ADRES / 100) % 10;display_table[2] = (ADRES / 10) % 10;display_table[3] = ADRES % 10;}}else{if (ADRES > 800) //設置閾值為 800{PORTB = 0;display_table[0] = seq_table[touch_count];display_table[1] = 0;display_table[2] = 0x37;display_table[3] = 0x3f;touch_flag = 1;}if (ADRES < 800){PORTB = 0x80;if (touch_flag){touch_count = (touch_count + 1) % 16;touch_flag = 0;}display_table[0] = seq_table[touch_count];display_table[1] = 0x6e;display_table[2] = 0x7b;display_table[3] = 0x6d;}}if (ADCON0bits.ADGO == 0){ADPRE = 0b00010000; //Precharge time is 128 clocks of the selected ADC clockADACQ = 0b00010000; //Acquisition time is 128 clocks of the selected ADC clockfor (int wait = 0; wait < 16; wait++); //wait for acquisition timeADCON0bits.ADGO = 1;} }void Init() {//Init PORTA,PORTB,PORTCPORTA = 0;LATA = 0;ANSELA = 0x80;TRISA = 0x80; //Set RA7 to inputPORTB = 0;LATB = 0;ANSELB = 0;TRISB = 0;PORTC = 0;LATC = 0;ANSELC = 0;TRISC = 0;Init_timer();Init_ADC(); }void Init_ADC() {//Init ADCADCLKbits.ADCCS = 0b000001; //FOSC/4ADCON1bits.ADPPOL = 0; //IO pin shorted to VSS, Chold shorted to AVDDADCON0bits.ADCS = 0; //Clock supplied by FOSC, divided according to ADCLK registerADCON0bits.ADFRM0 = 1; //ADRES and ADPREV data are right-justifiedADREFbits.ADPREF = 0b11; //VREF+ is connected to FVRADREFbits.ADNREF = 0b0; // VREF- is connected to VSSFVRCONbits.FVREN = 1; //FVR enableFVRCONbits.ADFVR = 0b11; //ADC FVR Buffer Gain is 4x, (4.096V)FVRCONbits.FVRRDY = 1; //Fixed Voltage Reference output is ready for useADCON1 = 0b00000000; // default ADPPOL, no ADDSENADCON2 = 0b00000000; // legacy modeADCON3 = 0b00000000; // default, no interruptADPCH = 0b000111; //ADC Positive Input Channel Selection == RA7ADCAP = 0b101; //ADC Additional Sample Capacitor == 5pFADPRE = 0b00010000; //Precharge time is 128 clocks of the selected ADC clockADACQ = 0b00010000; //Acquisition time is 128 clocks of the selected ADC clockfor (int wait = 0; wait < 16; wait++);//wait for acquisition timeADCON0bits.ADON = 1; //Turn ADC On }void Init_timer() {//Timer interruptINTCONbits.GIE = 1;PIR0bits.TMR0IF = 0; //clear the signal bitPIE0bits.TMR0IE = 1; //interrupt enable//Timer0 configurationT0CON0 = 0b00010000;T0CON1 = 0b01000000;TMR0H = 0x3c;TMR0L = 0xb0;T0CON0bits.T0EN = 1; }void seq_code_sel(int i) {PORTA = code_table[i];if (mode){PORTC = seq_table[display_table[i]];}else{PORTC = display_table[i];}for (int temp = 0; temp < 100; temp++); }總結
以上是生活随笔為你收集整理的PIC单片机 电容式触摸检测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PIC单片机 按键检测识别
- 下一篇: PIC单片机 IIC通信及实现