资讯详情

PIC单片机 电容式触摸检测

目录

        • ADC触摸检测原理
        • ADC的使用
        • 设计触摸检测程序

ADC触摸检测原理

??ADC内部电容Chold与外引脚连接的电容Csensor并联,等效电容为两者之和。首先,内部电容Chold充电,外部电容Csensor放电,然后连接两者,将两者的电荷量Q保持在恒定值。根据电容公式 Q = CU 可以看出,当手触摸外部电容器时,Csensor当电容增大时,等效电容增大,电荷Q恒定,电压U下降。测量触摸和未触摸电压阈值后,可根据电压变化判断是否触摸。

image-20210912185736184

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 proection 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.
#endif

unsigned char seq_table[16] = {
    0b00111111, //0
    0b00000110, //1
    0b01011011, //2
    0b01001111, //3
    0b01100110, //4
    0b01101101, //5
    0b01111101, //6
    0b00000111, //7
    0b01111111, //8
    0b01101111, //9
    0b01110111, //a
    0b01111100, //b
    0b00111001, //c
    0b01011110, //d
    0b01111001, //e
    0b01110001  //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 number

void __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 bit
    TMR0H = 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 clock
        ADACQ = 0b00010000; //Acquisition time is 128 clocks of the selected ADC clock
        for (int wait = 0; wait < 16; wait++); //wait for acquisition time
        ADCON0bits.ADGO = 1;
    }
}

void Init()
{
    //Init PORTA,PORTB,PORTC
    PORTA = 0;
    LATA = 0;
    ANSELA = 0x80;
    TRISA = 0x80; //Set RA7 to input

    PORTB = 0;
    LATB = 0;
    ANSELB = 0;
    TRISB = 0;

    PORTC = 0;
    LATC = 0;
    ANSELC = 0;
    TRISC = 0;

    Init_timer();
    Init_ADC();
}

void Init_ADC()
{
    //Init ADC
    ADCLKbits.ADCCS = 0b000001; //FOSC/4

    ADCON1bits.ADPPOL = 0; //IO pin shorted to VSS, Chold shorted to AVDD
    ADCON0bits.ADCS = 0;   //Clock supplied by FOSC, divided according to ADCLK register
    ADCON0bits.ADFRM0 = 1; //ADRES and ADPREV data are right-justified

    ADREFbits.ADPREF = 0b11; //VREF+ is connected to FVR
    ADREFbits.ADNREF = 0b0;  // VREF- is connected to VSS

    FVRCONbits.FVREN = 1;    //FVR enable
    FVRCONbits.ADFVR = 0b11; //ADC FVR Buffer Gain is 4x, (4.096V)
    FVRCONbits.FVRRDY = 1;   //Fixed Voltage Reference output is ready for use

    ADCON1 = 0b00000000; // default ADPPOL, no ADDSEN
    ADCON2 = 0b00000000; // legacy mode
    ADCON3 = 0b00000000; // default, no interrupt

    ADPCH = 0b000111;   //ADC Positive Input Channel Selection == RA7
    ADCAP = 0b101;      //ADC Additional Sample Capacitor == 5pF
    ADPRE = 0b00010000; //Precharge time is 128 clocks of the selected ADC clock
    ADACQ = 0b00010000; //Acquisition time is 128 clocks of the selected ADC clock
    for (int wait = 0; wait < 16; wait++);//wait for acquisition time
    ADCON0bits.ADON = 1; //Turn ADC On
}

void Init_timer()
{
    //Timer interrupt
    INTCONbits.GIE = 1;
    PIR0bits.TMR0IF = 0; //clear the signal bit
    PIE0bits.TMR0IE = 1; //interrupt enable

    //Timer0 configuration
    T0CON0 = 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++);
}

标签: 电容的if

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台