土曜日, 10月 19, 2019

PIC24FV16KM202 スイッチ読み込み(基本的...)

勤務先のソフト屋さんに相談したら,あまりに基本的で怒られそうな案件だ...

だが,自分の大切な記録として残しておく。

設計仕様
  • RA1とRB3に接続した押しボタンスイッチで,PICの動作を変えたりできるようにする。
  • とりあえずテストのため,ボタンが押された状況をUART(printf)で送信。
  • ボタンは「オフトリガー」すなわちある程度押され,離した時に処理を開始する。
  • [RA1] 単独,[RB3] 単独,[RA1] と [RB3] の同時押し,以上3つを判定する。
オフトリガーで同時押しも実装しようとしたのは,micro:bitが良い動きだったから。
ボタンで割り込みがかかるとかっこいいのだが,難しそうなので諦め,mainループ内で判定することにした。

/**
  Section: Included Files
*/
#include "mcc_generated_files/system.h"
#include "mcc_generated_files/mcc.h"
#include <stdio.h>

/*
                         Main application
 */
unsigned long int GLOBAL_TIME = 0;
unsigned long int NEXT_TIME = 0;
char RECEIVED_CHAR = ' ';

char prev_key_state = 3;
char current_key_state = 3;
char key_data = 3;
char pressed_key = 3;

char KEY_STATE = 0;

void My_TMR1_ISR(void)                     
  {
    GLOBAL_TIME++;
    current_key_state = ((_RA1)<<1)|(_RB3);
    if (GLOBAL_TIME>NEXT_TIME) {
        // printf("Interrupted at %lu.\n",NEXT_TIME);
        NEXT_TIME=NEXT_TIME+100; // means 1 sec
        // printf("RA1 state:%d\n",_RA1);
        // printf("RB3 state:%d\n",_RB3);
        // printf("current_key_state = %d.\n",current_key_state);
    }
    switch(KEY_STATE) {
        case 0:
            if (current_key_state != prev_key_state) {
                KEY_STATE=1;
                prev_key_state=current_key_state;
            }
        break;
        case 1:
        case 2:
            if (current_key_state == prev_key_state) {
                KEY_STATE++;                
            } else {
                KEY_STATE=0;
            }
        break;
    }
   }

int main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    TMR1_SetInterruptHandler(My_TMR1_ISR);  
    NEXT_TIME=100;
    // TMR1_Start();
    while (1) {

        // test code
        _LATA0=(_RA1)*(_RB3); // means LED=ON when RA1 and/or RB3 are pressed

        // UART RX
        if (UART1_IsRxReady()) {
            RECEIVED_CHAR=UART1_Read();
            printf("%c was received at %lu.\n",RECEIVED_CHAR,GLOBAL_TIME);
            // printf(" -->> current_key_state = %d.\n",current_key_state);
            // printf(" -->> prev_key_state = %d.\n",prev_key_state);
            // printf(" -->> SW_STATE = %d.\n",KEY_STATE);
        }
        
        // KEY routine
        if (KEY_STATE==3) {
            key_data=current_key_state;
            KEY_STATE=0; // means clear
            // printf("key_data = %d.\n",key_data);
            if (key_data==3) {
                switch (pressed_key) {
                    case 3:
                        break;
                    case 1:
                        printf("RA1 pressed.¥n");
                        // RA1 program
                        pressed_key=3;
                        break;
                    case 2:
                        printf("RB3 pressed.¥n");
                        // RB3 program
                        pressed_key=3;
                        break;
                    case 0:
                        printf("Both RA1 and RB3 pressed.¥n");
                        // RA1 and RB3 program
                        pressed_key=3;
                        break;
                }
            } else {
                pressed_key = pressed_key & key_data;
            }
        }
    }

    return 1;
}



いわゆる「チャタリング処理」を施している。いろいろ試行した結果,20msecとした。タイマーを用いているが,のちのち間違えそうなので,タイマーそのものは10msecごと。3回読んで(つまり20msec間)スイッチの状態が同じなら,チャタリングではないと判定した。

それでも,「同時押し」では,例えば [RA1] 押した -> さらに[RB3] 押した と離散的なデータが取れてしまう。考えた末,やはりオフトリガー,すなわちスイッチが1個,または2個完全に離された状態を判定して,そこまで片方しか押されなかったのか,同時押しだったのかを覚えておくようにした。最後の方の pressed_key = pressed_key & key_data; 

スイッチが2個だけなので,単純にビット操作を使うとうまくいった。

0 件のコメント: