なんとかなるさね

マイコンをネタにブログを始めてみました


RL78マイコン基板(RL78/G10)|TOOL0端子へのシリアル出力を使ったkbhit()関数もどきのコード 

前のエントリでブレッドボード上に組んだ書き込み回路(FT232RLと74HC125と抵抗2本の簡単なもの)経由で
秋月電子さんで販売されているRL78/G10 10pin DIP基板のTOOL0端子からPC上にデバッグメッセージを表示
させてみたのですが、そうなると人情としてPC側のキーボード入力をTOOL0端子でRL78/G10に伝えてみたく
なります。何か手は無いものかとRL78/G10のマニュアルを読んだところ、RL78/G10のキー割り込み機能を
使うとキー入力コードを区別することまでは出来ないもののキーが押されたことぐらいは伝えられそうな気が
しました。そこでアセンブラコードを書いて試してみたところ、悪くない感じで動作してくれました。

もともとのキー割り込み機能というのはRL78/G10に接続されたスイッチ(あるいはスイッチマトリックス)の
押下/解放(入力レベルの変化)を検出する為に内蔵されている機能ですが、このうちのチャンネル0がTOOL0
端子の兼用端子機能(こちらの場合の表記はKR0端子)として割り当てられていましたので、TOOL0端子に接続
されたFT232RLからのシリアル出力のスタートビット(立下りエッジ)の検出に使ってみました。(なお、割り
込みを発生させて割り込み処理ルーチンに分岐させるようなことまではしていません。) コードを書いている
最中は以下の点が気になりましたが、実際に動かしてみると問題無く動作してくれました。

(1) FT232RLを2Mbaudに設定しているのでシリアル出力信号の幅が狭いがRL78/G10が検出するかどうか?
  → 検出してくれた
(2) FT232RLとRL78/G10は単線UART(送信線と受信線が兼用)接続しているのでTOOL0端子からのソフト
  ウェアシリアル出力にも検出機能が反応してしまうが回避出来るかどうか?
  → ソフトウェアシリアル出力期間中だけ一時的に検出機能を中断させることが出来た
(3) FT232RL出力の単線UART化に使用している74HC125からのLow出力とTOOL0端子からのHigh出力が
  衝突する危険性を回避出来るかどうか?
  →TOOL0端子からはHi-zかLow出力だけを行うようにしてHigh出力をしないようにした(Hi-z時は外部
  1KΩのプルアップによりFT232RL入力から見るとHighとして認識される)

以下は試してみた時の画面なのですが、RL78/G10側でプログラム開始直後はPC側のキーが押下されるのを
待ち、PC側のキーが押されたら表示を開始し、それ以後は、再びPC側のキーが押下されたら表示を中断し、
更にPC側のキーが押されたら表示を再開し、というのを繰り返しているところです。(今回のコードはキー
入力コードは区別出来ませんので、最初は取り敢えずスペースキーで試していましたが、スペースは画面に
エコーバック表示されても見て分かりませんので、そのうち'/'キーで試すことが多くなりました。ちなみに、
単線UART接続ですのでFT232RLの出力は回路的にFT232RLに入力されて自動的にエコーバックされます。)



作成したアセンブラコード(計60バイト)は以下の通りです。(なお、putchar()とkbhit()の2つがありますが、
putchar()の方は前のエントリで作成したアセンブラコードから変更した箇所を赤字にしています。)

; This code is in the public domain. You may use, modify or distribute it freely.

PUBLIC  _putchar
_putchar:               ;X = data, A = ignored, void putchar( unsigned char )
    SET1    PM4.0       ; 2 clk     3 byte      always I do for robustness, P40 = TOOL0/KR0
    CLR1    P4.0        ; 2 clk     3 byte      same as above
    MOV1    CY, KRM0.0  ; 1 clk     3 byte      for kbhit(), get KR0 detection enable flag
    CLR1    KRM0.0      ; 2 clk     3 byte      for kbhit(), disable KR0 detection flag
    PUSH    PSW         ; 2 clk     2 byte
_putchar_b:             ;begin
    ONEB    A           ; 1 clk     1 byte      as a stop bit,   shorter than "MOV A, #01H"
    ADDW    AX, AX      ; 2 clk     1 byte      for a start bit, shorter than "SHLW AX, 1"
    DI                  ; 4 clk     3 byte
_putchar_l:             ;loop (start bit = 0, b0, b1, b2, b3, b4, b5, b6, b7, stop bit = 1)
    SHRW    AX, 1       ; 2 clk     2 byte
    MOV1    PM4.0, CY   ; 2 clk     3 byte
    CMPW    AX, #0000H  ; 2 clk     3 byte
    BNZ     $_putchar_l ; 2/4 clk   2 byte
_putchar_e:             ;end
    POP     PSW         ; 4 clk     2 byte
    MOV1    KRM0.0, CY  ; 2 clk     3 byte      for kbhit(), restore KR0 detection enable flag
    RET                 ; 7 clk     1 byte

PUBLIC  _kbhit
_kbhit:                 ;char kbhit( void ), return value : 1=detected / 0=not detected
    SET1    PM4.0       ;always I do for robustness, P40 = TOOL0/KR0
    SET1    KRM0.0      ;enable KR0 detection flag
    SET1    KRCTL.7     ;enable KRx detection flags
    MOV     A, KRF      ;get KRx detection flgas
    AND     A, #01H     ;check KR0 detecion flag
    BZ      $_kbhit_e   ;Z=not detected / NZ=detected
    MOV     C, #20      ;set loop count (10 clk/bit * 10 bit = 100 clk = 5 clk * 20)
_kbhit_w:               ;wait 100 clk (start bit, b0, b1, b2, b3, b4, b5, b6, b7, stop bit)
    DEC     C           ; 1 clk     1 byte
    BNZ     $_kbhit_w   ; 2/4 clk   2 byte
    MOV     KRF, #0FEH  ;clear KR0 detection flag
_kbhit_e:
    MOV     C, A        ;A = KR0 detecion flag (01H=detected / 00H=not detected)
    RET                 ;C = return value (1=detected / 0=not detected)

END


また、動作確認用に作成したCコードは以下の通りです。

void putchar( unsigned char );
char kbhit( void );

途中省略

void main(void)
{
    R_MAIN_UserInit();
    /* Start user code. Do not edit comment generated here */
    while ( !kbhit() )
    {
        /* wait for a first keyboard hit */
    }
    putchar('\r');
    putchar('\n');      
    while (1U)
    {
        unsigned char c;
        if ( kbhit() )
        {
            /* pause because of a keyboard hit */
            while ( !kbhit() )
            {
                /* wait for a keyboard hit to continue */
            }
            putchar('\r');
            putchar('\n');      
        }
        for ( c = '0' ; c <= '9' ; c++ )
        {
            putchar(c);     
        }
        for ( c = 'A' ; c <= 'Z' ; c++ )
        {
            putchar(c);     
        }
        for ( c = 'a' ; c <= 'z' ; c++ )
        {
            putchar(c);     
        }
        putchar('\r');
        putchar('\n');      
        G_LED_DATA = 0b010101010101;
        Wait_1sec();
        //Wait_1sec();
        G_LED_DATA = 0b101010101010;
        Wait_1sec();
        //Wait_1sec();
    }
    /* End user code. Do not edit comment generated here */
}




なお、RL78/G10のマニュアルは以下のウェブページにあります。

RL78/G10 ドキュメント一覧
http://japan.renesas.com/products/mpumcu/rl78/rl78g1x/rl78g10/Documentation.jsp

追記 : メモ

RL78/G10 ユーザーズマニュアル ハードウェア編
Rev.3.00 2014.11
http://documentation.renesas.com/doc/products/mpumcu/doc/rl78/r01uh0384jj0300_rl78g10.pdf

関連記事

2015/01/09   blog-entry-547   category: RL78 /* 16bit,8bit CISC */

go page top