PIC18F46K22 EUSART1(RS232C)で送信割込みを使用してパリティ付き送信(アセンブラプログラム)

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

概要

PIC18F46K22のEUSARTモジュールを使用しRS232Cを経由してパソコンと通信するプログラムである。
タイマー割り込みにより0.2秒置きのタイミングを作成します。そのタイミングで送信割込みを使用して偶数パリティを付けて文字列を送信します。
送信に割り込みを使用すると送信終了を割り込みで知ることができますので、送信中に別の処理を行うことができます。例えば9600bpsの場合、1byteのデータは最速でも約1msの時間待つ必要があります。64MHzでPICを動作させている場合、送信中に16000命令も実行することができます。
秋月電子 PIC18F46K22使用 マイコンボードをベースとし半田付けされている水晶20MHzをH8/3048ボードの16MHzと交換し64MHzで動作可能とした。このボードはICSP端子を備えておりPICKIT 3で書き込みができ、電源はミニUSBで供給可能である。またユニバーサル基板になっているので簡単に回路を追加することができる。
ちなみに水晶が20MHzの場合は、通信速度がかわるので設定を変更しなければならない。
EUSARTの設定値の計算はPIC18 EUSART ボーレート計算を参照してください。
使用メモリは以下のとおりです
プログラムメモリ 275byte使用
回路はPIC18F46K22 EUSART1(RS232C)で受信割込みを使用してパリティ付き受信(アセンブラプログラム)のとおりである。

通信設定

RS232C 19200bps 8bit ストップビット1 パリティ 偶数 フロー制御無し

プログラムの説明

初期化

EUSART1の初期化し通信仕様を設定します。
送信データーを書き込可能な時に発生する割り込みを禁止状態にしておきます。
timer0を1m秒周期に設定し、高レベル割込みに設定します。
割り込みは高位と低位の2種類使用できます。
送信割込みの優先順位をTX1IPビットにより低レベルに設定します。
優先順位割り込みを優先するためにIPENビットをセットします。
上記の割り込みは周辺の割り込みですので有効にするためにPEIEビットをセットします。
高位割り込みを許可するためにGIEビットをセットします。
割り込み発生時のジャンプ先は、割込みベクターでROMアドレスに高位が0008h、低位が0018hにジャンプします。通常は、このアドレスにgoto命令を記述して割り込み処理ルーチンへジャンプさせます。
timer0割込みを有効にしてから、受信データが発生するまで無限ループで待機します。

低位割り込み処理ルーチン intl

送信可能状態となると割込みが発生しintlにジャンプします。
低位割り込みの場合、Wレジスタ、バンクレジスタの値は自動に保存されないので、スタックに保存します。
複数の割り込み要因を許可していないので、割り込み要因をボーリングする作業をしておりません。
buf内にASCIIZ形式で文字列が保存されているので送信する文字のアドレスをbuf_adsから取り出しFSR1に格納します。
FSR1の示すアドレスから1文字を取り出します。文字が0の場合は、送信割込みをTX1IEビットで禁止します。
文字が0以外の場合は、サブルーチンparity2cで文字のパリティーを計算します。Cフラグの値によりTX9Dビットを設定します。 文字をTXREG1にコピーして送信を開始します。
FSR1を1文字分進めてアドレスをbuf_adsに保存します。
スタックからWレジスタ、バンクレジスタの値を復帰します。

高位割り込み処理ルーチン inth

timer0の割込みによりinthにジャンプします。
高位割り込みの場合、Wレジスタ、バンクレジスタ及びPCの値はPIC内の専用レジスタに保存されます。割り込みから復帰する場合は、retfie FAST命令を使用して保存された値によりWレジスタ、バンクレジスタ、PCを復帰します。
複数の割り込み要因を許可していないので、割り込み要因をボーリングする作業をしておりません。
1ms置きに割込みが発生するので200回の割込み間隔に1回、eusart1p_putsを呼び出し文字列を送信します。

eusart1p_puts

buf内にASCIIZ形式で文字列が保存されているので送信する文字のアドレスをbuf_adsに格納します。
送信割込みをTX1IEビットで許可します。
割込みが許可されると送信割り込みが発生します。

parity2c

PIC18のステーラスレジスターにはパリティーを示すフラグがありません。ちなみにZ80等には存在します。
Wレジスタの1のビット数を数え偶数の場合はCフラグを0、奇数の場合は1をセットします。
ビット数を数えるには1ビットずつシフト命令を使用してシフトさせキャリーフラグのチェックを8回か繰り返す方法が一番簡単かと思います。
ここでは、先に上位4bitと下位4bitの排他的論理和をとります。 その後はその結果と右シフトした結果とを排他的論理和をとります。 もう一度、結果と右シフトした結果とを排他的論理和をとると全ビットのパリティーが0ビット目に反映されます。さらに右シフトすると0ビット目がCフラグに反映されます。
計算過程については、PIC18の標準命令セットを参照願います。

パリティビットの設定について

マニュアルを見ているとTXREGxレジスタにデータを書き込む前にTXSTAxレジスタのTX9Dビットを設定すれば良いように書いてある。
最初、TSRレジスタが空でTXREGxレジスタに書き込めることを確認するためにTXSTAxレジスタのTRMTビットをチェックしてセットされていればTX9DにパリティをセットしてTXREGxレジスタにデータを書き込んでみた。
オシロスコープで確認するとパリティビットは送信されているが、プログラムでbcf命令でクリアしてもbsf命令でセットしても送信されているパリティビットに反映されていないことが判明した。
ちなみにパソコン側でターミナルソフトにTera Term Version 4.92を使用してみたところ、パソコン側のパリティを偶数、奇数、無いずれに設定しても正しい文字が表示されることが分かった。
さらにlenovo YOGA PRO3←→秋月USBシリアル変換ケーブル(スケルトン)←→リバースケーブル←→パソコンマザーボードX79 Extreme4-Mの様に2台のパソコンをクロスケーブルで接続しお互いにTera Termを立ち上げて通信したところやはりパリティに関係なく正しく文字が送受信できてします。
PIC18←秋月USBシリアル変換ケーブル(スケルトン)←パソコンマザーボードX79 Extreme4-Mでパソコン側からパリティを送信するとPICではパソコンで設定したパリティが正常に受信される。
TXREGxレジスタが空の状態を示すTX1IF割込みを使用してTX9Dを設定したところ、正常にパリティビットを送信することができました。
TRMTビットはTSRレジスタ(シフトレジスタ)が空の状態を反映するのに対してTX1IFはTXREGxが空の状態を反映します。
TRMTビットをチェックするとデータを連続して送信したい場合でも1送信クロック分空きが発生するのに対してTX1IFはTXREGxからTSRへ転送されてから直ちに発生するため、データを隙間なく送信することができます。
正常に動作しない例
usart1p_write ;   USART1へWREGの1byte書き込み 
       btfss    TXSTA1,TRMT ; TSR空か
       bra      usart1p_write
       movwf    POSTDEC2
       call     parity2c ; パリティ計算 キャリーフラグに反映される
       bc       p_l1    ; bc:奇数パリティ、bnc:偶数パリティ
       bsf      TXSTA1,TX9D
       bra      p_end
p_l1
       bcf      TXSTA1,TX9D
p_end
       movf     PREINC2,w

       movwf    TXREG1
       return

ソースファイル

以下のファイルで構成されている
eusart7ap.asm ・・・ メインプログラム

ソースファイルのダウンロード eusart7ap.zip

; EUSART1を用いたRS232Cパリティ付送信テストサンプルプログラム(timer0使用) Version 1.00
; RAM上のASCIIZ文字列を割り込みで送信。
; timer0の高レベル割り込みにより送信周期を設定(0.2秒間隔)
; EUSART1の低レベル割り込みによりRAM上のASCIIZ文字列を送信。

; 慈渓博瑞テクノロジー株式会社 PIC18F46K22 マイコンキット Ver2013.12.08用
;   http://akizukidenshi.com/catalog/g/gK-07231/
;   水晶は16MHzに交換してPICを64MHzで駆動
; MPLAB X IDE v3.45 Microchip MPASM(v5.70)
; PicKit 3
; PC側のターミナル(例えTera Term)と通信を行う
; 19200bps 8bit ストップビット1 パリティ:偶数 フロー制御無し
; RC2: Blue LED
; RE2: Red  LED
        #INCLUDE <p18f46k22.inc>
        ; 水晶発振(16MHz) クロック分周無 PLL有効(*4) プライマリクロック有効  ウォッチドッグタイマ無効 低電圧プログラム書き込みモード無効
        CONFIG FOSC = HSHP,PLLCFG=ON,PRICLKEN=ON,WDTEN=OFF,LVP=OFF

TMR0SET EQU     d'131'  ; 1/(64MHz/4)*128*(256-131)=0.001m秒
 
        ; プログラムメモリのアドレスadsをTBLPTRレジスタに設定
LDTBLPTR MACRO   ads
        movlw   UPPER ads
        movwf   TBLPTRU
        movlw   HIGH ads
        movwf   TBLPTRH
        movlw   LOW ads
        movwf   TBLPTRL
        ENDM
 
STACK_MAX EQU   d'32'
BUF_MAX   EQU   d'32'
 
bank1   IDATA 060h
stack1  RES     STACK_MAX ; スタックエリア      
 
acs_bank     UDATA_ACS     ; 変数の定義 アクセスバンク
count   RES     1 ; 周期
buf_ads RES     2 ;バッファ先頭位置
buf RES BUF_MAX

        CODE
        ORG     0
        goto    start    ;   リセット時
        org     08h
        goto    inth     ;   高位割り込み
        org     18h
        goto    intl     ;   低位割り込み
        
start
        BANKSEL ANSELB
        lfsr    2,stack1+(STACK_MAX-1)  
;       USART初期化
        BANKSEL ANSELC
        
;       movlw   b'00100100' ; CSRC=0:非同期 TX9=0:8bit BRGH=1:高速
        movlw   b'01100101' ; CSRC=0:非同期 TX9=1:9bit BRGH=1:高速   

        movwf   TXSTA1
;       movlw   b'10010000' ; シリアル 8bit
        movlw   b'11010000' ;TX9=1:9bit
        movwf   RCSTA1
; 19200bps
        movlw   d'207'          ; 64MHz/(16*19200)-1=207 19230bps 0.16%
; 38400bps
;       movlw   d'103'          ; 64MHz/(16*38400)-1=103 38462bps 0.16%
; 115200bps
;       movlw   d'34'          ; 64MHz/(16*115200)-1= 114286bps -0.29%
        movwf   SPBRG1
        movlw   b'00111111'
        movwf   ANSELC,BANKED
        movlw   b'11111011' ;   RC2をOUT
        movwf   TRISC
        movlw   b'00000000'     ;   RC2=offを出力
        movwf   PORTC

        movlw   b'11111011'
        movwf   ANSELE,BANKED
        movlw   b'11111011' ;   RE2をOUT
        movwf   TRISE
        movlw   b'00000000'     ;   RE2=offを出力
        movwf   PORTE

;   Timer0を設定する
        movlw   b'11000110'     ;   8bit FOSC/4 1:128
        movwf   T0CON
        movlw   TMR0SET
        movwf   TMR0L

        ; ROM内の文字列をRS232Cで送信
        LDTBLPTR open_msg_str
        lfsr    1,buf
loop2
        tblrd   *+
        movf    TABLAT,W
        bz      loop3
        movwf   POSTINC1
        bra     loop2
loop3   
        movwf   POSTINC1
        
        ;   Timer0割り込み許可
        bsf     INTCON,TMR0IE
        
        bcf     LATC,2  ;   Blue LEDを消灯
        bcf     LATE,2  ;   Red LEDを消灯  

        bcf     IPR1,TX1IP      ;   低レベル割り込み
        bsf     INTCON2,TMR0IP  ;   高位割り込み
        bsf     RCON,IPEN       ;   割り込み優先度有効
        bsf     INTCON,PEIE     
        bsf     INTCON,GIE              
        bra     $

intl    ;   低位割り込み (EUSART1送信)  
        movwf   POSTDEC2
        movff   FSR1H,POSTDEC2
        movff   FSR1L,POSTDEC2

        movff   buf_ads,FSR1L
        movff   buf_ads+1,FSR1H
        movf    POSTINC1,w
        bnz     next_write1
        btg     LATE,2
        bcf     PIE1,TX1IE  ;   送信割り込み禁止
        bra     intl_end        
next_write1     
        movff   FSR1L,buf_ads
        movff   FSR1H,buf_ads+1
        
        movwf   POSTDEC2
        call    parity2c    ;   パリティ計算

        bnc     p_l1    ; bc:奇数パリティ、bnc:偶数パリティ
        bsf     TXSTA1,TX9D
        bra     p_end
p_l1
        bcf     TXSTA1,TX9D
p_end
        movf    PREINC2,w
        movwf   TXREG1  
intl_end
        movff   PREINC2,FSR1L
        movff   PREINC2,FSR1H
        movf    PREINC2,w
        retfie

inth    ;   高位割り込み 1ms置きに呼び出される
        bcf     INTCON,TMR0IF ;   割り込みフラグクリア
        movf    count,w
        bz      write1
        decf    count
        bra     inth_end
write1  ; 200msの周期
        btg     LATC,2  ;   Blue LEDを点灯
        movlw   d'200'
        movwf   count
        
        call    eusart1p_puts
inth_end        
        movlw   TMR0SET
        movwf   TMR0L
        retfie  FAST

eusart1p_puts   ;   buf内の文字列を割り込みで送信する。
        lfsr    1,buf
        movff   FSR1L,buf_ads
        movff   FSR1H,buf_ads+1
        btg     LATE,2
        bsf     PIE1,TX1IE  ;   送信割り込み許可
        return
        
;   パリティ計算をし結果をcに保存 偶数パリティ
;   WREG:引数
;   FSR2:スタック 最大1byte消費
parity2c
        movwf   POSTDEC2
        swapf   WREG
        xorwf   PREINC2,W
        movwf   POSTDEC2
        rrcf    WREG
        xorwf   PREINC2,W
        movwf   POSTDEC2
        rrcf    WREG
        rrcf    WREG
        xorwf   PREINC2,W
        rrcf    WREG
        return

open_msg_str
        DB      "¥rPIC18F46K22 EUSART¥r¥n",0

        END