1.シリアル通信とは?
「シリアル通信」とは、一般にコンピュータ機器を接続する方法の一つで、
接続する線の本数を減らし、かつ遠距離まで信号が送れるようにした方式を
呼びます。このとき信号が1ビットごとにシリアル(直列)に送られるため
シリアル通信と呼ばれます。
2.パソコンとの接続
ここでは通信接続相手がパソコンとします。しかし、このシリアル通信の接続
は標準化されており、「RS232C」と呼ばれ、ほとんどのパソコンやモデム
がこの規格に従っていますので同じように接続することができます。
この接続には「25ピンDSUBコネクタ」か「9ピンミニDSUBコネクタ」
と呼ばれるコネクタが一般的に使われており、それを前提に説明します。
コネクタのピン番号と信号、および簡易的な使い方は下表となります。
ミニDSUB
コネクタ25ピン
DSUB信 号 名 称 簡易な使い方 1 8 CD(Data Carrier Detect) 入力、使わない 2 3 RD(Receive Data) 入力、相手TDに接続 3 2 TD(Transmit Data) 出力、相手RDに接続 4 20 DTR(Data Terminal Ready) 出力、使わない 5 7 SG(Signal Ground) グランド、相手SGに接続 6 6 DSR(Data Set Ready) 入力、使わない 7 4 RTS(Request to Send) 出力、相手CTSと接続 8 5 CTS(Clear to Send) 入力、相手RTSと接続 9 22 RI(Ring Indicate) 入力、使わない
3.シリアル通信制御プログラムの構成
今回の通信用プログラムはタイマー割込みを使っています。この割り込みを使う
ことにより、各ビットの信号を待っている間、コンピュータには他のことをさせる
ことができます。従って、通信をしながら何かをしたい時、例えば表示をしたり
モータを動かしたりするようなことが可能となります。
全体は3つのプログラムモジュールと1つの変数定義部分から出来ています。
(1)変数定義部分
通信プログラムで使う変数や定数を定義しています。ここで重要なのは、
通信速度を変更するためのパラメータです。速度を変えるためには2個の
パラメータの値を変更しアセンブルし直します。
(2)割込み処理モジュール(INTERRUPT)
これは割込みが入って来た時、その時のレジスタを保存したあと、
各フラグを見てどの状態の割込みかを判定して必要な処理へジャンプ
します。また各処理が終了したあと割込みが入った所へ戻るため、
保存しておいたレジスタを元にもどしてリターンします。
(3)送信プログラムモジュール(PUTCHAR)
送信は比較的単純で、送信要求があったら、まずスタートビットを出力し
一定時間のタイマーをスタートさせます。タイマーの割込みが入って
きたら、順次データを1ビットづつシフトしながら出力します。最後に
ストップビットを送信して完了します。
(4)受信プログラムモジュール(GETCHAR)
受信処理の部分で、まずスタートパルスを受信できるようにタイマーを
フルカウントより一つ少ない状態に設定しておきます。そこでスタート
ビットにより+1カウントすると割込みが発生し、スタートビットの検出
が出来たことになります。あとは、一定時間毎のタイマー割込みが発生
する様にしてその都度データを入力します。
これを図で示すと下図の様になります。
ここで少し工夫してあるのは、まずスタートビットの割込みが入って
来たら、確かめるため10usec待ってもう一度入力を読み込んで見て
同じ信号だったらスタートビットをみなします。違っていたらノイズで
割込みが入ったものとして無視し次のスタートビットの割込みを待ちます。
確かにスタートビットを受け取ったら次のタイマーは1.5ビット分の
時間としてスタートします。そしてタイムアップの割込みが入って来たら
データとして入力を読み込みます。これで、間違いなくデータの真ん中
で読み込んだことになります。以下は1ビット分の時間のタイマとして
続けます。
4.変数、定数の定義
(1)通信速度用パラメータ
通信速度を可変にするため2個のパラメータを使っています。その値の求め方
下記のようにします。
まず通信速度から1ビットのパルス幅を求める。次にマイコンのクロックで
それを割ってカウンタの値を求める。(1カウントは4クロック分)
さらにそのカウント値を実現するプリスケーラとTMR0の値を求める。
下表は実際の例で、クロックは10MHzの場合です。
ここで4800、9600bpsの場合には、プログラムの実行時間による遅れの分
BaudRate PulseWidth Counter
prescale
TMR0(BITTMR)
width 300bps 3333.33usec 8333
64(5)
130(7E)
3328usec 1200 833.33 2083
16(3)
130(7E)
832 2400 416.67 1041
8(2)
128(80)
409 4800 208.33 521
4(1)
124(84)
198 9600 104.17 260
2(0)
122(86)
99
を差し引いた値となっています。(約6usec分)
また上記のprescaleの括弧内の値がプリスケーラ設定用の値となり、これ
をBAUDRATEの値として設定します。
プログラムリスト上は下記となっています。
;
;BAUDRATE:boud rate 300 to 9600 at 10MHz clock.
; 5=300bps 3=1200bps 2=2400bps 1=4800bps 0=9600bps
;
BAUDRATE SET 0 ;ここにプリスケーラ値を指定する
BITTMR SET 086H ;TMR0に設定する値で上表の値を指定する
BITTMR1 SET 050H ;スタートビットの時の約1.5ビット分の値
(2)その他の変数
その他汎用に使う変数と、フラグ類は下記で定義されています。
;*************************************
; Define constant module
;*************************************
#DEFINE TXBUSY RESULT,0 ;sending
#DEFINE RXBUSY RESULT,2 ;receiving
#DEFINE RECV RESULT,3 ;receive end
#DEFINE ERROR RESULT,4 ;error bit
;**** Define Variables *****
RESULT EQU 0CH ;current status
WREG EQU 0DH ;wreg save area
SREG EQU 0EH ;status reg save area
BITCNT EQU 0FH ;send bit counter
EXTRA EQU 10H ;stop bit flag
TXREG EQU 11H ;send data buffer
RXREG EQU 12H ;receive data buffer
CNT2 EQU 13H ;counter for delay
5.割込み処理プログラム
割込みが入った時にまず実行する処理です。ここではレジスタの待避、復旧と
各種フラグを見てどの割り込みかを判定しそれぞれの処理に分岐します。
この処理のリストは下記です。
;****************************************
; Interrupt process module
;****************************************
INTERRUPT ;4番地からここにジャンプする
BTFSS INTCON,T0IF ;TMR0の割込みか確認
RETFIE ;違っていたら何もしないで戻る
BCF INTCON,T0IF ;TMR0の割込みフラグクリア
;**** W register & status registerを待避
MOVWF WREG ;W regを待避
SWAPF STATUS,W ;statusをwregに移動
MOVWF SREG ;statusを待避
BTFSC TXBUSY ;送信中か?
GOTO TXNEXT ;送信中なら次のビット送信へ
BTFSC RXBUSY ;受信中か?
GOTO RXNEXT ;受信中なら次のビット受信へ
GOTO STARTBIT ;スタートビット割込み処理へ
;**** registerを復帰させ割込みの入った場所へ戻る
RESTORE
SWAPF SREG,W ;status取り出し
MOVWF STATUS ;status復帰
SWAPF WREG,F ;wreg取り出し
SWAPF WREG,W ;wreg復帰
RETFIE ;次の割込み許可リターン
6.送信処理プログラム
送信はタイマーで一定時間毎に割込みを出し、その都度送信データのビットを
順次送り出す。送り出す先は常にRA3のポートである。
下記リストで説明する。
(1)まず送信要求がCALLされると、PUTCHAR処理ででTXBUSYフラグをセットして
送信中とし、続いてスタートビットを送信してタイマーを1ビット分の時間に
セットしてスタートさせてから割込み待ちとする。(TXSTART)
(2)タイマーがカウントアップして割込むとTXNEXT処理に分岐してデータの送信
を1ビット毎に行う。そのビット毎にタイマーをセットして割込みを待つ。
(3)最後のデータ送信後にはストップビットの送信(STOPBIT)に分岐し1ビット分
のストップビットを出力する。
(4)次の割込みですべて終了しDONEに分岐して割込みを禁止にして終了する。
;************************************
; Transmission process module
;************************************
;送信開始処理
PUTCHAR
BSF TXBUSY ;送信中フラグをセット
MOVLW 8 ;送信データビット数を8にして
MOVWF BITCNT ;ビットカウンタにセット
MOVLW 1 ;ストップビット数を1にして
MOVWF EXTRA ;カウンタにセット
CALL TXSTART ;スタートビット送信
BCF INTCON,T0IF ;割込みフラグクリア
BSF INTCON,T0IE ;タイマ割込み許可
RETFIE
;**** スタートビット送信処理 ****
TXSTART
CLRF TMR0 ;タイマセット
BSF STATUS,RP0 ;page 1
CLRWDT
MOVLW BAUDRATE ;プリスケーラセット
MOVWF OPTION_REG
BCF STATUS,RP0 ;page 0
BCF PORTA,3 ;スタートビットセット
MOVLW BITTMR ;タイマ値取り出し
MOVWF TMR0 ;タイマスタート
RETURN
;****** データビットの送信処理 *****
TXNEXT
MOVLW BITTMR ;タイマ再スタート
MOVWF TMR0
MOVF BITCNT ;全ビット終了か?
BTFSC STATUS,Z
GOTO STOPBIT ;終了時ストップビット送信へ
NEXTTXBIT
DECF BITCNT,F ;ビットカウンタ−1
BSF STATUS,C ;データビットをシフト
RRF TXREG ;
BTFSS STATUS,C ;データビットの0,1により
;RA3に0,1を出力
BCF PORTA,3 ;0 out
BTFSC STATUS,C
BSF PORTA,3 ;1 out
GOTO RESTORE ;return
;**** ストップビット送信処理 ****
STOPBIT
MOVF EXTRA,W ;ストップビット送信済みか?
BTFSC STATUS,Z ;
GOTO DONE ;送信済み終了へ
DECF EXTRA,F ;ストップビットカウンタ−1
BSF PORTA,3 ;ストップビット出力
GOTO RESTORE ;return
;*** 全データ送信完了、終了処理 ****
DONE
BCF INTCON,T0IE ;タイマ割込み禁止
BCF TXBUSY ;送信中フラグクリア
GOTO RESTORE ;return
7.受信処理プログラム
受信は少し処理内容が複雑ですが、流れは単純です。
(1)まず最初に受信要求があると、GETCHARでスタートビットの受信準備処理
を実行します。これにはタイマをフルカウント一つ手前として割込み待ち
とします。
(2)スタートビット入力によりタイマの割込みが入ったら、STARTBITに分岐し
10usec待ってもう一度データを入力しスタートビットである事を確認します。
もしそうで無かったら、ノイズによる誤割込みとして何もせず次のスタート
ビット待ちとして戻ります。(NOISE) 確かにスタートビットだったら、
受信中フラグ(RXBUSY)をセットし、タイマに1.5ビット幅分のタイマ値を
セットして割込み待ちとします。
(3)次からの割込みはデータビットとしてデータ受信(RXNEXT)に分岐します。
ここからは1ビット分の幅の時間にタイマを戻して順次データビットの受信
としてRXREGに格納していきます。(NEXTRXBIT)
最後のデータビットの次はストップビットの受信のはずなのでそれを確認
します。もしストップビットでなかったらエラーとしてERRORフラグをセット
して終了します。終了時には受信中フラグ(RXBUY)をクリアします。また
正常にデータが受信できた時にはデータ受信フラグ(RECV)をセットします。
;*************************************
; Receiving process module
;*************************************
GETCHAR
BSF RECV ;データ受信フラグクリア
MOVLW 9 ;データビット数を8として
MOVWF BITCNT ;ビットカウンタにセット
CLRF RXREG ;データバッファクリア
BCF ERROR ;エラーフラグクリア
;**** スタートビット受信準備処理 ****
CLRF TMR0 ;タイマを初期セット
BSF STATUS,RP0 ;page 1
CLRWDT ;clear WDT
MOVLW 038H ;ウォッチドッグタイマモード
MOVWF OPTION_REG ;でプリスケーラを1にセット
BCF STATUS,RP0 ;page 0
MOVLW 0FFH ;タイマをFFにセット
MOVWF TMR0 ;タイマスタート
BCF INTCON,T0IF ;タイマ割込みフラグクリア
BSF INTCON,T0IE ;タイマ割込み許可
RETFIE ;割込み待ちへ
;**** スタートビット割込み処理 ****
STARTBIT
CLRWDT ;
CALL TIME10 ;10usec待ち
BTFSC PORTA,4 ;再読込みスタートビットか?
GOTO NOISE ;違う時
BSF RXBUSY ;受信中フラグON
;データ受信準備
CLRF TMR0 ;タイマ再セット
BSF STATUS,RP0 ;page 1
MOVLW BAUDRATE ;プリスケーラセット
MOVWF OPTION_REG
BCF STATUS,RP0 ;page 0
MOVLW BITTMR1 ;1.5ビット幅の時間にセット
MOVWF TMR0 ;タイマスタート
GOTO RESTORE ;return
;*** スタートビットでない時の処理 ****
NOISE
MOVLW 0FFH ;タイマ再セット
MOVWF TMR0
GOTO RESTORE ;return
;**** データビット受信処理 ****
RXNEXT
BSF STATUS,RP0 ;page 1
CLRWDT ;タイマ再セット
MOVLW BAUDRATE
MOVWF OPTION_REG
BCF STATUS,RP0 ;page 0
MOVLW BITTMR ;1ビット幅の時間にセット
MOVWF TMR0 ;タイマ再スタート
DECFSZ BITCNT,F ;ビットカウンタ−1、終了か?
GOTO NEXTRXBIT ;次のデータ受信へ
;*** ストップビット受信処理 ***
BTFSS PORTA,4 ;データ入力しストップビット確認?
BSF ERROR ;ストップビットでない時エラ
BCF INTCON,T0IE ;割込み禁止
BCF RXBUSY ;受信中フラグリセット
BCF RECV ;データ受信フラグセット
;
;**** 割込み並列処理を実行する時は、ここに受信完了時の処理を***
; 追加し、処理実行後割込み処理から戻る。
; CALL RECEIVEPROCESS
GOTO RESTORE
;**** データビット受信処理 ***
NEXTRXBIT
BCF STATUS,C ;データの0,1によりRXREG
BTFSC PORTA,4 ;に0,1をセットする
BSF STATUS,C ;1 case
RRF RXREG,F ;set data to RXREG
GOTO RESTORE
;***** 10usec遅延タイマ *****
TIME10 ;10usec
MOVLW 7H
MOVWF CNT2
T_LP2 DECFSZ CNT2,F ;2+3*7-1=22
GOTO T_LP2
RETURN ;22+1=23