RS-485 트랜시버를 사용한 RS-485 센서와 Modbus 통신

업무상 RS-485 센서를 복수 사용하는 경우가 많습니다만,
Amazon에서 구입한 RS-485⇔Serial의 통신 변환 보드의 재고가 위험한 경우가 많습니다.
어쨌든 자작할 수 있으면…

소재


  • Seeeduino Mega
  • RS485/RS422 트랜시버 LTC485CN8
  • 점퍼 와이어
  • RS-485 센서

  • 환경


  • MacOS Catalina 10.15.7
  • Arduino IDE 1.8.12

  • 배선



    아래 그림과 같이 배선합니다.
    이번 사용하고 있는 센서가 5V 구동이므로 Mega로부터 그대로 전원을 잡을 수 있었습니다만,
    구동 전압이 다른 쪽은 다른 전원을 취해 오는 등 궁리해 주세요.



    브레드보드에서 배선한 사진입니다. (더럽고 죄송합니다..)


    코드



    rs485_test.ino
    
    #include <Arduino.h>
    #include <stdio.h>
    
    #define DE_PIN  3
    #define RE_PIN  2
    
    byte slaveID = 0x01;
    // 各自のRS-485センサーでの命令を記述してください
    byte getVolt[] = {slaveID, 0x03, 0x00, 0x16, 0x00, 0x02, 0x25, 0xCF};
    
    // 各自のRS-485センサーでのレスポンス時間に従って書き換えてください
    const int modbusTimeout = 30 * 1000;
    
    uint32_t startMillis = 0;
    int bytesRead = 0;
    
    byte responseBuffer[20];
    unsigned char p[4];
    float f = 0;
    
    void setup() {
      pinMode(DE_PIN, OUTPUT);
      pinMode(RE_PIN, OUTPUT);
    
      Serial.begin(115200);
      Serial1.begin(9600);
    
      Serial.println("setup completed!");
    }
    
    void loop() {
      transmit_enable();
    
      Serial1.write(getVolt, sizeof(getVolt)/sizeof(getVolt[0]));
      Serial1.flush();
      startMillis = millis();
    
      Serial.print("write instructions : ");
      // iは各自のセンサーの命令バイト数に従って書き換えてください
      for(int i=0; i < 8; i++){
        Serial.print(getVolt[i], HEX);  Serial.print(" ");
      }
    
      receive_enable();
    
      while ((Serial1.available() == 0) && ((millis() - startMillis) < modbusTimeout))
      { delay(1UL);}
    
      Serial.println();
    
      if (Serial1.available() > 0){
        // バイト数(10)は各自のセンサーのレスポンスバイト数に従って書き換えてください
        bytesRead = Serial1.readBytes(responseBuffer, 10);
    
        Serial.print("response frame : ");
    
        if(bytesRead > 0){
          // jは各自のセンサーのレスポンスバイト数に従って書き換えてください
          for(int j=0; j < 9; j++){
            Serial.print(responseBuffer[j], HEX); Serial.print(" ");
          }
        }
    
        Serial.println();
    
        // ここは私が使用しているセンサーの仕様で記述しています
        // 各自のセンサーのレスポンス仕様に従ってresponseBufferから値を取得してください
        p[0] = responseBuffer[3];
        p[1] = responseBuffer[4];
        p[2] = responseBuffer[5];
        p[3] = responseBuffer[6];
        f = get_float(p); // byte to float
        // 値取得ここまで
    
        Serial.print("float value : "); Serial.print(f);
        Serial.println();
      }
    
      Serial.println();
    
      emptyResponseBuffer(&Serial1);
      delay(5 * 1000UL);
    }
    
    void transmit_enable() {
      digitalWrite(DE_PIN, HIGH);
      digitalWrite(RE_PIN, HIGH);
    }
    
    void receive_enable() {
      digitalWrite(DE_PIN, LOW);
      digitalWrite(RE_PIN, LOW);
    }
    
    // Byte convert to float
    float get_float(unsigned char *p) 
    { 
      float value = 0;
      unsigned char *valueAddress = (unsigned char*)&value;
    
      *valueAddress = p[1];
      valueAddress++;
      *valueAddress = p[0];
      valueAddress++;
      *valueAddress = p[3];
      valueAddress++;
      *valueAddress = p[2];
    
      return(value); 
    }
    
    // This empties the serial buffer
    void emptyResponseBuffer(Stream *stream)
    {
        while (stream->available() > 0)
        {
            stream->read();
            delay(1);
        }
    }
    

    결과



    이번에 사용한 명령은 센서의 내부 전압(3.3V)을 반환하는 명령이었습니다.

    이와 같이 무사히 응답이 돌아왔다.

    요약



    일단 기본 통신을 할 수 있었으므로 안심입니다.
    보다 간이하게 통신할 수 있도록, 기판 제작에 도전해 가고 싶습니다.

    좋은 웹페이지 즐겨찾기