Информация от DS18B20 по RS485
- Войдите на сайт для отправки комментариев
Вс, 31/05/2020 - 23:26
Добрый день. Подскажите, пожалуйста, как организовать передачу/прием информации от датчиков температуры по 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);
}
Тип флоат на ардуино - это 4 байта. А вы в коде передаете только один байт, поэтому ничего хорошего не выходит.Чтобы передать флоат по Сериал или по RS485 - нужно сначала разбить флоат на 4 байта, потом передать эти байты - а потом в приемнике обратно собрать из 4х байтов флоат.
А чтобы передавать данные двух датчиков - нужно передавать не только температуру. но и номер датчика.
Но это еще не все. Понимаете, правильно передавать данные между ардуинами - это немного больше чем просто пихать байты в линию со стороны передачтчика и ждать что они придут на приемник :) На самом деле тут нужно позаботится о том, что бы обе ардуины понимали, когда начинается передача, сколько в ней байт, когда она закончена, а так же умели проверять правильность принятых данных. Все это обеспечивается так называемым протоколом - правилами передачи, которые вы либо должны описать в программе сами. либо использовать готовый, например Модбас
Тип флоат на ардуино - это 4 байта. А вы в коде передаете только один байт, поэтому ничего хорошего не выходит.Чтобы передать флоат по Сериал или по RS485 - нужно сначала разбить флоат на 4 байта, потом передать эти байты - а потом в приемнике обратно собрать из 4х байтов флоат.
Попробовал разбить флоат так:
А собрать так:
ничего не получилось. Пришли какие-то непонятные символы. Подскажите, хоть в какую сторону смотреть, может есть что почитать доступным языком про int в float?
Выкусил из рабочей прошивки. Возможно, что-то упустил, но принцип должен быть понятен. Каждая температура передается в двух 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; }