USB-IO2.0(AKI)でスイッチを押すたびにフルカラーLEDを順番に点灯させる

icon 項目のみ表示/展開表示の切り替え

概要

フルカラー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