Загрузка данных


#include <Arduino.h>

// ---------- прототипы ----------
void MB_F03(uint8_t * data, uint16_t len);
void MB_F06(uint8_t * data, uint16_t len);
uint16_t GetCrc16(uint8_t * data, uint16_t len);

// ---------- глобальные переменные ----------
const uint16_t Slave_ID = 12;      // вариант 3: адрес ведомого — 5
uint16_t crc16;
uint16_t Hreg = 0;                // значение регистра AO
uint16_t Hreg_Addr = 5;          // вариант 3: адрес регистра AO — 12
#define debug false               // true — для отладки через RealTerm (эхо принятых байт)

uint8_t rcvData[256];
uint8_t idxBuf = 0;

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  // 1) приём байт из UART в буфер
  while (Serial.available()) {
    rcvData[idxBuf] = Serial.read();
    if (debug) Serial.write(rcvData[idxBuf]);
    idxBuf++;
    delay(5);
  }

  // 2) разбор принятого запроса
  if (idxBuf > 0) {
    uint8_t req[idxBuf];
    for (int i = 0; i < idxBuf; i++) req[i] = rcvData[i];

    // проверка контрольной суммы CRC16
    crc16 = GetCrc16(req, idxBuf - 2);
    uint8_t crc16Low  = crc16;
    uint8_t crc16High = crc16 >> 8;

    if ((crc16Low == req[sizeof(req) - 2]) && (crc16High == req[sizeof(req) - 1])) {
      // проверка адреса Slave ID
      if (req[0] == Slave_ID) {
        switch (req[1]) {          // проверка функционального кода Modbus
          case 0x06:
            MB_F06(&req[0], sizeof(req));
            break;
          case 0x03:
            MB_F03(&req[0], sizeof(req));
            break;
          default:
            break;
        }
      }
    }
    idxBuf = 0;
  }

  // 3) индикация текущего значения регистра светодиодом (вариант 3: условие <100)
  if (Hreg < 73) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

// ---------- чтение регистра AO (Modbus функция 0x03) ----------
void MB_F03(uint8_t * data, uint16_t len) {
  if (data[3] == Hreg_Addr && data[5] == 1) {
    uint8_t resSize = 3 + 2 + 2;   // адрес + код + кол-во байт + 2 байта данных + CRC
    uint8_t res[resSize];

    res[0] = data[0];       // Slave ID
    res[1] = data[1];       // функциональный код (эхо запроса)
    res[2] = 0x02;          // количество байт данных далее
    res[3] = Hreg >> 8;     // старший байт значения регистра
    res[4] = Hreg;          // младший байт значения регистра

    crc16 = GetCrc16(res, sizeof(res) - 2);
    res[5] = crc16;
    res[6] = crc16 >> 8;

    Serial.write(res, sizeof(res));
  }
}

// ---------- запись регистра AO (Modbus функция 0x06) ----------
void MB_F06(uint8_t * data, uint16_t len) {
  if (data[3] == Hreg_Addr) {
    Hreg = data[5];

    uint8_t resSize = 1 + 1 + 2 + 2 + 2;  // адрес+код+адрес рег.(2)+значение(2)+CRC(2)
    uint8_t res[resSize];

    for (uint8_t i = 0; i < resSize - 2; i++) res[i] = data[i];

    crc16 = GetCrc16(res, sizeof(res) - 2);
    res[6] = crc16;
    res[7] = crc16 >> 8;

    Serial.write(res, sizeof(res));
  }
}

// ---------- стандартный расчёт CRC16 (Modbus RTU) ----------
uint16_t GetCrc16(uint8_t * data, uint16_t len) {
  uint16_t crc = 0xFFFF;
  for (uint16_t pos = 0; pos < len; pos++) {
    crc ^= (uint16_t)data[pos];
    for (int i = 8; i != 0; i--) {
      if ((crc & 0x0001) != 0) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }
  return crc;
}