忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

シリアル通信の設定(2)連続送信

関連:シリアル通信関連記事一覧

文字列の連続送信を行います。

割り込みを使った連続送信を行いますが、その前に割り込みを使わない連続送信を試してみます。
初期化関数はシリアル通信の設定(1)のものをそのまま使用します。

送信する文字列を設定するためにsprintfを使います。
sprintfを使うためには標準で用意されているstdio.hを読み込みます。
標準で用意されているものなので、プロジェクトにファイルを追加する必要はありません。
includeするだけで使えます。
#include <stdio.h>

メイン関数を変更します。
<設定>
void main(){
    init_SCI1();                        //シリアル通信1の初期化

    char _sci1_tx_data[255];    //送信文字バッファー(最大255文字)
    int _sci1_tx_num;        //送信したい文字数
    int _sci1_tx_now=0;        //送信済み文字数
    _sci1_tx_num=sprintf(_sci1_tx_data,"HELLO WORLD\n");    //送信文字を設定+文字数をカウント

    while(1){                            //無限ループ開始
        if(SCI1.SCSSR.BIT.TDRE){    //送信可能
            if(_sci1_tx_now<_sci1_tx_num){    //まだ送信する文字がある
                SCI1.SCTDR=_sci1_tx_data[_sci1_tx_now];        //送信データを設定
                SCI1.SCSSR.BIT.TDRE = 0;    //送信開始
                _sci1_tx_now++;
            }//end if
        }//end if
    }//end while
}//end main

<解説>
sprintfはchar型配列に文字列を入れていくことができます。
また、入力した文字数を戻り値として取得することができます。
入力した文字数送信したい文字数 となります。

TDREの状態をみて処理を行っています。
文字送信途中で次の文字を送信することはできません。
そこで、SCI1.SCSSR.BIT.TDREを確認します。SCI1.SCSSR.BIT.TDREが1の時送信が可能です。

送信済み文字数_sci1_tx_nowと送信したい文字数_sci1_tx_numを比較してまだ送信していない文字がある場合は送信処理を行います。

送信データとして_sci1_tx_dataに格納した_sci1_tx_now番目の文字を設定します。
そして前回同様送信を開始します。

次の文字送信に備えて送信済み文字数_sci1_tx_nowを1カウントアップします。

<動作確認>

実行して起動時とボードのリセットボタンを押す度にHELLO WORLDが表示されれば成功です。

割り込みを使った文字列連続送信

先ほどのプログラムでは文字列送信がメインのwhileループの中を占拠してしまっています。
ここに他の処理を追加すると色々おかしなことになります。
そこで文字列の連続送信処理を割り込み処理で実行させます。

ここまではメインのcファイルに書いていましたが、PWM等他の割り込み処理と同様に別ファイルに書いて後で使いまわせるようにします。
以下のファイルを新規作成します。
 SCI設定ソース:intSCI.c
 SCI設定ヘッダ:intSCI.h
今まで通りメモ帳などを使って作って、プロジェクトに追加します。
intSCI.cSCIの初期化関数を移植します。
また、
char _sci1_tx_data[255];    //送信文字バッファー(最大255文字)
int _sci1_tx_num;        //送信したい文字数
int _sci1_tx_now=0;        //送信済み文字数
の3つの変数もintSCI.c内のグローバル変数として移植します。

初期化関数に2行追加します。
    INTC.IPRL.BIT._SCI1 = 0x7;    // 割り込み優先度(0x0:最低~0xF:最高)
    _sci1_tx_now=0;        //送信済み文字数をリセットする
割り込み優先度を設定します。
また、他の割り込みと同様にresetprg.cの36行目付近
#define SR_Init    0x000000F0

#define SR_Init    0x00000000
へ変更します。

先ほどのプログラムでは_sci1_tx_dataの設定をmain関数内で行っていましたが、この処理をintSCI.cに新規作成する関数で処理させます。

<設定>
void write_sci1(char* trans_buf){
    if(_sci1_tx_now)    //文字列の送信が終わっていない
        return;            //関数を強制終了

    _sci1_tx_num=sprintf(_sci1_tx_data,"%s",trans_buf);    //送信文字を設定+文字数をカウント
    SCI1.SCSCR.BIT.TIE = 1;        // 送信割り込み要求を許可
}
<用語>
TIE:トランスミットインタラプトイネーブル
送信割り込み許可。
これを1に設定すると、TDREが1になった時に割り込み処理が発生するようになります。
要するに先ほどのプログラムでif(SCI1.SCSSR.BIT.TDRE)で待機させていた部分を割り込み処理で自動実行できるようになります。
ベクタ番号は222でvecttbl.cintprg.cINT_SCI1_TXI1関数がこれに該当します。

<解説>
char*
char型変数のポインタ(変数のアドレス)を示す変数で、今回は文字配列の先頭アドレスを入力します。

割り込み処理関数

TXI割り込みが発生したときに処理を作成します。
中身は先ほどのプログラムのwhile文の中身とほとんど同じになります。
<設定>
void SCI1_INT_TXI1(void){
    if(SCI1.SCSSR.BIT.TDRE){    //送信可能
        if(_sci1_tx_now<_sci1_tx_num){    //まだ送信する文字がある
            SCI1.SCTDR=_sci1_tx_data[_sci1_tx_now];        //送信データを設定
            SCI1.SCSSR.BIT.TDRE = 0;    //送信開始
            _sci1_tx_now++;                //送信済み文字数をカウントアップ
        }else{                    //送信する文字がなくなった
            _sci1_tx_now=0;                //送信済み文字数をリセット
            SCI1.SCSCR.BIT.TIE = 0;        // 送信割り込み要求を禁止
        }//end if
    }//end if
}

先ほどのプログラムとは異なるのは、送信する文字がなくなったときに送信する文字をリセットする処理が増えたのと、送信割り込み要求を禁止する(送信割り込みを停止させる)設定が増えたぐらいです。
TDREが1にならないとこの関数は実行されないはずなので、最初のif文は必要ないはずですが、念のため残しておきました。

この時点でのintSCI.cの中身は以下となります。
<設定>
#include "iodefine.h"
#include <stdio.h>
#include "intSCI.h"

//ファイル内で使いまわす変数
char _sci1_tx_data[255];    //送信文字バッファー(最大255文字)
int _sci1_tx_num;        //送信したい文字数
int _sci1_tx_now=0;        //送信済み文字数

//シリアル通信1初期化関数
void init_SCI1(void){
    STB.CR3.BIT._SCI1=0;    //モジュールスタンバイ解除
    PFC.PACRL1.BIT.PA3MD=1;    //PA3をRXD1入力に設定
    PFC.PACRL2.BIT.PA4MD=1;    //PA4をTXD1出力に設定
    SCI1.SCSCR.BYTE=0x00;    //設定中のため送受信割込禁止、送受信禁止

    SCI1.SCSMR.BYTE=0x00;    //とりあえず全部0(標準設定)にしておく
    SCI1.SCSMR.BIT._PE    = 1;    // パリティー有効:1/無効:0
    SCI1.SCSMR.BIT.OE    = 0;    // パリティー奇数:1/偶数:0

//    25MHz,9600bpsの時、BRR=(25000000/(32*9600)) - 1 => 80
//    SCI1.SCBRR=80;        //9600bps
//    SCI1.SCBRR=39;        //19200bps
    SCI1.SCBRR=19;        //38400bps
//    SCI1.SCBRR=6;        //115200bps

    SCI1.SCSCR.BIT.TE  = 1;    // トランスミットイネーブル:送信動作を許可
    SCI1.SCSCR.BIT.RE  = 1;    // レシーブイネーブル:受信動作を許可   

    INTC.IPRL.BIT._SCI1 = 0x7;    // 割り込み優先度(0x0:最低~0xF:最高)
    _sci1_tx_now=0;        //送信済み文字数をリセットする
}

//文字列送信関数
void write_sci1(char* trans_buf){
    if(_sci1_tx_now)    //文字列の送信が終わっていない
        return;            //関数を強制終了

    _sci1_tx_num=sprintf(_sci1_tx_data,"%s",trans_buf);    //送信文字を設定+文字数をカウント
    SCI1.SCSCR.BIT.TIE = 1;        // 送信割り込み要求を許可
}

//送信割り込み処理関数
//intprog.cのINT_SCI1_TXI1へ登録が必要

void SCI1_INT_TXI1(void){
    if(SCI1.SCSSR.BIT.TDRE){    //送信可能
        if(_sci1_tx_now<_sci1_tx_num){    //まだ送信する文字がある
            SCI1.SCTDR=_sci1_tx_data[_sci1_tx_now];        //送信データを設定
            SCI1.SCSSR.BIT.TDRE = 0;    //送信開始
            _sci1_tx_now++;                //送信済み文字数をカウントアップ
        }else{                    //送信する文字がなくなった
            _sci1_tx_now=0;                //送信済み文字数をリセット
            SCI1.SCSCR.BIT.TIE = 0;        // 送信割り込み要求を禁止
        }//end if
    }//end if
}

また、ヘッダファイルintSCI.cの中身は以下となります。
<設定>
#if !defined _INTSCI_H_    //読み込まれていない(_INTMTU_H_が定義されていない)とき読み込む

#define _INTSCI_H_ 0

void init_SCI1(void);
void write_sci1(char*);
void SCI1_INT_TXI1(void);

#endif

割り込み関数SCI1_INT_TXI1intprg.cINT_SCI1_TXI1内へ登録しておく必要があります。
void INT_SCI1_TXI1(void){/* sleep(); */}

void INT_SCI1_TXI1(void){SCI1_INT_TXI1();}

これで割り込みを使った連続送信処理の準備が整いました。
ここまで下ごしらえをしてしまえはメイン関数は非常に簡単になります。
<設定>
#include "iodefine.h"
#include <stdio.h>
#include "intSCI.h"

void main(){
    init_SCI1();                        //シリアル通信1の初期化

    write_sci1("HELLO WORLD\n");

    while(1){                            //無限ループ開始
    }//end while
}//end main

実行して起動時とボードのリセットボタンを押す度にHELLO WORLDが表示されれば成功です。
うまく動かない場合はresetprg.cintprg.cの編集を忘れていないか確認してください。
PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント