はじめに
この記事は、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通信へつながる内容を学習していきます。

コメント