PIC16F1938でRS485通信(送信・受信)をやってみる

はじめに

この記事は、PIC16F1938とRS485トランシーバ(LTC1485)を使って
RS485通信に成功させた方法の解説となります。
通信の成功を見るために、LEDを点滅させています。

RS485はDMX512やModbusでも利用されている差動通信方式です。
今回はPIC16F1938とLTC1485を使って、
一方向通信と双方向通信を実装します。

これまで、USART通信(PIC ⇔ PC)やI2C通信(LCD表示)パラレル通信(LCD表示)に成功しています。

そして今回は、長距離の通信も可能でノイズ対策もできる
RS485通信にチャレンジしました。

今回の回路図

今回はPIC – PICの通信をさせるため、
同じ配線の物を2つ準備します。
また、今回は一つのブレッドボードで
通信を行っているため、RS485のトランシーバ間を
LANケーブルのツイストペアになっているもので接続しています。

また、LTC1485のデータシートにも記載されているので、
配線の方法はこちらもご参考にしてください。

また、DEと/REをショートさせて、
RA2のhigh/lowで送信/受信を切り替えています。

実際のコードと解説

RS485通信の初期設定

c

void Pin_Init(void) {
    ANSELA = 0x00;           //デジタルにセット
    ANSELB = 0x00;           //デジタルにセット

    TRISAbits.TRISA2 = 0;    //RA2を送信にセット
    TRISAbits.TRISA1 = 0;    //RA1を送信にセット
    LATAbits.LATA2 = 0;      //RA2をLOW
    LATAbits.LATA1 = 0;      //RA1をLOW

    TRISCbits.TRISC6 = 1;    //USART使用時はRC6はUSARTに制御される
    TRISCbits.TRISC7 = 1;    //RC7(RX)を受信にセット

}
c

void USART_Init(void) {
    TXSTAbits.SYNC = 0;       //EUSARTモード選択 0:非同期  1:同期
    TXSTAbits.BRGH = 1;       //高baudレート選択 1:非同期高速モード
    BAUDCONbits.BRG16 = 1;    //0:8ビットbaudレート 1:16ビットbaudレート

    SPBRG = 207;              //baudレートを9600に(datasheet:P305)
    SPBRGH = 0;

    RCSTAbits.SPEN = 1;       //シリアルポート有効
    TXSTAbits.TXEN = 1;       //送信イネーブル

    RCSTAbits.CREN = 1;       //受信イネーブル
}

これらは、一方向、双方向共通となります。

一方向通信

c

#if NODE_TRANSMITTER
/* 送信モード */

    LATAbits.LATA2 = 1;           // RS485トランシーバを送信モード

    while (1) {
        while (!PIR1bits.TXIF);   //書き込み保留中でなくなるまで待つ
        TXREG = 'A';
        while (!TXSTAbits.TRMT);  //最後の1bitまで送信完了するのを待つ
        __delay_ms(1000);
    }
c

#else
/* 送信モード */

    LATAbits.LATA2 = 0;                    // RS485トランシーバを受信モード

    while (1) {
        if (PIR1bits.RCIF) {               // 受信保留中
            char data = RCREG;             // 受信したデータをdataに書き込む
            
            if (data == 'A') {
                LATAbits.LATA1 = !LATAbits.LATA1;   //LED反転
            }
        }

    }

NODE_TRANSMITTER = 1 送信モード
NODE_TRANSMITTER = 0 受信モード

として、それぞれを書き込む

 

双方向通信

c

/********マスターモード**********/ 
#if NODE_TRANSMITTER

    while (1) {
        if(RCSTAbits.OERR) {
     //受信文字が3文字以上を受信したときのエラーフラグが出た時の処理
            RCSTAbits.CREN = 0;
            RCSTAbits.CREN = 1;
        }
   
/********送信モード**********/     
        LATAbits.LATA2 = 1;
        
        while (!PIR1bits.TXIF);
        TXREG = 'A';
        while (!TXSTAbits.TRMT);
        //コマンド"A"を送信


/********受信モード**********/   
        LATAbits.LATA2 = 0;
        
        __delay_ms(100);     //デバッグしやすいように少し待つ
        
        if(PIR1bits.RCIF){
            data = RCREG;
            
            if (data == 'B') {
                LATAbits.LATA1 = !LATAbits.LATA1;
                //コマンド'B'を受信したらLEDを反転
            }
        }
        __delay_ms(1000);
    }
c

/********スレーブモード**********/ 
#else

/********受信モード**********/     
    LATAbits.LATA2 = 0;
    
    while (1) {
        if(RCSTAbits.OERR) {
            RCSTAbits.CREN = 0;
            RCSTAbits.CREN = 1;
        }
        
        if(PIR1bits.RCIF)
        {
            data = RCREG;
            
            if(data == 'A'){
                LATAbits.LATA1 = !LATAbits.LATA1;
                //コマンド"A"を受信したらLED反転

/********送信モード**********/ 
                LATAbits.LATA2 = 1;
                
                while (!PIR1bits.TXIF);
                TXREG = 'B';
                while (!TXSTAbits.TRMT);
                //コマンド"B"を送信

/********受信モード**********/ 
                LATAbits.LATA2 = 0;
            }
        }
    }    

一方向通信では、送信モードと受信モードを切り替えましたが、
双方向では、マスターモード(親機)とスレーブモード(子機)
と分けています。

NODE_TRANSMITTER = 1 マスターモード
NODE_TRANSMITTER = 0 スレーブモード

 

動作確認とまとめ

一方向通信では、受信側のLEDが1秒毎に点滅、
双方向通信では、送受信共にLEDが1秒毎に点滅していることが
確認できました。

RS485は半二重通信です。

そのため送信時はDE/RE=High、
受信時はDE/RE=Lowに切り替える必要があります。

DE・/REのhigh・lowを切り替えることによって、
送信・受信を切り替え、
RS485での通信が行われていることが確認できました。

今回のPIC間を50cm程度のLANケーブルで行いました。
理論上は200m程度まで通信できるとされています。

次回はRS485通信をさらに発展させ、
複数ノード間の通信や
DMX通信へつながる内容を学習していきます。

コメント

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