Информация от DS18B20 по RS485

dovant
Offline
Зарегистрирован: 31.05.2020

Добрый день. Подскажите, пожалуйста, как организовать передачу/прием информации от датчиков температуры по RS485 так чтобы можно было обрабатывать каждый датчик независимо от другого? И как передать float по rs485?

Железо выглядит так:

- Передатчик. Нано, на ней три датчика ds18b20.

-  Приемник. Уно, 4 ds18b20 на OneWire и прием по 485.

//Передатчик
#include <SoftwareSerial.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>

SoftwareSerial RS485Serial (9,10);
const float PIN_DIR = 3;
OneWire  ds(2);
DallasTemperature sensors(&ds);                                         //Создаем объект sensors, подключенный по OneWire
DeviceAddress temp1DeviceAddress;                                       //переменная для хранения адреса датчика
DeviceAddress temp2DeviceAddress;                                       //второй информационный датчик
//DeviceAddress temp3DeviceAddress;                                       //переменная для хранения адреса датчика
float temp[2];

void setup() {
  pinMode (PIN_DIR, OUTPUT);
  digitalWrite(PIN_DIR,HIGH);
  Serial.begin(9600);
  sensors.begin();
  RS485Serial.begin(9600);
}

void loop() {
  //Запуск процедуры измерения температуры
  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);
delay(750);
 
  //Считывание значения температуры
  sensors.getAddress(temp1DeviceAddress, 0);
  temp[0] = sensors.getTempC(temp1DeviceAddress);
  Serial.print("Kabel 1 = ");
  Serial.print(temp[0]);
  Serial.println("C");
  RS485Serial.write(temp[0]);
  delay(750);
  sensors.getAddress(temp2DeviceAddress, 1);
  temp[1] = sensors.getTempC(temp2DeviceAddress);
  Serial.print("Kabel 2 = ");
  Serial.print(temp[1]);
  Serial.println("C");
  RS485Serial.write(temp[1]);



 //Приемник
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>

RF24 radio(10, 9); // CE, CSN
OneWire  ds(2);

SoftwareSerial RS485Serial (6,7);
const float PIN_DIR = 4;
DallasTemperature sensors(&ds);                                         //Создаем объект sensors, подключенный по OneWire
DallasTemperature sensors_p(&ds_p);
//Создаем переменные для работы с термометром
DeviceAddress temp1DeviceAddress;                                       //переменная для хранения адреса датчика
DeviceAddress temp2DeviceAddress;                                       //второй информационный датчик
DeviceAddress temp3DeviceAddress;                                       //переменная для хранения адреса датчика
DeviceAddress temp4DeviceAddress;
DeviceAddress temp5DeviceAddress;                                       //второй информационный датчик
DeviceAddress temp6DeviceAddress;                                       //переменная для хранения адреса датчика
DeviceAddress temp7DeviceAddress;   
float temp;
float temp_p;
void setup() {
  pinMode (PIN_DIR, OUTPUT);
  digitalWrite(PIN_DIR,LOW);
  RS485Serial.begin(9600);
  Serial.begin(9600);
  sensors.begin();
  sensors_p.begin();
  delay(2);
  }

void loop() {
//  Запуск процедуры измерения температуры
  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);
delay(750);
  sensors_p.setWaitForConversion(false);
  sensors_p.requestTemperatures();
  sensors_p.setWaitForConversion(true);

  //Считывание значения температуры
  sensors.getAddress(temp1DeviceAddress, 0);
  temp[0] = sensors.getTempC(temp1DeviceAddress);
  Serial.print("Kabel 1 = ");
  Serial.print(temp[0]);
  Serial.println("C");
  delay(750);
  sensors.getAddress(temp2DeviceAddress, 1);
  temp[1] = sensors.getTempC(temp2DeviceAddress);
  Serial.print("Kabel 2 = ");
  Serial.print(temp[1]);
  Serial.println("C");
  delay(750);
  sensors.getAddress(temp3DeviceAddress, 2);
  temp[2] = sensors.getTempC(temp3DeviceAddress);
  Serial.print("Kabel 3 = ");
  Serial.print(temp[2]);
  Serial.println("C");
  delay(750);
  sensors.getAddress(temp4DeviceAddress, 3);
  temp[3] = sensors.getTempC(temp4DeviceAddress);
  Serial.print("Kabel 4 = ");
  Serial.print(temp[3]);
  Serial.println("C");
  delay(750);

  if (RS485Serial.available() > 0)    
      temp = RS485Serial.read();
      Serial.write(RS485Serial.read());
      Serial.println (temp);
      delay (100);
  
     }

 

b707
Онлайн
Зарегистрирован: 26.05.2017

Тип флоат на ардуино - это 4 байта. А вы в коде передаете только один байт, поэтому ничего хорошего не выходит.Чтобы передать флоат по Сериал или по RS485 - нужно сначала разбить флоат на 4 байта, потом передать эти байты - а потом в приемнике обратно собрать из 4х байтов флоат.

А чтобы передавать данные двух датчиков - нужно передавать не только температуру. но и номер датчика.

Но это еще не все. Понимаете, правильно передавать данные между ардуинами - это немного больше чем просто пихать байты в линию со стороны передачтчика и ждать что они придут на приемник :) На самом деле тут нужно позаботится о том, что бы обе ардуины понимали, когда начинается передача, сколько в ней байт, когда она закончена, а так же умели проверять правильность принятых данных. Все это обеспечивается так называемым протоколом - правилами передачи, которые вы либо должны описать в программе сами. либо использовать готовый, например Модбас

dovant
Offline
Зарегистрирован: 31.05.2020

b707 пишет:

Тип флоат на ардуино - это 4 байта. А вы в коде передаете только один байт, поэтому ничего хорошего не выходит.Чтобы передать флоат по Сериал или по RS485 - нужно сначала разбить флоат на 4 байта, потом передать эти байты - а потом в приемнике обратно собрать из 4х байтов флоат.

Попробовал разбить флоат так:

float temperature;
uint8_t *array; 
array = (unit8_t*)(&temperature);
 RS485Serial.write(array,4);

А собрать так:

float temperature;
temperature = *((float*)array);

ничего не получилось. Пришли какие-то непонятные символы. Подскажите, хоть в какую сторону смотреть, может есть что почитать доступным языком про int в float?

sergek
sergek аватар
Offline
Зарегистрирован: 05.04.2020

Выкусил из рабочей прошивки. Возможно, что-то упустил, но принцип должен быть понятен. Каждая температура передается в двух 16-битных регистрах modbus:

const byte MAX_SENSORS_QTY = 10;                    // максимальное колическтво датчиков на линии
DeviceAddress sensAddress[MAX_SENSORS_QTY];         // массив адресов датчиков температуры
byte bufSensTmp[9];                                 // буфер данных датчика температуры
word registers[56];                                 // таблица Modbus-регистров (массив из 56 регситров):
#define ACCUR                     10                // установка значения точности датчиков
                                                    // 9 -  0,5000 (094 мс)
                                                    // 10 - 0,2500 (187 мс)
                                                    // 11 - 0,1250 (375 мс)
                                                    // 12 - 0,0625 (750 мс)


        for (byte i=0; i<MAX_SENSORS_QTY; i++) {
            float temperature = -127;                                                             // переменная для хранения температуры

                int retries = 0;                                                                  // текущая попытка чтения
                while(retries++ < numberOfRetries) {
                    temperature = -127;
                    oneWire.reset();                                                              // сброс шины
                    oneWire.select(sensAddress[i]);                                               // выбор датчика
                    oneWire.write(0xBE, POWER_MODE);                                              // команда чтения памяти датчика
                    oneWire.read_bytes(bufSensTmp, 9);                                            // чтение памяти датчика, 9 байтов

                    // проверка CRC и ненулевого значения регистра конфигурации
                    if (OneWire::crc8(bufSensTmp, 8) == bufSensTmp[8] && bufSensTmp[4]) {
                                                                                                  // выделение слова данных с обнулением незначащих бит
                        int mask = 0xFFFF << (12-ACCUR);                                          // маска для обнуления незначащих бит в зависимости от разрядности
                        int16_t rom = ((int)bufSensTmp[0]) | (((int)bufSensTmp[1]) << 8);
                        rom = rom & mask;
                                                                                                  // знак температуры определяется по старшей тетраде. rom - 16-битное целое
                        if(rom & 0xF000) {                                                        // отрицательная температура (биты S = 1)
                          temperature = -(~rom + 1)*0.0625;
                        } 
                        else {                                                                    // положительная температура
                         temperature = rom*0.0625;
                        }
                        
                        break;     
                    }
                }
            * (float *)(registers+i*2) = temperature;
        }