PICの基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
チャタリング(Chattering) 防止プログラム

Push SWを使用するときに、注意しなければならないことは、チャタリングの防止です。 充分に考慮しておかないとSWを1回押したつもりでも、何度も押したときと同じ動作を指定増します。 以下に、良く使用するプログラムを示します。 ( 2017/7/5 - XC8用にプログラムを書き換えました )

プログラム例

PushSWが押されるとLEDの表示を増加させる内容です。
PushSWが押されるまで while と delay 文で待つ単純な防止プログラム例です。

//  File name: Anti-Chattering
//  Description: チャタリング防止
//  Notes: 4MHz内部クロック
//    Language: MPLABX  xc8
//    Target: PIC18F14K50

#include <xc.h>
#define _XTAL_FREQ 4000000      // delay_ms(x) のための定義

#define LEDs      LATC
#define pushSW    PORTBbits.RB7    // スイッチを定義

#pragma config FOSC = IRC        //  内部クロック
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO  = OFF, FCMEN = OFF, PLLEN  = ON
#pragma config BORV  = 30,  BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST  = OFF
#pragma config BBSIZ = OFF, LVP    = OFF, STVREN = ON
#pragma config CP1  = OFF, CP0  = OFF, CPD  = OFF, CPB  = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB  = OFF

//----------------------メインプログラム-------------------------
void main(void){
    char count = 0;
    OSCCON = 0b01010010;    //  内部クロック4Mhz
    LATC = 0;
    TRISC = 0;              //  PortC 出力に設定
    // -------------- 繰返し -----------------
    while(1){
        while(!pushSW);     // SWが押されていないことを確認
        __delay_ms(5);      //   チャタリング防止 5mS遅延
        while(pushSW);      // SWが押されるのを待つ
        __delay_ms(5);      //   チャタリング防止 5mS遅延
        LEDs = ++count;     // 表示を1増やす
    }
}

Timer0で内部クロック(4MHz)をカウントし、プリスケラで1/4にして、 約 1mS毎に割込みが発生します。 チャタリング防止はこの割込みルーチン内にプログラムされており、pushSWのチャタリングを排除したSWcleanを生成するとともに、SWが押されると「1」になる SWpress がも作っています。 SWpress は、SW入力を処理するメインルーチン内で「0」に戻しています。

//  File name: Anti-Chattering
//  Description: チャタリング防止
//  Timer0で内部クロック(4MHz)をプリスケラで1/4にして、
//    カウントアップで割込みが発生する(1024uS毎)
//    割込みごとにKeyの状態を確認する。
//  Notes: 4MHz内部クロック
//    Language: MPLABX XC8
//    Target: PIC18F14K50

#include <xc.h>

#define LEDs      LATC
#define pushSW    !PORTBbits.RB7        // スイッチを定義
#define MonCnt    5                     // チャタリングの防止時間

#pragma config FOSC = IRC
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO  = OFF, FCMEN = OFF, PLLEN  = ON
#pragma config BORV  = 30,  BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST  = OFF
#pragma config BBSIZ = OFF, LVP    = OFF, STVREN = ON
#pragma config CP1  = OFF, CP0  = OFF, CPD  = OFF, CPB  = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB  = OFF

// ----------------------------------------------
char SWmonit = MonCnt;    // チャタリング防止回数定義
char SWclean   = 0;       // チャタリングを排除したSW信号
char SWpress = 0;         // チャタリングを排除した「押した」マーク
char SWreles = 0;         // チャタリングを排除した「離した」マーク

//----------------------高優先割込み------------------------
void interrupt Hi_Isr(void){
    if(TMR0IF){                             //Timer0からの割込みを確認
        TMR0IF = 0;                         // 割込みフラッグをクリア
        // チャタリング防止 -----------------------------------------
        if(SWmonit == 0){                   // SWが安定状態時
            if(SWclean != pushSW)               // SWの状態が変更されたら
                SWmonit = MonCnt;               // チャタリング防止をセット
        }else{                              // チャタリング防止中に
            if(SWclean != pushSW){              // SWの状態が変化したままか
                SWmonit--;                      //   変化継続を5回確認
                if(SWmonit == 0){               // 防止期間終了で
                    SWclean = pushSW;           //   新しい状態を反映
                    if(SWclean)SWpress = 1;     //   ONなら 「押した」を1
                    else SWreles = 1;           //   OFFなら「離した」を1
                }
            }else{                              // SWが元に戻ったら
                SWmonit = 0;                    //   SWが安定状態を維持
            }
        }
    }
}

//----------------------メインプログラム-------------------------
void main(void){
    char count = 0;
    OSCCON = 0b01010010;        // 内部クロック4Mhz
    ANSEL  = 0;                 // Port をデジタルに設定
    ANSELH = 0;
    LATC  = 0;
    TRISC = 0;                  // PortC 出力に設定

    T0CON = 0b11000001;         // Timer 0 設定(1mSecごと)
                                // 内部クロックをカウント
                                // 8BIT モード PS_1/4
    TMR0IP = 1;                 // Timer0 からの割込みを高優先に設定
    TMR0IF = 0;                 // Timer0 からの割込みフラッグをクリア
    TMR0IE = 1;                 // Timer0 からの割込みを許可
    RCONbits.IPEN=1;            // 2段階の割込みに設定
    INTCONbits.GIEH=1;          // 高優先割込みを許可
    INTCONbits.GIEL=0;          // 低優先割込みを禁止
    // -------------- 繰返し -----------------
    while(1){
        if(SWpress){                  // SWが押されたら
            LEDs = ++count & 0x7;       // 表示を1増やす
            SWpress = 0;              // 処理済みを明示
        }
        LATC3 = SWclean;
    }
}

上記プログラムと下記プログラムとの差はチャタリングを排除したSWcleanを生成するタイミングにあります。
上のプログラムは、SWが押されるとチャタリングが収まるのを待ってから、新しい状態を反映します。
下のプログラムは、状態が変化するとすぐに新しい状態を反映し、その後一定時間はSWの状態が変わってもSWcleanへの反映を禁止し、チャタリングを排除します。

//  File name: Anti-Chattering
//  Description: チャタリング防止
//  Timer0で内部クロック(4MHz)をプリスケラで1/4にして、
//    カウントアップで割込みが発生する(1024uS毎)
//    割込みごとにKeyの状態を確認する。
//  Notes: 4MHz内部クロック
//    Language: MPLABX XC8
//    Target: PIC18F14K50

#include <xc.h>

#define LEDs      LATC
#define pushSW    !PORTBbits.RB7        // スイッチを定義
#define MonCnt    5                     // チャタリングの防止時間

#pragma config FOSC = IRC
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO  = OFF, FCMEN = OFF, PLLEN  = ON
#pragma config BORV  = 30,  BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST  = OFF
#pragma config BBSIZ = OFF, LVP    = OFF, STVREN = ON
#pragma config CP1  = OFF, CP0  = OFF, CPD  = OFF, CPB  = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB  = OFF

// ----------------------------------------------
char SWmonit = MonCnt;      // チャタリング防止回数定義
char SWclean   = 0;         // チャタリングを排除したSW信号
char SWpress = 0;           // チャタリングを排除した「押した」マーク
char SWreles = 0;           // チャタリングを排除した「離した」マーク

//----------------------高優先割込み------------------------
void interrupt Hi_Isr(void){
    if(TMR0IF){                     // Timer0からの割込みを確認
        TMR0IF = 0;                 // 割込みフラッグをクリア
        // チャタリング防止 -----------------------------------------
        if(SWmonit){                // SW操作後の変更禁止期間なら
            SWmonit--;              //   変更禁止期間を減らす
        }else{                      // 変更可能期間なら
            if(SWclean!=pushSW){    //   状態が変わったなら
                SWclean=pushSW;     //     変更を反映
                SWmonit=MonCnt;     //     変更禁止をセット
                if(SWclean){        //     SWが押されたなら
                    SWpress=1;      //       押されたマークを1
                }else{              //     SWが離れたなら
                    SWreles=1;      //       離れたマークを1
                }
            }
        }
    }
}

//----------------------メインプログラム-------------------------
void main(void){
    char count = 0;
    OSCCON = 0b01010010;        // 内部クロック4Mhz
    ANSEL  = 0;                 // Port をデジタルに設定
    ANSELH = 0;
    LATC  = 0;
    TRISC = 0;                  // PortC 出力に設定

    T0CON = 0b11000001;         // Timer 0 設定(1mSecごと)
                                // 内部クロックをカウント
                                // 8BIT モード PS_1/4
    TMR0IP = 1;                 // Timer0 からの割込みを高優先に設定
    TMR0IF = 0;                 // Timer0 からの割込みフラッグをクリア
    TMR0IE = 1;                 // Timer0 からの割込みを許可
    RCONbits.IPEN=1;            // 2段階の割込みに設定
    INTCONbits.GIEH=1;          // 高優先割込みを許可
    INTCONbits.GIEL=0;          // 低優先割込みを禁止
    // -------------- 繰返し -----------------
    while(1){
        if(SWpress){                  // SWが押されたら
            LEDs = ++count & 0x7;       // 表示を1増やす
            SWpress = 0;              // 処理済みを明示
        }
        LATC3 = SWclean;
    }
}

一般的な処理では、SWclean情報や、SWがOFFになる情報は使用しないことが多くあります。もし、SWが押された ON 情報だけがプログラムで必要なら、多少チャタリング防止は短くすることができます。
チャタリング防止部分のプログラムおよび、そのフローチャートを示します。

//------ SWチャタリング防止 1msループ内 -------
if(SWmonit){                // SWupの確認中
    if(pushSW)SWmonit--;    //   確認中をー1
      else    SWmonit = 5;  //   確認を最初から
}else if(!pushSW){          // 確認済みでDownなら
        SWpress = 1;        //   SWが押された
        SWmonit = 5;        //   確認待ちに
}