センサライト開発(3) 初号機設計

焦電型人感センサは、センサモジュールの電源レギュレータICを交換してと手がかかったのだが、そのわりに、感度があまり良くなく、トイレに入っていると電気が消えてしまう。頭をちょっと動かせば、また点灯するのだが、それも、鬱陶しいので、消灯するまでのタイマーをちょっと長いめに調整し、安定運用と相成った。
今回は、PICの制御プログラムの処理の流れをご紹介。
プログラムの処理を表現するには、いろいろな方法があるが、学生時代からなじんでいる昔なじみのフローチャートがやっぱり自分では一番分かりやすい。
簡単に説明すると、
処理は、上から下に向かって進む。
○は、プログラムの最初と最後。
□は処理。
横が二重線になっている□は、まとまった処理。
まとまった処理は、別のところにその詳細を記述する。
◇は判断分岐。条件によって処理の行き先が変わる。
だいたい、こんなところを抑えておけば、概ね理解できる非常にシンプルな構造。
装置に組み込むプログラムで、特徴的なのは、割込みと言う処理。
通常、プログラムを書くと、最初に何やって、次に何やって…と順番に処理を記述する。でも、例えば、何か仕事をしていて、電話がかかってくる と、仕事を中断して、電話に出て、対応して、また仕事に戻るというようなことをするが、それと同じ事がプログラムでも記述できる。
それが、割込み処理。割込みを使わないで同じように処理する方法もあるが、割込みをうまく使うと、省電力にもできる。最近のCPU(コンピュータチップ)は、何もすることが無い場合はスリープモードと言って電力をほとんど消費しない仕組みが組み込まれている。省電力化するには、お仕事はちゃっちゃと済ませて、終わったらすぐ にスリープするように処理を記述すると、とってもエコになる。
今回の処理も、割込みをたくさん使っている。

1710634155_12 1710634155_78
動作を簡単に説明すると、、、、
まず、電気のスイッチが入ったら、電灯を点灯(電灯回路に電気を流すようにリレーを閉じる)する。
ある一定時間が過ぎるまでに、センサが人の動きを検知したら、点灯時間を延長する。
動きが無く、一定時間が経過したら電気を消灯(リレーを開く)する。
基本的には、それだけなのだが、お昼など、まわりが明るいときはどうするか。
昼でも、スイッチが入ったら、とりあえず、電気は点けた方が良いと思う。スイッチを入れても電気がつかなかったら、電球が切れていると思ってしまうし。
そこで、スイッチを入れて、人の動きがない状態がある一定時間過ぎたら、消灯。その後、人の動きを検知して、再点灯させるときには、照度センサで周囲の明るさを確認し、明るかったら、点灯させない。
さらに、夕方など、だんだん暗くなるようなときには、人の動きを検知する度に、照度センサで、周囲の明るさを確認して点灯するか消灯するかを判断すると。
だいたい、そんな動きになっている。
一定時間を、最初は2分にしていたのだが、すぐに消えてしまうので、8分ぐらいに調整した。人の頭が、10センチぐらい動けば検知するので、8分ぐらいの間には、1度ぐらいは動くだろうと言うこと。じ~~~~っとしていると、消えてしまうので、その場合は、ちょっと頭を動かせば、再点灯してくれる。

前回へ  次回へ
====================================================================
以下にプログラムのソースコードを紹介する。PICのアセンブラという言語。javaやCなどに比べると、低級言語なので、効率は悪いが、処理速度はぴかいち。
; ========================================================
;  人感センサ(割込み)によるACライン制御
;   人感センサ検知→cdsセルで暗さ検知→LED2(AC電源制御)
;  PIC12F629
;  clock:INTRC_OSC_NOCLKOUT 4MHz
;  電源:5V-DC
;  内部クロック4MHz
;  全てのピン(6ピン)をデジタルIOで使用
;  GP0: LED1(出力)(人感センサ状況)
;  GP1: LED2(出力)(AC電源制御)
;  GP2: 人感センサ(GP2/INT)
;  GP3: Cds(入力)
;  人感センサによりGP2/INT割込みを発生させ、LED2を5秒間点灯させる
;  CdsをGP3で検知し、暗い時のみ動作
;  時間待ちは、TMR0割込みを使用
;  人の動きを検出していない時は、SLEEP状態(省電力待機)にする
LIST  P=12f629
#INCLUDE <p12f629.inc>
ERRORLEVEL -302     ; 302警告を非表示にする
CB = _CPD_OFF        ; データメモリ非保護
CB &= _CP_OFF        ; プログラムメモリ非保護
CB &= _WDT_OFF       ; ウォッチドッグタイマ未使用
CB &= _BODEN_ON       ; 低電圧自動リセット
CB &= _PWRTE_ON       ; 電源ON時ウェイトON
CB &= _MCLRE_OFF      ; 外部リセット端子未使用
CB &= _INTRC_OSC_NOCLKOUT  ; 4MHz内部クロック(クロック出力無し)
__CONFIG CB
CBLOCK 020h
save_st         ; STATUSのセーブ領域
save_w         ; W-regのセーブ領域
CNT76          ; TMR0割込みを約5秒(76回)カウントするカウンタ
; 1us(4MHzで4クロック分)×256×256=65.536ms 65.536ms×76=4.981s
DIM1          ; LED PWM 点灯時間用
DIM2          ; LED PWM 消灯時間用
CNT01          ; LEDディマー消灯用カウンタ1
CNT02          ; LEDディマー消灯用カウンタ2
CNT99          ; LEDディマー消灯用カウンタ2
f_int_tmr        ; 割込種別フラグ
; xxxx x210
;  0:GP2/INT割込発生
;  1:TMR0割込発生
;  2:点灯継続タイマ満了
light_st        ; 点灯状態フラグ
ENDC
ORG   0        ; ORG H’0’でも同じ
GOTO  INIT      ; 初期処理に行く
; ======================== 割込み処理 ========================
INTSTART
ORG   4        ; 割込みベクタ(4番地)を指定する。
;  割込み処理中は他の割込みを禁止
BCF   INTCON,GIE   ; 全ての割込みを禁止
;  レジスタ待避定型処理
MOVWF  save_w     ; W-regをセーブ
SWAPF  STATUS,W    ; STATUSレジスタの上位下位を入れ替えW-regに
MOVWF  save_st     ; STATUSレジスタセーブ
;  割込みの種別判定
CLRF  f_int_tmr    ; 割込種別フラグクリア
BTFSC  INTCON,INTF   ; GP2/INT割込み?
GOTO  GP2INT     ; Yes
BTFSC  INTCON,T0IF   ; TMR0割込み?
GOTO  T0INT      ; Yes
GOTO  INTEXIT     ; No
GP2INT   ; GP2/INT割込み処理(人感センサ検知)
BCF   INTCON,INTF   ; 外部割込みフラグクリア
CALL  RESETTIMER   ; 継続表示タイマをリセット
BSF   f_int_tmr,0   ; 割込種別フラグセット(GP2/INT割込発生)
BSF   INTCON,T0IE   ; タイマ割込み許可
GOTO  INTEXIT
T0INT    ; TMR0割込み処理(点灯継続カウントダウンタイマ)
BCF   INTCON,T0IF   ; タイマ割込みフラグクリア
BSF   f_int_tmr,1   ; 割込種別フラグリセット(TMR0割込発生)
DECFSZ CNT76,F     ; CNT76-1が0か?(継続時間経過したか)
GOTO  INTEXIT     ; No
; Yes (点灯継続時間経過)
BCF   INTCON,T0IE   ; TMR0割込み不許可
;  CALL  RESETTIMER   ; 継続表示タイマをリセット
BSF   f_int_tmr,2   ; 5秒経過フラグをセット
INTEXIT
;  レジスタ復帰定型処理
SWAPF  save_st,W    ; save_stの上位下位を入れ替えW-regに
MOVWF  STATUS     ; STATUSレジスタを復帰
SWAPF  save_w,F    ; SWAPを2回行うことでW-regを復帰
SWAPF  save_w,W    ; これはSTATUSレジスタに影響させないため
;  割込み許可
RETFIE         ; GIEセットしてリターン
; ================= PICの初期化 =========================
INIT
BSF   STATUS,RP0   ;■バンク1に切替え
MOVLW  0Ch       ; B’0000 1100′
MOVWF  TRISIO     ; GP2(INT),3は入力,GP0,1は出力
MOVLW  087h      ; OPTIONレジスタの設定 B’1000 0111′
MOVWF  OPTION_REG   ; ^GPPU:1 ,INTEDG:0 ,T0CS:0 ,PSA:0 ,PS2-PS0:111
BCF   STATUS,RP0   ;■バンク0に切替え
MOVLW  07h       ; B’00000111′ SETUP DIGITAL I/O MODE
MOVWF  CMCON      ; GP2-0はデジタルIO
CLRF  GPIO      ; GPIOをクリア(初期状態ではLED消灯)
CLRF  light_st    ; 人感センサ検知状態クリア
;  GOTO  SLEEPMODE    ; テスト用
; ===== 電源ON後、人感センサの回路が安定するまで5秒待ちスリープ =====
BSF   GPIO,GP0    ; 電源ON後人感センサが安定するまでLED1(GP0)点灯
CALL  RESETTIMER   ; 継続表示タイマをリセット
MOVLW  0A0h      ; INTCONの設定(B’1010 0000′)
MOVWF  INTCON     ; GIE:1 ,T0IE:1(TMR0割込み許可)
WAIT5S           ; 電源ON後、人感センサの回路が安定するまで5秒待つ
BTFSS  f_int_tmr,2   ; 5秒経過フラグON?
GOTO  WAIT5S     ; No
CLRF  INTCON     ; 割込み全不許可
BCF   GPIO,GP0    ; 電源ON後人感センサが安定したらLED1(GP0)消灯
GOTO  SLEEPMODE    ; 準備が整ったらスリープし人感センサ割込を待つ
; ================= メイン処理 =========================
LOOP
;  CALL  DISP      ; 人感センサ状態をLEDで表示
; 割込種別の判定
BTFSC  f_int_tmr,0   ; 人感センサ割込?
GOTO  SENSORINT    ; Yes:人感センサ割込処理に
BTFSC  f_int_tmr,1   ; タイマ割込?
GOTO  TIMERINT    ; Yes:タイマ割込処理に
GOTO  LOOP      ; 割込がない場合はLOOP
; 人感センサ割込み処理
SENSORINT
BTFSS  light_st,0   ; 点灯状態を確認
GOTO  TENTOU     ; No :消灯の場合は点灯可否判断に
GOTO  LOOPEND     ; Yes:既点灯の場合はループ終了へ
; 点灯処理
TENTOU
BTFSS  GPIO,GP3    ; cdsセル:暗い?
GOTO  SLEEPMODE    ; No :明るい場合は何もせずスリープモードに
BSF   GPIO,GP1    ; Yes:暗い場合はLED2を点灯
BSF   light_st,0   ; 点灯状態フラグをセット
GOTO  LOOPEND     ; No :ループ終了へ
; タイマ割込み処理
TIMERINT
BTFSS  f_int_tmr,1   ; タイマー割込による割込?
GOTO  LOOPEND     ; No :ループ終了へ
BTFSS  light_st,0   ; 点灯状態を確認
GOTO  LOOPEND     ; No :ループ終了へ
; 消灯処理
SYOTOU
BTFSS  f_int_tmr,2   ; タイマー満了?
GOTO  LOOPEND     ; No :ループ終了へ
BCF   GPIO,GP1    ; Yes:タイマ満了の場合はLED2を消灯
BCF   light_st,0   ; 点灯状態フラグをクリア
GOTO  SLEEPMODE    ; スリープモードに
; 割込種別フラグをクリア
LOOPEND
GOTO  LOOP      ; ループ先頭に
; スリープモードに
SLEEPMODE
MOVLW  0A0h      ; INTCONの設定(B’1010 0000′)
MOVWF  INTCON     ; GIE:1 ,T0IE:1(TMR0割込み許可)
CALL  DIMMEROFF    ; LEDディマー消灯でスリープモードに入る
MOVLW  090h      ; INTCONの設定(B’1001 0000′)
MOVWF  INTCON     ; GIE:1 ,INTE:1(GP2/INT割込み許可)
SLEEP          ; 省電力モードで待機(GP2/INT割込み待ち)
NOP           ; SLEEPから復帰したら実施された後割込み処理に
GOTO  LOOP      ; ループ先頭に
; ============== 人感センサ状態LED表示処理 ======================
RESETTIMER
CLRF  TMR0      ; TMR0クリア
MOVLW  d’76’      ; 人感で点灯継続タイマをリセット
MOVWF  CNT76      ; 点灯継続タイマを初期化
RETURN
; ============== 人感センサ状態LED表示処理(未使用) ==============
DISP
BTFSC  GPIO,GP2    ; 人感センサ = ON?(プルアップされてるためONでLow)
GOTO  LED1OFF     ; No(人感センサ非検知はLED消灯してリターン)
BSF   GPIO,GP0    ; LED1(人感)を点灯する
GOTO  DISPRET
LED1OFF
BCF   GPIO,GP0    ; LED1(人感)を消灯する
DISPRET
RETURN
; ============== スリープする前にLEDをディマー消灯 =============
DIMMEROFF
CLRF  TMR0      ; TMR0クリア
MOVLW  0ffh      ; PWM点灯時間初期化
MOVWF  DIM1      ;
MOVLW  01h       ; PWM消灯時間初期化
MOVWF  DIM2      ;
DIMLOOP
MOVF  DIM1,W     ; 点灯時間をカウンタにセット
MOVWF  CNT01      ;
MOVF  DIM2,W     ; 消灯時間をカウンタにセット
MOVWF  CNT02      ;
BSF   GPIO,GP0    ; LED1を点灯する
WAIT01
CALL  WAIT99     ; 時間稼ぎ
DECFSZ CNT01,F     ; カウンタが0か?
GOTO  WAIT01     ; Wait01ループ
BCF   GPIO,GP0    ; LED1を消灯する
WAIT02           ;
CALL  WAIT99     ; 時間稼ぎ
DECFSZ CNT02,F     ; カウンタが0か?
GOTO  WAIT02     ; Wait02ループ
INCF  DIM2,F     ; 消灯時間を増やす
DECFSZ DIM1,F     ; 点灯時間を減らす
GOTO  DIMLOOP     ; 点灯時間が0になったら終了
DIMRET
RETURN
WAIT99
MOVLW  09h       ; 時間待ちループ
MOVWF  CNT99      ; ↓
WAIT91           ; ↓
DECFSZ CNT99,F     ; ↓
GOTO  WAIT91     ; ここまで
RETURN
END
; ========================================================

(Visited 831 times, 1 visits today)
スポンサーリンク

シェアする

フォローする