Renesas Synergy™

FAQ 1006980 : 8ビットのタイマHと汎用のポートを用いてUARTを実現した簡単なプログラムがほしい。

ここでは、調歩同期通信で9600~19200ボーの通信速度で、データ長は8ビット、パリティはなし、ストップ・ビットは1ビットでLSBファーストの通信に対応するものとします。また、通信は半二重で行なうものとします。
ソフトウェアによるUARTを実現する際の考え方は、「ソフトウェアによるUART機能」を参照して下さい。


[プログラムの概要]
このプログラム例は大きく分類して、以下の部分で構成されています。
①ボー・レート・キャリブレーション部
②INTP1によるデータ受信処理部
③受信処理起動部
④データ送信処理部

①のボー・レート・キャリブレーション部は高速内蔵発振クロックを使用する際の補正を行なうための部分です。外部クロックやセラミック発振子等を用いる場合には必要ありません。

②がスタート・ビットの立下りによるINTP1で起動される処理で、調歩同期通信の受信処理を行なう部分です。基本的に割り込み処理であるために、 結果はレジスタではなく、RAMに受信したデータと結果のフラグを格納します。半二重通信であることから、常にスタート・ビットを待っている訳ではありま せん。必要なときに③の処理で起動する必要があります。1キャラクタのデータを受信完了すると、INTP1割り込みとタイマH割り込みはマスクされ、タイ マHは停止します。

③では受信(実際にはスタート・ビット待ち)を起動するために、必要なフラグをセットしてINTP1割り込みを許可します。ここでは、受信処理の起動だけを行なうので、スタート・ビットがくるまでは送信以外の他の処理を実行可能です。

④はデータ送信処理を行ないます。送信タイミングをタイマHの割り込みで得ていますが、ベクタ割り込みは使用していません。そのため、他の処理と並行して実行はできません。



[サンプリング・タイミングの発生]
このプログラムでは、受信でのサンプリング・タイミングや送信のためのタイミング生成用にタイマHを用いています。ただし、受信の場合に実際のサンプリング・タイミングのバラツキを少なくするために、タイマHの割り込みをHALT命令で待ち合わせて処理しています。


[ボー・レートのキャリブレーション]
高速内蔵発振器からの誤差が大きいクロックを使用することを考慮して、通信動作の前にキャリブレーションを行ないます。このための簡単な方法としては、通 信相手から8ビット分の連続したロー・レベル(データとしては80H)を受信して、その時間を計測します。考え方については、「ソフトウェアによるUART機能」を参照して下さい。

CAL:    DI                              ; 割り込みは禁止
MOV     INTM0,#00110000b        ; INTP1は両エッジ検出に設定
MOV     MK0,#11110111b          ; INTP1のマスク解除
MOVW    HL,#0
PRELOOP:
BF      RxDPIN,$PERLOOP         ; 端子がハイになるのを待つ
CLR1    PIF1                    ; 擬似検出をクリア

HALT                            ; 2:立下りエッジ待ち
;  割り込み受け付けには3~5クロック必要
CLR1    PIF1                    ; 6:割り込み要求をクリア
MLOOP:
NOP                             ; 2:時間調整用
INCW    HL                      ; 4:時間計測
BF      PIF1,$MLOOP             ;10:割り込み要求待ち

ここで得られた回数をクロック数(1カウント=16クロック)に変換し、測定したビット数(8)で割ることで、(最終的に2倍すると)実際のデータ送受信タイミング(間隔)を得ることができます。
この時間をタイマHで計測する場合には、カウント・クロックを周辺機能動作クロックの1/4に設定し、上記カウント値を単純に1/2することでタイマHで のカウント数が得られます。このための具体的なプログラムは以下のようになります。なお、スタート・ビット検出用に使用する補正用の定数SOFFSETは EQU擬似命令を用いて、以下のように定義してあります。カッコの中の第1項はINTP1の割り込み応答時間、第2項はタイマH起動までの時間、第3項は スタート・ビット中央検出でのタイマ再起動までの時間、第4項は実際にデータをサンプリングするまでの時間(クロック数)です。タイマHは1/4分周した クロックをカウントするので、合計のクロック数を4で割って補正値を算出しています。

SOFFSET EQU     (14+34+29+10)/4 ; スタート・ビット検出補正用

上記のプログラムで得られたパルス幅(クロック数)と補正値を使って、実際にタイマHで時間測定を行なう部分のプログラム例は以下のようになります。除算や乗算のような手間のかかる処理は使わず、代わりにシフト処理で済ますようにしています。

;
;  19200~9600なら1/2した値がマージンをみて、90~255の範囲を正常と
;みなす。
;
MOVW    AX,HL           ; 計測結果をAXレジスタへ
CLR1    CY
RORC    A,1             ; 結果を1/2する
XCH     A,X
RORC    A,1
XCH     A,X
ADD     A,#0FFH         ; 上位が0?
BC      $CALEXIT        ; 遅すぎるなら抜ける
XCH     A,X
CMP     A,#90           ; 下限のチェック
BC      $CALEXIT
CALNEXT:                        ; CY=0
MOV     CMPDATA1,A      ; CMP01設定値を保存領域に
DEC     CMPDATA1        ; -1補正
RORC    A,1
SUB     A,#SOFFSET+1    ; スタート・ビット処理補正
MOV     CMPDATA0,A      ; スタート・ビット処理用に
CALEXIT:
RET

このようにして得られたタイマHでの時間測定に使用する値が変数CMPDATA1(ビット間隔計測用)とCMPDATA0変数(スタート・ビット検出用)に格納されます。


[受信割り込み処理]
実際の受信は、スタート・ビットの先頭による、INTP1のエッジ検出割り込みで起動します。割り込みが受付けられたら、信号を確認し、ロー・レベルに なっているかを確認します。確認できたら、タイマを起動してスタート・ビットの中央を待ちます(このときは、ここまでの処理の時間とスタート・ビット中央 でデータ・サンプリングのタイミング用にタイマHを再起動するまでを補正した(その分短くした)時間となります)。下記のプログラムで、コメント欄の頭に 記載した数値が命令の処理クロック数で、INTP1処理の先頭からタイマ起動まで(赤字の命令) がその後の時間計測に影響する部分です。 タイマHを起動してしまえば、後はタイマHが時間測定を行なうので、命令の処理時間はそれほど気にする必要はありません。その後、スタート・ビットの中央 確認タイミング待ちのための処理を行ない、HALT命令でタイマH割り込み(INTTMH1)待ちをします。HALT命令での割り込み(ここでは、 HALT状態の解除のみでベクタ処理は行なわない)待ちは応答時間が速いので、スタート・ビットの中央確認からデータ・サンプリング用のタイマH再起動ま での時間を短くできます。以下の緑字の命令がスタート・ビット中央検出からデータ・サンプリングのためのタイマH再起動までの処理となります。

P1INT:
BT      RxDPIN,$P1INTEND ;10:ノイズなら抜ける
PUSH    AX ; 4:レジスタをセーブ
CLR1    TMHE1 ; 6:タイマH停止
MOV     A,CMPDATA0 ; 4:設定値の読み出し
MOV     CMP01,A ; 4:ビット中央までをセット
SET1    TMHE1 ; 6:タイマHを再起動
CLR1    TMIFH1                  ; タイマ割り込みクリア
CLR1    TMMKH1                  ; タイマ割り込みマスク解除
SET1    PMK1                    ; エッジ検出をマスク
MOV     A,CMPDATA1
HALT ; 3:スタート・ビット中央待ち
CLR1    TMHE1 ; 6:タイマH停止
BT      RxDPIN,$NOTSTART ;10:スタート・ビット未検出なら抜ける
MOV     CMP01,A ; 4:新しい比較値をセット
SET1    TMHE1 ; 6:タイマH再起動
CLR1    TMIFH1                  ; タイマ割り込みクリア
MOV     A,#10000000b            ; 初期データをセット

もし、スタート・ビットの中央で検出に失敗したときには、タイマHを停止して、再度INTP1の割り込み待ちに戻ります。

NOTSTART:
SET1    TMMKH1
CLR1    PIF1
CLR1    PMK1
POP     AX
RETI

スタート・ビットを検出したら、引き続いて、データ・ビットの受信処理となります。


[データ受信処理]
データの受信は、タイマH割り込み(INTTMH1)をHALT命令の解除に用いることによりタイミングを計っています。ここでは、ビット単位での受信のための処理をサブルーチン化し、CALLT命令で参照できるように以下のように定義してあります。

TABLESUB        CSEG    CALLT0
TXSTARTSUB:
DW      TXSTART
TXDATASUB:
DW      TXDATA
RXSTARTSUB:
DW      RXSTART
RXDATASUB:
DW      UARTRX
TXBITSUB:
DW      TXBIT
RXBITSUB:
DW      RXBIT

ここで、CSEG  CALLT0の部分がCALLT命令で使用するサブルーチンのアドレスを格納する領域へ配置することを指定しています。後は、 CALLT命令のオペランドとして使用したいラベルを定義して、DW擬似命令で対応したサブルーチンのアドレスを記述します。一番下が1ビットのデータ受 信処理を行なうためのサブルーチンのアドレスを定義しています。サブルーチンの本体は以下のようなプログラムです。タイマH割り込み(INTTMH1)か ら13クロック以内(BF命令の途中では既にデータを読み込んでいるので、これよりは早くなります)にデータを確認してキャリーに反映しています。同じサ ブルーチンをストップ・ビット確認でも使用するので、ここの処理では受信結果はキャリーに反映するだけにしています。

RXBIT:
CLR1    CY                      ; キャリーをクリアしておく
HALT ; 3:割り込み待ち
BF      RxDPIN,$RXDLOW ;10: データ確認
SET1    CY
RXDLOW:
CLR1    TMIFH1
RET

以上説明したサブルーチンをCALLT命令(具体的にはCALLT [RXBITSUB]) で呼び出し、得られたキャリーをRORC A,1命令でAレジスタに左から取り込みます(これでLSBファーストのフォーマットになります)。このときの受信ビット数はAレジスタに設定されている 初期値で決まります(これで、新しいビットの取り込みとビットのカウントを同時に実行しています)。
8ビット分の受信が完了すると、次にストップ・ビットを受信して、結果をフレーミング・エラーに格納します。ストップ・ビットまでの受信が完了すると、タイマHを停止し、フラグをセットして処理を終了します。

RXDATALOOP:
CALLT   [RXBITSUB] ; ビット受信
RORC    A,1                     ; 新しいビットを左から取り込む
BNC     $RXDATALOOP             ; 8ビット分繰り返す
MOV     RXDATA,A                ; 受信データを保存
CALLT   [RXBITSUB] ; ストップ・ビット受信
NOT1    CY                      ; CY:フレーミング・エラー
MOV     A,#01000000b
ROLC    A,1                     ; 結果をエラーにセット
MOV     RXSFLAG,A               ; フラグにセット
CLR1    TMHE1                   ; タイマを停止
SET1    TMMKH1                  ; タイマ割り込みをマスク
MOV     TRXSTAT,#0              ; 受信中フラグをクリア
POP     AX
P1INTEND:
DUMMY:
RETI


[受信起動処理]
受信処理そのものはこれまで説明したように、INTP1のエッジ検出割り込みで起動されますが、通常はINTP1のエッジ検出割り込みは禁止状態になって います。調歩同期の受信を開始するときに割り込みを許可したり、必要なフラグをセットしたりするのが受信起動処理です。このプログラムは以下のようになり ます。これは、単に受信処理を起動するだけですので、受信が完了したかはRXSFLAGのビット7がセットされたかで確認します。

RXSTART:
MOV     RXSFLAG,#0              ; エラー・フラグをクリア
MOV     TRXSTAT,#SRXMODE        ; 受信起動をセット
CLR1    PIF1                    ; 割り込みをクリア
CLR1    PMK1                    ; マスク解除
EI                              ; RxD立下り待ち
RET


[受信処理サブルーチン]
簡単に使うために以下のような、受信起動から受信完了までを処理するサブルーチンを準備しています。このサブルーチンはCALLT のテーブルにRXDATASUBの名前で登録してあるので、CALLT [RXDATASUB]と記述することで、使用することができます。受信したデータはAレジスタに格納され、Xレジスタ及びゼロ・フラグにエラー・ステー タスが入ります。

UARTRX:
CALLT   [RXSTARTSUB]            ; 受信起動
RXLOOP0:
MOVW    AX,RXDATA               ; 受信ステータスを読み出す
ROL     A,1                     ;
BNC     $RXLOOP0                ; 完了まで待つ
AND     A,#00000010b            ; 完了フラグをマスク
XCH     A,X
DI
RET


[データ送信処理]
基本的に半二重通信しかできないので、受信処理中(受信処理はスタート・ビットを割り込みで処理しているので、スタート・ビット待ちの状態でもメイン処理ができるようになっています)には処理が終わるまで待ち、受信終了後に送信を行ないます。
送信が可能ならば、送信を開始(TXSTARTサブルーチンで必要なパラメータを設定して、タイマを起動し、TxD端子をロー・レベルにしてスタート・ ビットを送信開始)します。ここまでが下記のプログラムの赤字で示した処理です。その後、次のビットを送信するために1ビット送信サブルーチンを呼び出し て、送信中のビットの転送完了をタイマH割り込み(INTTMH1)で待ちます。ストップ・ビットの送信まで完了すると、タイマHを停止して、処理を完了 します。

TXDATA: PUSH    PSW
UARTREADYCHK:
BT      CHKSRXMODE,$UARTREADYCHK ; 受信完了を待つ
DI ; 割り込みを禁止しておく
CALLT   [TXSTARTSUB] ; 送信開始
TXDATALOOP:
CALLT   [TXBITSUB]              ; 1ビット送信
DEC     TXBCOUNT                ; ビット数をカウント
BNZ     $TXDATALOOP
MOV     A,#0FFH                 ; ストップ・ビットをセット
CALLT   [TXBITSUB]
CALLT   [TXBITSUB]              ; ストップ・ビット完了待ち
CLR1    TMHE1                   ; タイマ停止
SET1    TMMKH1                  ; 割り込みマスク
POP     PSW
RET

ここで呼び出している1ビット送信サブルーチンは下記のプログラムに示すように、送信すべきビット(AレジスタのLSB)をキャリーにセットした状態で前 のビットの送信完了をHALT命令により待ちます。タイマH割り込み(INTTMH1)でHALT状態が解除されると、キャリーをチェックし、TxD端子 をビット操作してデータを出力します。




[送信起動処理]
送信起動処理はデータ送信処理から呼び出されるサブルーチンで、データ送信で必要な各種のパラメータ割り込み設定を行ない、タイマHを起動し、スタート・ビットの送信を開始してもどります。

TXSTART:
PUSH    AX                      ; 送信データをセーブ
MOV     TXBCOUNT,#BLENGTH ; ビット長を作業用に設定
MOV     A,CMPDATA1              ; ビット長時間をセット
MOV     CMP01,A
SET1    PMK1 ; 送信時にはINTP1をマスク
CLR1    TMIFH1
CLR1    TMMKH1
SET1    TMHE1                   ; タイマH起動
CLR1    TxDPIN ; スタート・ビット送信
POP     AX                      ; 送信データを戻す
RET


[通信を行なうための準備]
以上のプログラムを使用するために、以下のように定数を定義します。ここでは、78K0S/KU1+や78K0S/KY1+を高速内蔵発振クロックで使う場合にあわせた定義になっています。

RxDPIN  EQU     P3.2
RxDMODE EQU     PM3.2
RxDPUP  EQU     PU3.2
TxDMODE EQU     PM4.0
TxDPIN  EQU     P4.0
INTP1FALL       EQU     00000000b
BLENGTH EQU     8               ; ビット長
SOFFSET EQU     (14+34+29+10)/4 ; スタート・ビット検出補正用
B9600   EQU     207             ; 9600ボーのタイマ値
HB9600  EQU     104-SOFFSET-1   ; 9600ボーでの1/2ビット時間

また、リセットや割り込みのベクタ・テーブルは以下のように定義しています。基本的にはINTP1だけベクタ割り込みを使用し、INTTMH1はスタンバイの解除にだけ使用します。

RSTVECT CSEG    AT      0
DW      START           ;00:リセットスタート処理のベクタ
DW      DUMMY           ;02:
DW      DUMMY           ;04:
DW      DUMMY           ;06:LVI
DW      DUMMY           ;08:INTP0
DW      P1INT           ;0A:INTP1
DW      DUMMY           ;0C:INTTMH1
DW      DUMMY           ;0E:INTTM000
DW      DUMMY           ;10:INTTM010
DW      DUMMY           ;12:INTAD

使用するRAM領域は以下のような定義になっています。

DSEG
DS      20H
STACKTOP:
DSEG    saddrp          ; 16ビットアクセスのため
RXDATA:         DS      1               ; 受信データ。ステータスとペア
RXSFLAG:        DS      1               ; 受信ステータス・フラグ
;                  76543210
;                  |      +----: フレーミング・エラー
;                  +-----------: 受信完了
DSEG    saddr
TRXSTAT:        DS      1               ; 受信中ステータス
;                  76543210
;                  +-----------: 1:受信中
SRXMODE         EQU     10000000b       ; 受信中
CHKSRXMODE      EQU     TRXSTAT.7
TXBCOUNT:       DS      1               ; 送信用ビット・カウンタ
CMPDATA0:       DS      1               ; スタート・ビット確認用
CMPDATA1:       DS      1               ; ビット間隔用設定値

端子等は以下の例のように初期化します。端子としては、TxD端子をハイレベルにして出力に設定し、RxD端子では内蔵プル・アップ抵抗を有効に設定(青字の部分)します。また、タイマHに設定する時間データの初期値を変数に設定(緑字の部分)します。
高速内蔵発振器を使用する場合には、キャリブレーションが必要なので、赤字のように処理を呼び出しておきます。

MOV     CMPDATA1,#B9600 ; タイマの初期値設定
MOV     CMPDATA0,#HB9600
SET1    RxDPUP
SET1    TxDPIN ; TxDをハイに設定しておく
CLR1    TxDMODE ; TxD端子を出力に
CALL    !CAL            ; キャリブレーション
MOV     TMHMD1,#00010000b


[使用方法]
①UART機能を使用するための初期化処理の例です。この例では、タイマHのパラメータ領域に8MHzクロックを用いた場合の9600ボー用の初期値を設 定し、ポート関係の初期化を行なっています。その後キャリブレーション処理を行ない、タイマHのモードを設定しています(ただし、タイマHはまだ起動はし ない)。

MOV     CMPDATA1,#B9600 ; タイマの初期値設定
MOV     CMPDATA0,#HB9600
SET1    RxDPUP
SET1    TxDPIN          ; TxDをハイに設定しておく
CLR1    TxDMODE         ; TxD端子を出力に
CALL    !CAL            ; キャリブレーション
MOV    TMHMD1,#00010000b

②8キャラクタのデータを受信するための例を以下に示します。ここではHLレジスタをデータ格納用のRAMのポインタとして使用し、Bレジスタでデータ数を指定します。

DSEG
;
;  データ・バッファ
;
RXDATABUFF:     DS      8               ; 受信用のデータ・バッファ

CSEG
MOVW    HL,#RXDATABUFF
MOV     B,#8
RXLOOP:
CALLT   [RXDATASUB]     ; データ受信
MOV     [HL],A          ; 受信データをバッファへ
INC     L               ; 次のデータへ
DBNZ    B,$RXLOOP       ; 8回繰り返す

③同様に送信は以下のようになります。

DSEG
;
;  データ・バッファ
;
TXDATABUFF:     DS      8               ; 送信用のデータ・バッファ

CSEG
MOVW    HL,#TXDATABUFF
MOV     B,#8
TXLOOP:
MOV     A,[HL]          ; 送信データの読み出し
CALLT   [TXDATASUB]     ; データ送信
INC     L               ; 次のデータへ
DBNZ    B,$TXLOOP       ; 8回繰り返す

適用製品

78K0S/Kx1+
他にご質問がございましたら、リクエストを送信してください