ラベル 16F18313 の投稿を表示しています。 すべての投稿を表示
ラベル 16F18313 の投稿を表示しています。 すべての投稿を表示

2023年5月9日火曜日

赤外線で通信する 出入り検知器(まとめ)


 これまで出入り検知器を作ってきて、3作品目で一応納得できるものに仕上がった。

【送信部】

 送信部の回路には特に変更はない。

 【受信部】

受信部にはフォトリレーを追加して発声時以外はオーディオアンプの電源を切るようにした。その結果10mAあった通常時の消費電流を3.0~3.5mAまで低下できた。さらにフォトリレーを追加した結果、発声に伴って外部の回路を制御できるようになった。

 

【その後】

これまでの回路に気圧計とRTC(リアルタイムクロック)を追加した。

しかしそのままではPICの足が足りないので、代償としてLEDを廃止した。追加回路は2段目の基板に組み込んだ。

 気圧計のプログラムを書いているうちにメモリーをほぼ使い切ったのでRTCの処理まで進めなかった。PICをもう少し足の数とメモリー容量の大きいものに変える必要がある。またLEDを廃止した事で内部の状態が分かり辛くなったので、LEDも復活したい所である。


2023年4月26日水曜日

赤外線で通信する 出入り検知器(その2)

【送信部】

  先ず、前回以降送信部のPICを同じペリフェラルを持って安価な16F18313(8ピン)に替えた。ピンの接続変更、及びソフトでのピンマッピング(PPS)の変更以外は何もせずそのまま動かすことができた。

この送信部はPIC16F18313を使って次の様に、秋月の片面ユニバーサル基板(47×36mm)の半分を使ってコンパクトに組み立てる事ができた。この大きさなら何かに組み込むことも容易だ。

送信部は一定間隔でひたすらデータを送信するのみで何も特別な事はしない。

さて、実際のプログラムであるが全体を説明しても冗長なのでキモの部分に絞って説明する。初期設定を終えた後のメインプログラムの主要部分は次の通り。

    INTCONbits.PEIE = ON;     // Enable Peripheral Interrupt
    INTCONbits.GIE  = ON;     // Enable Global Interrupt
    T0CON0          = 0x80;   // Enable Timer0, 8bit, post=1:1
    T0CON1          = 0x90;   // LFINTOSC, Async, Pre=1:1
    TMR0H           = 62;     // tick for every 2ms
    PIR0bits.TMR0IF = OFF;
    PIE0bits.TMR0IE = ON;     // Start Timer0 Interrupt
//main loop    
    while(TRUE){
        SLEEP();              // wake every 2ms and UART intr.
        // Show Battery Warning
        if(low_batt){
            if(--bl_blk_cnt==0){
                r_led_on = !r_led_on;
                R_LED(r_led_on);
                bl_blk_cnt  = (r_led_on) ? BL_BLNK_ON : BL_BLNK_OFF ;
            }
        }else{

            r_led_on = OFF;
            R_LED(
r_led_on);
        }
    }

つまり、Timer0の2ms毎の割込みをONにした後SLEEP()する。SLEEP()は2ms毎及びその他の割込みが起きると目覚めるので、もしその時電圧低下(low_batt)フラグが立っていれば赤色LEDを点滅させる。

 割込みサービスルーチンは次の通り。

void __interrupt() isr(){
    if(PIR1bits.TXIF && PIE1bits.TXIE) sendISR();
    if(PIE0bits.TMR0IE && PIR0bits.TMR0IF){
        Y_LED(ON);
        tickISR();    PIR0bits.TMR0IF = 0;
        Y_LED(OFF);
    }
}

もしUARTの送信可割込みであればsendISR()を呼び出す。Timer0割込みであればY-LEDをONにし、tickISR()を呼び出した後Y-LEDをOFFにする。これによって2ms毎の割込みが機能していることが分かる(黄色LEDが薄く点灯する)。

sendISR()は次の様に、送信データがあれば送信、データが無ければ割り込みをOFFとする。

byte        *bufp; 

void sendISR(void){
    byte d  = *bufp++;          // get next data
    if(d == 0){
        PIE1bits.TXIE = OFF;    // Disable Interrupt
        bufp--;                 // guard
    }else{
        TX1REG = (low_batt)? (d | 0x80): d; // send data
    }
}

ここで送信データのビット7は受信部に電圧低下を知らせるフラグとして使っている。

送信の起動は次の様にバッファにポインタをセットし割り込みを可とすることで行う。通常この行を実行した瞬間に割込みが発生する。

void sendUART(byte *buf){
    bufp            = buf;
    PIE1bits.TXIE   = ON;
}

tickISR()(タイマー割込み)ではカウンタを設けて40ms毎にデータを送信、及び30秒ごとにバッテリー電圧のチェックを行っている。

static int      cnt     = (TX_PERIOD/TICK_TIME);
static byte     key     = KEY_MIN;
static byte     dat[3]  = "  ";
static uint     bccnt   = BC_PERIOD/5;   // battery check counter

void tickISR(){
    // Send data, every 40ms
    if(--cnt==0){
        dat[0] = key;
        dat[1] = key ^ KEY_SWAP;       // toggle lower 7 bits
        sendUART(dat);
        key++; if(key>KEY_MAX) key = KEY_MIN;
        cnt = (TX_PERIOD/TICK_TIME);
    }
    // Battery Check, every 30sec
    if(--bccnt == 0){
        low_batt = is_bat_low();
        bccnt = BC_PERIOD;
    }
}

送信するデータはKEY_MINからKEY_MAXまでのデータを繰り返している。

 バッテリー電圧はA/Dコンバータでチェックする。10ビットA/Dコンバータは2つの参照電圧(Vref+、Vref-)間を1024(=2^10)段階でデジタル化してくれる。参照電圧に内蔵の2.048Vと0Vを選ぶと1ステップが2mVとなる。実際には精度が10ビットも必要ないので上位8ビットを使って1ステップ8mVとしている。さらに電源電圧は3.3Kと1.5Kで分割してA/Dコンバータに与えているので、その比率を加味すると1ステップ25.6mVに相当する。バッテリーの電圧チェックは次の通り。

#define BC_LEVEL        104     // Voltage Threshold, 0.0256V step

boolean is_bat_low(){
    ADCON0bits.GO   = 1;        // Start Conversion
    while(ADCON0bits.GO==1){}   // Wait until complete
    bt_data = ADRESH;
    return (bt_data < BC_LEVEL);
}

このA/D変換は数μsで終わるので実行時間に与える影響はほぼ皆無である。
最後に、A/Dコンバータの初期化は次の様に行っている。

void Init_AD(){
    // AD Converter
    ADCON0bits.CHS  = 4;    // CHS=ANA4,  A4 for input
    ADCON0bits.ADON = 1;    // AD ON
    ADCON1      = 0x53;     // Fosc/16(=1us), Vref+ is FVR
    ADACT       = 0x00;     // No auto conversion
    // FVR
    FVRCONbits.FVREN    = 1;    // Enable
    FVRCONbits.ADFVR    = 2;    // ADFVR=2.048V    
}

(その3)へ続く

2023年4月8日土曜日

赤外線で通信する 出入り検知器(その1)

 PICを使った 赤外線の送受信及びタイマーと割込みの扱いが理解出来たので、これを応用して人の移動を検知してアクションを起こす簡易なセンサー(入退出検出器)を作ってみる。

【概要】

 人の出入りを検知するには焦電素子を使った人感センサーを先ず思いつくが、これは指向性や反応速度が緩いうえに焦電センサーは赤外線輻射量の変化を検知するので前を通る車や風にも反応し条件が整わないと上手く反応できない。超音波やマイクロ波を使ったレーダー式は周囲に物を置いた状態では検知しずらい。カメラの画像解析は良さそうだが高価になりそうという事で、光電管式ネズミ捕りと同様な仕組みをこれまで試した赤外線を使って作ってみる事とした。

 基本的なアイデアは次の通り。


 送信部では赤外線をある短い間隔で水平に発信する。受信部では水平に離れた2点で赤外線を受信し、人が赤外線を横切った場合の赤外線の断を検知して人の移動を判断し何らかのアクションを行う。

【検討】

 赤外線の遮蔽を的確に検知するには短いパルス状の信号を連続的に送る事が好ましいがリモコン受光部の特性から100msの周期中に25msの休止も必要。ノイズの影響を排除するためには偽信号をチェックするカラクリも欲しい。一般にUARTの信号にはパリティを付加できるがPICのEUSARTにパリティの機能は無い。但しデータに9ビット目を付加できるのでソフト的にパリティビットを実現することは可能であるが面倒、という事でビット反転させた2つのデータを連続して送る事で到達チェックすることにした。これで最短34ms毎の検出が可能となる(実際には約40msに設定した)。ちなみに本装置の受光部はTV等のリモコンの赤外線にも反応するが、このやり方で誤検知を防ぐことができる。

 人の移動速度はせいぜい時速4Km(秒速1.1m)とし、人の前後の厚みを25cmと仮定すると1つのセンサーの前を人が通過するのに必要な時間は227msとなるので送信部で40ms毎に信号を出すと受光部で最低5回のパルスの欠落が発生し探知が可能である。

 では2つのセンサーの間隔はどれくらい必要だろうか。出来れば1回でも人が両方のセンサーを同時に遮蔽することが望ましいので20cmでトライしてみよう。20cmの間隔を秒速1.1mで進むと1つ目のセンサーを通過した後2つ目のセンサーに到達するのに180msかかり、その間40ms毎のパルスを4回は遮る事になる。これで検知区間の単独の通過とその進行方向を検知できる。

 さて2つのセンサーで人の出入りを監視するロジックであるが、単に出入りのチェックだけやるのであれば簡単であるが、途中で引き返したり、真ん中に長時間留まって多少左右に動いて作業したり、TV等のリモコンの赤外線に干渉されたり、実用に使うには様々な問題がある。それらを含めてどれだけだけ正確に検知できるか、がソフト作りの腕の見せ所である。

 とりあえずこれまでの経験をもとに次のようなハードウェアを作成した。

【送信部】 

 送信部は次の回路とした。回路で新しく追加したのはA/D変換器を使ってバッテリー電圧を監視できるようにしたところ。バッテリー電圧が概ね2.7Vまで下がると電圧低下の警告が出るようにし、また送信信号にもその情報を入れるようにして受信側で警告が出せるようにした。PICを使うとバラで組むより配線をかなり簡略化できるのが嬉しい。

 次の写真が実際に秋月の汎用基板に組み立てたところ。黄色LEDは割込み処理中に点灯し、赤色LEDはバッテリー電圧低下(2.7V位)で点灯させる。LEDごとにシリーズ抵抗が違うが、黄色はデューティ比が低い一方赤色は連続点灯なので、LEDの明るさを見て暗めの適当な明るさに調整した結果である。この回路全体の消費電流は2.5mA。単2電池二本で数ヶ月持つ事を想定してる。電池3本(4.5Vでも問題なく使える)。

 その後PICを同じペリフェラルを持つ16F18313(8ピン)に替えたがピンの接続変更、及びソフトでのピンマッピング(PPS)の変更以外は何もせずそのまま動いた。

【受信部】

 受信部は次の回路とし、新しく音声合成ICとスピーカを鳴らすためのオーディオアンプを追加した。PICと音声合成ICのインターフェイスはUARTも使えるがPICの2組のEUSARTを赤外線入力に使って余裕が無かったためI2Cを使った。音声合成ICのUARTインターフェイスはPCと繋ぎPCから音声データの発声テストを出来るようにしている。JP3は人の入退室方向を反転させるためのジャンパー、JP4はPICのUSART2をデバッグ用インターフェイスとして使う場合にショートする予定だったがこれまでの所出番はなかった。

  この回路の消費電流は定常時で10mA程度であるが音声発声時に大きく増えるためUSBで電源供給するようにした。また電池駆動も考え、電源電圧が約4.5Vまで低下すると警告を出すようにした。

 次の写真が実際にこの回路を秋月の汎用基板に組み立てたところ。28ピンの音声合成ICが大きな面積を占有している。

なお、PICから制御信号を出す事で音声合成ICやオーディオアンプをスタンバイ状態において更に消費電力を減らす事も可能なようなので後で検証したい。

 
(その2)へ続く