山本ワールド
PIC18F46K22 EUSART1(RS232C)で送信割込みを使用してパリティ付き送信(アセンブラプログラム)
概要
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
Copyright (C) 2012 山本ワールド All Rights Reserved.