関連:
シリアル通信関連記事一覧文字列の連続送信を行います。
割り込みを使った連続送信を行いますが、その前に割り込みを使わない連続送信を試してみます。
初期化関数は
シリアル通信の設定(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.cに
SCIの初期化関数を移植します。
また、
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 0x000000
F0
を
#define SR_Init 0x000000
00
へ変更します。
先ほどのプログラムでは
_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.cと
intprg.cの
INT_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_TXI1は
intprg.cの
INT_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.cと
intprg.cの編集を忘れていないか確認してください。