山本ワールド
USB-IO2.0(AKI)でスイッチを押すたびにフルカラーLEDを順番に点灯させる
概要
フルカラーLEDをスイッチを押すたび(スイッチが押された瞬間)に色(白 黄 紫 赤 水 緑 青 消灯 の順)を変える。RB4 RB5 RB6にLEDを接続する。
クロックはUSB-IOで接続済みの12MHzのセラミック振動子を使用する。USB-IO2(AKI)のプログラムを書き換えて使用する。プログラムを書き込むことにより購入時付属のサンプルプログラムでIO操作はできなくなるので注意。書込みはPICKit3を前提とする。
回路図(PNG) 回路図(PDF) 回路図(DXF)
プログラムの説明
外部クロックの設定
USB2.0を動作させるには内部クロック48MHzが必要である。本プログラムでは0.5秒置きにLEDを点滅させるだけなので、クロックの種類は問わないので、48MHzをクロックとして使用することにする。アセンブラソースのCONFIGで指定する。
使用するLEDと電流制限抵抗
LEDは色により順方向電圧が異なるため、色ごとに抵抗値を変えた。
IOポートの設定
使用するIOポートのピンがアナログ入力と共用(ピン配置)となっているため、ANSEL、ANSELHレジスタによりピンをデジタル入出力に設定する。ピンを出力にするためTRISA、TRISB、TRISCレジスタをクリアする。
IOポートに出力する
PORTBレジスタに書き込むことにより出力することができる。
スイッチのチャタリングを除去する(サブルーチン sw1_in)
チャタリングとはスイッチが押されたり・離されたときにスイッチの接点が振動でしばらくOn/Offする現象である。チャタリング対策をしないとスイッチを1回押したにもかかわらず数回押したような現象が発生します。
チャタリングを除去するには、1回スイッチの状態を読み込み10ms程度待ってからもう一度読み込み前回と値が同じであればチャタリングしていない、値が変化していればチャタリング中なのでもう一度10ms待って前回値が同じかどうか比較する。同じになるまで繰り返すことでチャタリングが除去できる。前回の値との比較はXORによってビット1があれば変化があったとみなせる。
SW10にスイッチの状態が返される
スイッチの押された瞬間・離された瞬間を検出する(サブルーチン sw1_trg_in)
サブルーチン sw1_inの前回の戻り値と今回の戻り値を比較することにより検出している。
SW1_TRGに変化したスイッチ、SW10にスイッチの状態が返される
10m秒を得る
3段ループにより約0.5秒の時間待ちを作るプログラムをサブルーチン化している。
アセンブラソース
ソースのダウンロードsw1.zip
; RB6:Red LED,RB5:Green LED,RB4:Blue LED,RC0:SW 点灯テスト
; スイッチが押された瞬間に色を変化させる 白 黄 紫 赤 水 緑 青 消灯 の順で変化
; チャタリング対策有り
; RB7の値も変化しているので注意
#INCLUDE <p18f14k50.inc>
CONFIG FOSC = HS,CPUDIV = NOCLKDIV,PLLEN=ON,WDTEN=OFF,LVP=OFF;not WDT
Tcount1 EQU 0
Tcount2 EQU 1
Tcount3 EQU 2
SW10 EQU 3 ; 前々回の入力値
SW11 EQU 4 ; 今回の入力値
SW12 EQU 5 ; 前回の入力値
SW1_TRG EQU 6 ; 変化したビットが1となる
Tcount EQU 7 ; 押された回数の16倍
org 0
goto start
start
movlw 0fh
clrf ANSEL ; RC3-RC0,RA4をデジタル入力バッファに設定
clrf ANSELH ; RB5-RB4,RC7-RC6をデジタル入力バッファに設定
clrf SLRCON ; PORTA,PORTB,PORTCをスルーレートを標準に設定
clrf TRISA ; PORTAを全部出力に設定
clrf TRISB ; RB7-RB4を出力に設定
movlw 01h ; RC0のみ入力に設定
movwf TRISC
movlw 01h
movwf SW10 ; スイッチが押されていない状態で初期化
clrf Tcount
clrf PORTB
loop
call sw1_trg_in
btfss SW1_TRG,0
goto loop ; スイッチに変化がない
btfsc SW10,0 ; btfssを使用すると離された場合に色を変化させられる
goto loop ; スイッチが離された場合
movf Tcount,W ; スイッチが押されたので色を変化させる
addlw 010h
movwf Tcount
movwf PORTB ; LEDを点灯
goto loop
sw1_trg_in ; SW1前回の読み出しから変化したか検出する。(押した・離した瞬間を検出)
; SW1_TRG スイッチの状態が変化したビットが1にして返す
; SW1の状態を入力しSW11に返す 0:Off 1:On
call sw1_in
movf SW10,W ; 前回sw1_trg_inが呼び出された時のSWの状態
xorwf SW11,W ; SW状態が変化したビットが1となる
movwf SW1_TRG
movf SW11,W
movwf SW10
return
sw1_in ; SW1の状態を入力しSW11に返す 0:Off 1:On
movf PORTC,W
andlw 01h ; bit0以外はクリアする
movwf SW12
call wait10
sw1_loop
movf PORTC,W
andlw 01h ; bit0以外はクリアする
movwf SW11
xorwf SW12,W ;チャタリングがあるビットは1となる
btfsc STATUS,Z ; Zフラグが0の場合は次の命令をスキップする
goto sw1_exit ; チャタリングが収まったので入力値として採用する
movf SW11,W
movwf SW12
call wait10 ; 10ms待機
goto sw1_loop
sw1_exit
return
wait10 ; 約10ms待機
movlw d'200' ; 50μs*200=10ms
movwf Tcount2
dloop21 ; t=(12+12*count3)/48MHz 50μs
movlw d'199' ; 4clock
movwf Tcount3 ; 4clock
nop ; 4clock
dloop31
decfsz Tcount3 ; 4clock
goto dloop31 ; 8clock
decfsz Tcount2
goto dloop21
return
END