忍者ブログ

Fグループ電子工作講座

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

シリアル通信の設定(1)1文字送受信

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

PCで送受信できることが確認できたのでSH7125のシリアル通信の設定を行っていきます。
SH7125でのシリアル通信の機能名はSCI(Serial Communication Interface)です。

ピン設定の確認

ベースボードに付いているコネクタを使ってシリアル通信を行います。
って事でそのコネクタに繋がっている端子を制御する必要があります。
ベースボードキットの取説を確認してみます。
手元にない人は秋月のページからダウンロードしてください

最後のページの回路図を見ます。
右の方にある楕円(表記JP3)がRS232Cのコネクタです。
2本配線が伸びてIC2に接続されています。
IC2は前々回説明した電圧変換ICです。
さらにJP2へ配線が伸びています。
これはCPUボードを外すと見えるジャンパピンです。
ジャンパピンが刺さっていると1と2、3と4がつながります。
さらにたどっていくとPA3とPA4に繋がっています。
要するにPA3PA4が制御すべき端子です。

続いてCPUボードの取説またはハードウェアマニュアルを見てみます。
TXDRXDがそれぞれシリアル通信のデータ送信(TransmitData)とデータ受信(ReciveData)の機能です。
PA3RXD1PA4TXD1となっています。

SH7125ではSCI0SCI1SCI2の合計3系統のシリアル通信機能が搭載されています。
今回使うRXD1TXD1は番号の通りSCI1の機能に該当します。
という事で、付属のコネクタで通信を行うにはSCI1の機能を設定する必要があります。


プログラムの作成

まずは割り込みを使わない方式で文字送信を試みます。

初期設定

初期化関数を作ります。

設定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;    //設定中のため送受信割込禁止、送受信禁止

<用語>
SCSCR:シリアルコントロールレジスタ
シリアル通信にかかわる機能や割り込みの有効/無効を設定ます。
PACRL1の設定方法はPWMなどに設定する場合と一緒です。

設定2、通信条件の設定
<設定>

    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

<用語>
SCSMR:シリアルモードレジスタ
シリアル通信の通信条件を設定します。
0:調歩同期式モード / 1:クロック同期式モード
0:8ビットデータ  / 1:7ビットデータ
0:パリティ無効  / 1:パリティ無効
0:偶数パリティ  / 1:奇数パリティ
0:1ストップビット / 1:2ストップビット
0:マルチプロセッサモード無効 / 1:マルチプロセッサモード有効
00:Pφクロック 01:Pφ/4クロック 10:Pφ/16クロック 11:Pφ/64クロック
調歩同期式モード(受信側がストップビット基準で同期をとってくださいモード)たぶん
クロック同期式モード(データ以外にクロックを別途送るのでそれで同期をとってくださいモード)
マルチプロセッサモードは知りません。
一番最後のクロック選択はPWMやCMTでのクロック選択を同じような考え方です。
その他はPCでシリアル通信を行ったときに出てきた項目に該当します。

SCBRR:ビットレートレジスタ
シリアル通信の通信速度を設定します。設定する値Nは以下で求めます。
 N = ()×10^6 ÷ (64×2^(2n-1)×B)  - 1
:25MHz
n:クロックセレクトを00に設定したので0
を入れると
N = 25000000 ÷ (32×B) - 1

Bはビットレートです
B=38400bpsだとN=19.34 N=19に設定→通信誤差1.7%
B=115200bpsだとN=5.78 N=6に設定→通信誤差3%

設定3、通信開始
<設定>
    SCI1.SCSCR.BIT.TE  = 1;    // トランスミットイネーブル:送信動作を許可
    SCI1.SCSCR.BIT.RE  = 1;    // レシーブイネーブル:受信動作を許可   

これで1文字ずつ送受信の準備ができました。

送信プログラム

起動時に文字'A'を送信してみます。
<設定>
void main(){
    init_SCI1();                        //シリアル通信1の初期化
    SCI1.SCTDR='A';                        //送信データを設定
    SCI1.SCSSR.BIT.TDRE = 0;            //送信開始
    while(1){                            //無限ループ開始
    }
}
<用語>
SCTDR:トランスミットデータレジスタ
送信するデータをここに入れます。

TDRE:トランスミットデータレジスタエンプティ
送信できる文字が無いとき1になります。
0に設定すると送信が開始され、
送信が完了すると送信できる文字が無いため1になります。

全部まとめるとこんな感じ
<設定>
#include "iodefine.h"

//シリアル通信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;    // レシーブイネーブル:受信動作を許可   
}

//メイン関数
void main(){
    init_SCI1();                        //シリアル通信1の初期化
    SCI1.SCTDR='A';                        //送信データを設定
    SCI1.SCSSR.BIT.TDRE = 0;            //送信開始
    while(1){                            //無限ループ開始
    }//end while
}//end main


動作確認

書き込みが完了したらマイコンから出力される文字をTMZで受信してみます。
※FDTでデバイスとの切断を行っていないとTMZで「ポートをオープンできませんでした」が出ます。めんどくさいのでFDTのオプション→自動切断にチェックを入れておくと便利です。

TMZの設定は前回に引き続き
ビットレート  :38400
文字サイズ   :8
フロー制御   :制御なし
パリティービット:偶数パリティー
停止ビット   :1ビット
エコー     :OFF

この状態でマイコンを起動してTMZにAが表示されれば成功です。
マイコンの電源入れ直し、またはリセットボタンを押す度にAが表示されるはずです。

ASCIIコードを理解する

SCI1.SCTDR='A';

SCI1.SCTDR=0x42;
へ変換して実行してみます。

※TMZを終了してCOMポートを開放しておかないとFDTで「ポートのオープンエラー」が出て
プログラムを書き込むことができません。

今度はTMZにBが表示されるはずです。
0x41とするとAが表示されます。
これは文字コード0x41(10進数の65)が文字のAに相当するからです。
※sprintf等の関数は文字列が文字コードに変換しています。
この文字コードはASCIIコード(アスキーコード)と呼ばれるものです。

シリアル通信で文字を送る場合はこのASCIIコードが適用されます。
文字を送る通信をテキスト通信
数値をそのまま送る通信をバイナリ通信といった呼び方をします。
今後は主にテキスト通信を扱っていくものとします。

文字を受信する

送信ができたので受信してみます。
メイン関数を以下の様に変更します。
<設定>
void main(){
    init_SCI1();                        //シリアル通信1の初期化
    SCI1.SCTDR='A';                        //送信データを設定
    SCI1.SCSSR.BIT.TDRE = 0;            //送信開始
    while(1){                            //無限ループ開始
        if(SCI1.SCSSR.BIT.RDRF){        //何か受信した
            SCI1.SCSSR.BIT.RDRF=0;        //受信フラグを下す
            SCI1.SCTDR=SCI1.SCRDR;        //受信文字を送信データに設定
            SCI1.SCSSR.BIT.TDRE = 0;    //送信開始
        }//end if
    }//end while
}//end main

<用語>
RDRF:レシーブデータレジスタフル
何かデータを受信すると1になる。
一度1になると、0を入れないの1のまま

<解説>
if文で受信が来ているか確認し、受信があれば
 とりあえず受信フラグを下す
 受信したデータを送信用データとして設定
 送信開始

動作確認

起動時に'A'が表示されることに変わりはありません。
ここでTMZから文字を送信してみます。
TMZから送信した文字がTMZに表示されれば成功です。

通信を使った簡単な制御

文字を使ってLEDの制御をしてみます。
 汎用IO設定ソース:io_setup.c
 汎用IO設定ヘッダ:io_setup.h
を読み込みます。
io_setupは割り込みを使用していないのでそのまま読み込むだけで使えます。

文字'W'で赤点灯、緑点灯
文字'A'で赤消灯、緑点灯
文字'D'で赤点灯、緑消灯
文字'S'で赤消灯、緑消灯
とします。

<設定>
#include "iodefine.h"
#include "io_setup.h"

//シリアル通信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;    // レシーブイネーブル:受信動作を許可   
}

//メイン関数
void main(){
    hardware_setup();                    //汎用IOの初期化
    init_SCI1();                        //シリアル通信1の初期化
    SCI1.SCTDR='A';                        //送信データを設定
    SCI1.SCSSR.BIT.TDRE = 0;            //送信開始
    while(1){                            //無限ループ開始
        if(SCI1.SCSSR.BIT.RDRF){        //何か受信した
            SCI1.SCSSR.BIT.RDRF=0;        //受信フラグを下す
            SCI1.SCTDR=SCI1.SCRDR;        //受信文字を送信データに設定
            SCI1.SCSSR.BIT.TDRE = 0;    //送信開始
            if(SCI1.SCRDR=='W'){
                set_LED_R(1);
                set_LED_G(1);
            }
            if(SCI1.SCRDR=='A'){
                set_LED_R(0);
                set_LED_G(1);
            }
            if(SCI1.SCRDR=='D'){
                set_LED_R(1);
                set_LED_G(0);
            }
            if(SCI1.SCRDR=='S'){
                set_LED_R(0);
                set_LED_G(0);
            }
        }//end if
    }//end while
}//end main

送信した文字に応じてLEDの点灯が変われば成功です。

次回、文字列を連続して送信するために割り込み処理を設定します。
更にややこしくなります。
PR

コメント

プロフィール

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

最新コメント