PR

PICマイコン(PIC16F1827)のシリアル通信の応用

組み込みエンジニア
本記事はプロモーションが含まれています。

こんにちは、ENGかぴです。

PIC16F1827のシリアル通信機能(EUSART)を応用して外部機器から電文を送信しPIC16F1827を操作し電文でレスポンスさせて動作確認を行いました。電文を使ったシリアル通信の送信と受信の考え方についてまとめました。

本記事は下記記事の応用編となります。EUSARTの設定やTMR0の設定は同様です。

PICマイコン(PIC16F1827)のシリアル通信を実装する

外部機器にはArudino UNOを使用しています。PIC16F1827で動作確認したことについてリンクをまとめています。

PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ

送受信に使用する電文

PIC16F1827を外部機器からの電文で操作します。電文の構成は任意で構成することができますが外部機器とPIC16F1827で交換する電文の構成は同じ構成にすると管理しやすくなります。

電文の構成

電文の構成
電文の構成

電文の構成は1バイト目をヘッダーとしデータの先頭であることを通知します。2バイト目には3バイト以降にセットするデータのサイズを示すデータ長をセットします。電文の最終バイトにはデータ長以降のデータの総和を計算したチェックサムを付加します。

ヘッダーの部分の文字コードが’P’の場合はPIC16F1287への電文とし’A’であればArudino UNOへ送出する電文として区別します。

チェックサムはデータ部分の総和をとり1バイト分のデータをセットします。1バイトの大きさ(255)を超えても下位の1バイトをセットします。チェックサムをuint8_tで宣言しておくとオーバーフローして1バイトデータとなります。

例ではデータ1からデータ4としていますが任意のデータとすることで様々なパターンに対応する処理を作ることができます。

PR:わからないを放置せず、あなたにあった最低限のスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!

電文を受信する

while(EUSART_is_rx_ready()) //受信データがあるか
{
    picRcv.buf[picRcv.wp] = EUSART_Read(); //データをリード
    if( ++picRcv.wp >= sizeof(picRcv.buf)){ //次に保管する位置を更新
        picRcv.wp = 0;
    }
}

EUSARTで受信したデータを一時保管します。While()で受信データを確認しているのはメイン処理に来るたびに受信しているデータ分だけ確実に取得するためです。if()で確認するよりもデータの一時保管が早くなります。

データの受信と送信のシーケンス

void eUsartmain(void){

    switch( ComMode ){
        case COM_RX_WAIT:
            //受信待ちで一時保管したデータのチェックを行う  
            break;
        case COM_RCVDATA: 
            //受け入れた電文に対して処理を行う
            break;
        case COM_TX:
            //返信電文を送信する
            break;        
    }
}

受信と送信をモードの切り替えによる処理で管理します。以下のように3つのモードを実装します。

モード説明
COM_RX_WAIT受信待ちで一時保管したデータをヘッダーやデータ長から電文を判断する。
データのチェックサムによって問題なければ電文を受け付ける
COM_RCVDATA受け付けた電文を解析して処理を行う。
COM_TX準備したデータを送信する。
送受信を管理するモードの説明

COM_RX_WAITで受信を待ちチェックサムの条件を満たし電文を受け付けるとモードをCOM_RCVDATAに遷移します。COM_RCVDATAで電文を解析して処理を行いデータを返信する場合はモードをCOM_TXに遷移させます。

返信しない場合はモードをCOM_RCVDATAに戻して受信待ちにします。

モードを切り替えて処理するため受信データのチェックと送信の処理が同時に発生することはありません。

PR:RUNTEQ(ランテック )- マイベスト3年連続1位を獲得した実績を持つWebエンジニア養成プログラミングスクール

受信データのチェック

一時保管したデータが電文の構成であるかを確認するためにCOM_RX_WAITモードで受信データのチェックを行います。

if( picRcv.buf[ rp ] != HEADER ){ //ヘッダーが一致するか
    ReadPointerAdd(); //読み込み位置の更新
}
else{
    if( rxsz >= 2 ){ //データ長分だけ獲得しているか
        //データ長を確定する             
        if( rxsz >= allsz){ //確定したサイズ以上か                
            for( i=0; i < allsz; i++ ){
                Rcvdata[i] = picRcv.buf[picRcv.rp]; //一時保管したデータを移す
                ReadPointerAdd(); //読み込み位置の更新
            }
                       
            sumchk = CalcSum(&Rcvdata[2], datsz); //チェックサムの計算
            if( sumchk == Rcvdata[allsz-1]){ //チェックサムの確認
                ComMode = COM_RCVDATA; //モードを遷移
            }
        }
    }               
}

最初にヘッダーを確認します。PIC16F1827であればArudino UNOから受信するためヘッダーは’P'(0x50)になります。ヘッダーが一致した場合は2バイト目のデータ長が受信できているかの確認を行います。

2バイト目のデータ長によって電文全体のサイズが確定できるため受信データを電文保管用のバッファ(Rcvdata[])に移し替えます。Rcvdata[]のチェックサムを計算しチェックサムが一致するか確認します。チェックサムに問題がなければ電文として受け入れるためモードを進めて処理を行います。

データの送信

if(EUSART_is_tx_ready()){ //送信ビジーでないか
    if ( Txdata.cnt < sizeof(Txdata.data)){
        EUSART_Write(Txdata.data[Txdata.cnt]); //データを送信
        ++Txdata.cnt; //送信データカウントを更新
    }
    else{ //全データの送信が完了
        timTxWait = TIME_OFF;
        ComMode = COM_RX_WAIT; //受信待ちに遷移
    }
}  
                
if( timTxWait == TIME_UP ){ //送信タイムアウトか
    timTxWait = TIME_OFF;
    ComMode = COM_RX_WAIT; //受信待ちに遷移
}

送信がビジー(待機状態)でなければデータを送信します。送信データを配列として準備し送信データカウントを更新しながら配列の先頭から順に送信します。送信データの準備についてはソースコード全体のTxDataSet()を参考にしてください。

送信する際にタイムアウトを設けていますが何らかの要因で送信がうまくいかなかった場合にタイムアウトすることで受信モードに切り替えることができます。

送信タイムアウトは電文のサイズによって適切な時限をセットする必要があります。

送信タイムアウトに引っかかってしまう場合は異常状態とみなしてシリアル通信機能をリスタートするなど対策に使用できます。

PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!

動作確認

PIC16F1827とArduino UNOを接続してシリアル通信の動作確認を行います。通信条件はボーレートが19200bps、パリティなしとします。

動作確認用の回路

PIC16F1827とArduino UNOによるシリアル通信の確認回路
PIC16F1827とArduino UNOによるシリアル通信の確認回路

Arduino UNOではソフトウェアシリアルのライブラリを使用してPIC16F1827とシリアル通信を行います。

SW1とSW2でArudino UNOから送出する電文を切り替えて送信します。SW1を押すとPIC16F1827はLED3を点灯してArudino UNOに「OK-1」を含む電文で返信します。SW2を押すとPIC16F1827はLED3を消灯して「OK-2」を含む電文で返信します。

LED1はPIC16F827からシリアル通信でデータを取得すると点灯/消灯します。LED2は動作確認用として250ms毎に点灯/消灯を切り替えています。

PIC16F1827のピン設定(MCC)
PIC16F1827のピン設定(MCC)

シリアル通信に使用するピン以外MCLRを除いてDOピンとして設定しています。

PR:次の一手があなたの未来を決める! アビリティクラウドーフリーランスを目指すあなたに向けたエンジニアのマッチングサービス。大手のエンドクライアントメインの企業が多く、業務内容も規模が大きいのが特徴

動作結果

シリアルモニタによる動作確認の結果
シリアルモニタによる動作確認の結果

SW1とSW2を押すとArudino UNOから電文が送出されLED3が点灯/消灯することが確認できました。

返信電文はArduinoのシリアルモニタを使用して動作確認を行いました。「OK-1」を含む電文はSW1を押したときの文字列であり「OK-2」はSW2を押したときの文字列であり、PIC16F1827から電文による返信を受けていることが分かりました。

スポンサーリンク

ソースコード全体

ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。

リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。

ソースコードをダウンロード

main.cをコピーすると使用できます。pic16f1827-eusart2-arduino.txtはArduinoのソースコードです。拡張子をtxtからinoに変更するかコピーすると使用できます。

本ソースコードはMPLAB X IDEにMCCのプラグインをインストールしていることが前提となります。MCCをインストールする方法は下記記事を参考にしてください。

MPLAB Code Configurator(MCC)の追加と使い方

関連リンク

PICマイコンを使ってマイコンのレジスタの設定やMPLAB X IDEのプラグインであるMCCを使用して動作確認したことについてまとめています。

PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ

PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ

PR:わからないを放置せず、あなたにあった最低限のスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました