RS232cで通信@
PIC16F84を使った通信
▼まずはマイコンとRS232cを接続するドライバを作成
MAX232を買いに行ったらMAX3232が売ってたのでそれを購入
コンデンサ容量が小さくていいらしい
▼実際に作ってみた所
動作確認にはパソコンのRS232cに接続
回路のマイコン側の出力と入力を結線して、
適当にパソコンから文字を送信すると、LEDがチカチカして、そのまま文字が返ってきました
うまく動作しているみたいです
■マイコンの作成
LED表示機で作った基盤をそのまま流用
クロックを10Mのセラロックに変更しました
■タイマー割り込み
よくよくRS232cの通信速度を見ると、
300の倍数になっています
ということは、1/9600 sec のタイマーを作って、32倍すれば
300bpsで通信できると考えられます
また、通信しようと思うと、その倍のスピードでタイマーを設定
して、ビットの真ん中あたりの時間をとらないと、
うまく受信できないと思われます
そこで、1/19200 sec のタイマーを作成して、それを32倍して1/600 secの
タイマー割り込みを作りたいと思います
前作ったPICのアセンブラをチョコチョコ改造しました
;---------------------------------------------------------------
;タイマー割り込みにより実行
;---------------------------------------------------------------
int2 ;タイマー割り込み
;タイマーにはクロックが1/4周期で供給されるため、
;10MHzクロックでは 1/2500000secとなる
;1/19200 sec(52 usec)毎にタイマー割り込みを入れるために
;減算タイマー値に256-130=0x7Eを設定
;しかし、割り込みから、ここまでに0x0Eほどかかるため加算する
movlw 0x7E+0x0E ;タイマー値リセット
movwf TMR0
bcf INTCON,2 ;タイマー割り込みフラグリセット
;割り込み時の処理をここに記述
;1/19200 secでタイマー割り込み
call _300B_TMR
COMF PORTA,1 ;←portAを反転
goto intret
;---------------------------------------------------------------
;タイマー割り込みの設定
;---------------------------------------------------------------
movlw 0x00 ;タイマー値リセット
movwf TMR0
bsf STATUS,5 ;ページを1に切り替え
bsf OPTION_REG,0 ;PS0 プリスケーラの設定
bsf OPTION_REG,1 ;PS1
bsf OPTION_REG,2 ;PS2
bsf OPTION_REG,3 ;PSA プリスケーラをTMRで使用する場合は0,WDTで使用する場合は1
bcf OPTION_REG,5 ;T0CS タイマ0の入力先 1でRA4ピン入力,0でクロック1/4入力
bcf STATUS,5 ;ページを0に切り替え
bsf INTCON,5 ;タイマ割り込み発生許可
;---------------------------------------------------------------
;割り込みの開始
;---------------------------------------------------------------
bsf INTCON,7 ;割り込み許可
;***************************************************************
;メイン
;***************************************************************
main
goto main
_300B_TMR
decfsz TMR_Counter,F
return
MOVLW 0x1F
MOVWF TMR_Counter
COMF PORTB,1 ;←portBを反転
return
1/19200 sec ごとにportAのビットを反転
1/600 sec ごとにportBのビットを反転するようにしました
portBは、推測では、1 / 300 = 0.0033333.....で反転するはずです
portBにオシロを接続してタイミングを確認
およそ3.3msごとにビットが反転しています。
タイマー割り込みがうまくいってるみたいです。
■次に
ポートAのビット0をRS232cの入力と考えて
ビットが立ち下がるタイミングで1バイト分のタイマー割り込みを入れたいと
思います
;---------------------------------------------------------------
;タイマー割り込みにより実行
;---------------------------------------------------------------
int2 ;タイマー割り込み
;タイマーにはクロックが1/4周期で供給されるため、
;10MHzクロックでは 1/2500000secとなる
;1/19200 sec(52 usec)毎にタイマー割り込みを入れるために
;減算タイマー値に256-130=0x7Eを設定
;しかし、割り込みから、ここまでに0x0Eほどかかるため加算する
movlw 0x7E+0x0E ;タイマー値リセット
movwf TMR0
bcf INTCON,2 ;タイマー割り込みフラグリセット
;割り込み時の処理をここに記述
;1/19200 secでタイマー割り込み
;スタートビットが立ったことを検出する
;BIT_Count ビット数をカウントするメモリ
;TMR_Counter タイマー割り込みを分周するためのメモリ
COUNTSET_START
TSTF BIT_Count ;BIT_Countがゼロかテストする
BNZ COUNTSET_END ;ゼロでないときジャンプ
COUNTSET
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ;
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
MOVLW 0x12+0x01 ;Wレジスタに値を代入
MOVWF BIT_Count ;WレジスタからFレジスタに代入
COUNTSET_END
TSTF BIT_Count ;BIT_Countがゼロかテストする
BZ intret ;ゼロのときジャンプ
;1/19200を32分周して1/600を作り出す
decfsz TMR_Counter,F ;Fレジスタを‐1して0ならスキップ
goto intret ;ジャンプ
MOVLW 0x1F ;Wレジスタに値を代入
MOVWF TMR_Counter ;WレジスタからFレジスタに代入
DECF BIT_Count ;Fレジスタを-1する
COMF PORTB,1 ;Fレジスタを反転
goto intret ;ジャンプ
MAX3232を通したデータは反転していますので
スタートビットを検出するのには、ポートのビットがLowになるタイミングを検出
する必要があります
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
MAX3232を通す前の(反転している)信号線のノイズを考えると
Low状態からノイズでHiにはなりやすいですが
Hi状態からノイズによりLowにはなりにくいと考えられます。
上記部分を4回読み出す事によりノイズを検出しています
複数回読み出してみてLowが続かなかった場合ノイズと考え処理を無視します
ポートBとMAX3232の出力線にオシロを繋いでタイミングを確認しました
RS232cの先にはパソコンを接続して300bpsで"A"を送信しました
Aは
16進数で 0x41
2進数で 01000001
■RS232cの波形
@スタートビットにより相手機器に送信開始を伝えます
A値を下位ビットから順に送信します
Bストップビットにより相手機器に送信終了を伝えます
上記@〜Bが送信になります
▼Zを送信した時の波形
Zは16進数では0x5A ですので二進数に直すと
01011010 になります
下位ビットから送信されますので反転すると
01011010
になります
01011010と読み取れますのでZだと確認できます
▼・を送信した時の波形
・は16進数では0xA5 ですので二進数に直すと
10100101 になります
下位ビットから送信されますので反転すると
10100101
になります
10100101と読み取れますので・だと確認できます
■スタートビットのノイズ対策
ビットが立ち下がるタイミングで入る
1バイト分のタイマー割り込みの1バイト目でポートの値を見ることにより
スタートビットの値を見ることが出来ます。
スタートビットの時点でビットが立ち下がったままならば、
正しいスタートビットだと判断できますし
ビットが立ち上がっていたら、それはノイズにより誤動作していると考え
られます
;----------------------------------------------------------------------
;Startビットの確認
;----------------------------------------------------------------------
BIT_ST_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代
SUBLW 0x12 ;Wレジスタから値を引く
BNZ BIT_ST_END ;結果が0以外ならジャンプ
BIT_ST_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_ST_ERR ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_ST_ERR ;ジャンプ;
;Startbitが立っている事を確認
goto BIT_0_END ;ジャンプ;
BIT_ST_ERR
;Startbitが立っていない ノイズであるため受信処理をリセット
MOVLW 0x00 ;Wレジスタに値を代入
MOVWF BIT_Count ;WレジスタからFレジスタに代入
BIT_ST_END
これにより、スタートビットがノイズにより誤動作していると
考えられる場合にはリセットします
■RS232cの受信
スタートビットと同じように、ビットが立ち下がるタイミングで入る
1バイト分のタイマー割り込みのタイミングでポートの値を見れば
そのタイミングのビットの値が読み取れます
それを連結して、バイトにすれば、RS232cの値を受信できるはずです。
;----------------------------------------------------------------------
;0ビット目の取得
;----------------------------------------------------------------------
BIT_0_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代
SUBLW 0x10 ;Wレジスタから値を引く
BNZ BIT_0_END ;結果が0以外ならジャンプ
BIT_0_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_0_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_0_ON ;ジャンプ;
BIT_0_OFF
BCF BUF,0 ;指定ビットに0を立てる
goto BIT_0_END ;ジャンプ;
BIT_0_ON
BSF BUF,0 ;指定ビットに1を立てる
BIT_0_END
;----------------------------------------------------------------------
;1ビット目の取得
;----------------------------------------------------------------------
BIT_1_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x0E ;Wレジスタから値を引く
BNZ BIT_1_END ;結果が0以外ならジャンプ
BIT_1_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_1_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_1_ON ;ジャンプ;
BIT_1_OFF
BCF BUF,1 ;指定ビットに0を立てる
goto BIT_1_END ;ジャンプ;
BIT_1_ON
BSF BUF,1 ;指定ビットに1を立てる
BIT_1_END
現在のビット位置が何ビット目であるかを確認して
目的のビット位置であった場合ポートから値を読み取り
値をバッファに格納するようにしました。
これを8ビット分連結し1バイトを読み出します
■受信の確認
ビットが立っているか見やすいようにポートにLEDを取り付け
バッファの内容をポートの出力するようにしました
パソコンから'Z'の文字を送信して見ました
写真からは見づらいですが、Zの文字コード01011010が受信できている
ことが確認できました
やったー、受信が出来るようになりました
長い道のりでした ふう
■ここまでで作った全ソースコード
;---------------------------------------------------------------
LIST P=16F84
#include <p16F84.inc>
__CONFIG _CP_OFF & _HS_OSC & _PWRTE_ON & _WDT_OFF
;---------------------------------------------------------------
;アドレスに名前を付ける
;---------------------------------------------------------------
;割り込み時にレジスタを退避させる変数
w_temp equ 0x0C
status_temp equ 0x0D
wait_val1 equ 0x0E
wait_val2 equ 0x0F
TMR_Counter equ 0x10
BIT_Count equ 0x11
BUF equ 0x12
;***************************************************************
;リセットベクタ
;***************************************************************
org 0
goto start
;***************************************************************
;割り込みベクタ
;***************************************************************
org 4
;レジスタの退避
movwf w_temp
movf STATUS,w
clrf STATUS
movwf status_temp
;各割り込みに対して適切なアドレスにジャンプさせる
btfsc INTCON,0
goto int0
btfsc INTCON,1
goto int1
btfsc INTCON,2
goto int2
intret
;レジスタの復帰
clrf STATUS
movf status_temp,w
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie ;割り込みから復帰
;---------------------------------------------------------------
;RB0/INT割り込みにより実行
;---------------------------------------------------------------
int0 ;RB4~RB7割り込み
;割り込み時の処理をここに記述
bcf INTCON,0 ;RB4~RB7割り込みフラグリセット
goto intret
;---------------------------------------------------------------
;RB4〜RB7割り込みにより実行
;---------------------------------------------------------------
int1 ;RB0/INT割り込み
;割り込み時の処理をここに記述
bcf INTCON,1 ;RB0/INT割り込みフラグリセット
goto intret
;---------------------------------------------------------------
;タイマー割り込みにより実行
;---------------------------------------------------------------
int2 ;タイマー割り込み
;タイマーにはクロックが1/4周期で供給されるため、
;10MHzクロックでは 1/2500000secとなる
;1/19200 sec(52 usec)毎にタイマー割り込みを入れるために
;減算タイマー値に256-130=0x7Eを設定
;しかし、割り込みから、ここまでに0x0Eほどかかるため加算する
movlw 0x7E+0x0E ;タイマー値リセット
movwf TMR0
bcf INTCON,2 ;タイマー割り込みフラグリセット
;割り込み時の処理をここに記述
;1/19200 secでタイマー割り込み
;スタートビットが立ったことを検出する
;BIT_Count ビット数をカウントするメモリ
;TMR_Counter タイマー割り込みを分周するためのメモリ
COUNTSET_START
TSTF BIT_Count ;BIT_Countがゼロかテストする
BNZ COUNTSET_END ;ゼロでないときジャンプ
COUNTSET
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ;
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto COUNTSET_END ;ジャンプ
MOVLW 0x12+0x01 ;Wレジスタに値を代入
MOVWF BIT_Count ;WレジスタからFレジスタに代入
COUNTSET_END
TSTF BIT_Count ;BIT_Countがゼロかテストする
BZ intret ;ゼロのときジャンプ
;1/19200を32分周して1/600を作り出す
decfsz TMR_Counter,F ;Fレジスタを‐1して0ならスキップ
goto intret ;ジャンプ
MOVLW 0x1F ;Wレジスタに値を代入
MOVWF TMR_Counter ;WレジスタからFレジスタに代入
DECF BIT_Count ;Fレジスタを-1する
;----------------------------------------------------------------------
;Startビットの確認
;----------------------------------------------------------------------
BIT_ST_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代
SUBLW 0x12 ;Wレジスタから値を引く
BNZ BIT_ST_END ;結果が0以外ならジャンプ
BIT_ST_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_ST_ERR ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_ST_ERR ;ジャンプ;
;Startbitが立っている事を確認
goto BIT_0_END ;ジャンプ;
BIT_ST_ERR
;Startbitが立っていない ノイズであるため受信処理をリセット
MOVLW 0x00 ;Wレジスタに値を代入
MOVWF BIT_Count ;WレジスタからFレジスタに代入
BIT_ST_END
;----------------------------------------------------------------------
;0ビット目の取得
;----------------------------------------------------------------------
BIT_0_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代
SUBLW 0x10 ;Wレジスタから値を引く
BNZ BIT_0_END ;結果が0以外ならジャンプ
BIT_0_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_0_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_0_ON ;ジャンプ;
BIT_0_OFF
BCF BUF,0 ;指定ビットに0を立てる
goto BIT_0_END ;ジャンプ;
BIT_0_ON
BSF BUF,0 ;指定ビットに1を立てる
BIT_0_END
;----------------------------------------------------------------------
;1ビット目の取得
;----------------------------------------------------------------------
BIT_1_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x0E ;Wレジスタから値を引く
BNZ BIT_1_END ;結果が0以外ならジャンプ
BIT_1_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_1_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_1_ON ;ジャンプ;
BIT_1_OFF
BCF BUF,1 ;指定ビットに0を立てる
goto BIT_1_END ;ジャンプ;
BIT_1_ON
BSF BUF,1 ;指定ビットに1を立てる
BIT_1_END
;----------------------------------------------------------------------
;2ビット目の取得
;----------------------------------------------------------------------
BIT_2_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x0C ;Wレジスタから値を引く
BNZ BIT_2_END ;結果が0以外ならジャンプ
BIT_2_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_2_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_2_ON ;ジャンプ;
BIT_2_OFF
BCF BUF,2 ;指定ビットに0を立てる
goto BIT_2_END ;ジャンプ;
BIT_2_ON
BSF BUF,2 ;指定ビットに1を立てる
BIT_2_END
;----------------------------------------------------------------------
;3ビット目の取得
;----------------------------------------------------------------------
BIT_3_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x0A ;Wレジスタから値を引く
BNZ BIT_3_END ;結果が0以外ならジャンプ
BIT_3_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_3_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_3_ON ;ジャンプ;
BIT_3_OFF
BCF BUF,3 ;指定ビットに0を立てる
goto BIT_3_END ;ジャンプ;
BIT_3_ON
BSF BUF,3 ;指定ビットに1を立てる
BIT_3_END
;----------------------------------------------------------------------
;4ビット目の取得
;----------------------------------------------------------------------
BIT_4_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x08 ;Wレジスタから値を引く
BNZ BIT_4_END ;結果が0以外ならジャンプ
BIT_4_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_4_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_4_ON ;ジャンプ;
BIT_4_OFF
BCF BUF,4 ;指定ビットに0を立てる
goto BIT_4_END ;ジャンプ;
BIT_4_ON
BSF BUF,4 ;指定ビットに1を立てる
BIT_4_END
;----------------------------------------------------------------------
;5ビット目の取得
;----------------------------------------------------------------------
BIT_5_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x06 ;Wレジスタから値を引く
BNZ BIT_5_END ;結果が0以外ならジャンプ
BIT_5_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_5_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_5_ON ;ジャンプ;
BIT_5_OFF
BCF BUF,5 ;指定ビットに0を立てる
goto BIT_5_END ;ジャンプ;
BIT_5_ON
BSF BUF,5 ;指定ビットに1を立てる
BIT_5_END
;----------------------------------------------------------------------
;6ビット目の取得
;----------------------------------------------------------------------
BIT_6_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x04 ;Wレジスタから値を引く
BNZ BIT_6_END ;結果が0以外ならジャンプ
BIT_6_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_6_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_6_ON ;ジャンプ;
BIT_6_OFF
BCF BUF,6 ;指定ビットに0を立てる
goto BIT_6_END ;ジャンプ;
BIT_6_ON
BSF BUF,6 ;指定ビットに1を立てる
BIT_6_END
;----------------------------------------------------------------------
;7ビット目の取得
;----------------------------------------------------------------------
BIT_7_INIT
MOVFW BIT_Count ;WレジスタにFレジスタを代入
SUBLW 0x02 ;Wレジスタから値を引く
BNZ BIT_7_END ;結果が0以外ならジャンプ
BIT_7_START
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_7_ON ;ジャンプ
BTFSC PORTA,0 ;指定ビットがゼロならスキップ
goto BIT_7_ON ;ジャンプ;
BIT_7_OFF
BCF BUF,7 ;指定ビットに0を立てる
goto BIT_7_END ;ジャンプ;
BIT_7_ON
BSF BUF,7 ;指定ビットに1を立てる
BIT_7_END
; COMF PORTB,1 ;Fレジスタを反転
goto intret ;ジャンプ
;***************************************************************
;スタート
;***************************************************************
start
;---------------------------------------------------------------
;ポートの設定
;---------------------------------------------------------------
clrf PORTA
clrf PORTB
bsf STATUS,5 ;ページを1に切り替え
movlw 0x03
movwf TRISA ;portAをbit 0 to 1 for inputに設定
movlw 0x00
movwf TRISB ;portBを出力に設定
bcf STATUS,5 ;ページを0に切り替え
;---------------------------------------------------------------
;RB0/INT割り込みの設定
;---------------------------------------------------------------
bsf STATUS,5 ;ページを1に切り替え
bcf OPTION_REG,6 ;RB0のエッジ設定は立ち上がり
bcf STATUS,5 ;ページを0に切り替え
; bsf INTCON,4 ;RB0/INT割り込み発生許可
;---------------------------------------------------------------
;RB4〜RB7割り込みの設定
;---------------------------------------------------------------
; bsf INTCON,3 ;RB4〜RB7割り込み発生許可
;---------------------------------------------------------------
;タイマー割り込みの設定
;---------------------------------------------------------------
movlw 0x00 ;タイマー値リセット
movwf TMR0
bsf STATUS,5 ;ページを1に切り替え
bsf OPTION_REG,0 ;PS0 プリスケーラの設定
bsf OPTION_REG,1 ;PS1
bsf OPTION_REG,2 ;PS2
bsf OPTION_REG,3 ;PSA プリスケーラをTMRで使用する場合は0,WDTで使用する場合は1
bcf OPTION_REG,5 ;T0CS タイマ0の入力先 1でRA4ピン入力,0でクロック1/4入力
bcf STATUS,5 ;ページを0に切り替え
bsf INTCON,5 ;タイマ割り込み発生許可
;---------------------------------------------------------------
;割り込みの開始
;---------------------------------------------------------------
bsf INTCON,7 ;割り込み許可
;***************************************************************
;メイン
;***************************************************************
APP_INIT
main
MOVFW BUF ;WレジスタにFレジスタを代入
MOVWF PORTB ;FレジスタにWレジスタを代入
goto main
; COMF PORTB,1 ;Fレジスタを反転
;---------------------------------------------------------------
;ウエイト
;---------------------------------------------------------------
wait_loop
MOVLW 0x00
MOVWF wait_val1
wait_loop1
MOVLW 0x00
MOVWF wait_val2
wait_loop2 NOP
decfsz wait_val2,F
goto wait_loop2
decfsz wait_val1,F
goto wait_loop1
return
END
20060915更新
▲トップページ
>
マイコンなど