Added firmware of temperature sensor
This commit is contained in:
@@ -0,0 +1,238 @@
|
|||||||
|
/*********************************************************************************
|
||||||
|
*
|
||||||
|
* A temperature sensor which can be connected to an RS-485 ModBus interface.
|
||||||
|
*
|
||||||
|
* LED on Arduino gives status:
|
||||||
|
*
|
||||||
|
* ON : Booting
|
||||||
|
* BLINK : I2C ERROR
|
||||||
|
* FLASH : Heartbeat
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 M.T. Konstapel https://meezenest.nl/mees
|
||||||
|
*
|
||||||
|
* This file is part of weather_station_MK2_sensor_temperature
|
||||||
|
*
|
||||||
|
* weather_station_MK2_sensor_temperature is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* weather_station_MK2_sensor_temperature is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with weather_station_MK2_sensor_temperature. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* See CHANGELOG.md
|
||||||
|
*
|
||||||
|
**********************************************************************************/
|
||||||
|
|
||||||
|
// When set to 1 debug messages are send to the serial port, set it to 0 for production code!
|
||||||
|
#define _DEBUG_ 0
|
||||||
|
|
||||||
|
#include <ModbusSerial.h>
|
||||||
|
#include "SparkFun_Weather_Meter_Kit_Arduino_Library.h"
|
||||||
|
|
||||||
|
/**************************/
|
||||||
|
/* Configurable variables */
|
||||||
|
/**************************/
|
||||||
|
// RS485 driver
|
||||||
|
#define RS485_RE 11 // Tight to RS485_DE and must be configured as an input to prevent a short circuit
|
||||||
|
#define RS485_DE 12
|
||||||
|
// Used Pins
|
||||||
|
const uint16_t TxenPin = RS485_DE; // -1 disables the feature, change that if you are using an RS485 driver, this pin would be connected to the DE and /RE pins of the driver.
|
||||||
|
// ModBus address
|
||||||
|
const uint8_t SlaveId = 14;
|
||||||
|
/* Modbus Input Registers
|
||||||
|
*
|
||||||
|
* 0-3 : DefineSensorSerial (unique value): 0x4D45 followed by index. The index starts at 0x0 0x0 0x0 and is incremented for every unique device.
|
||||||
|
* 4 : Sensor Type (specifies sensor type): 0x01 for this temperature sensor
|
||||||
|
* 5 : Sensor Version (specifies sensor version)
|
||||||
|
* 6-30 : Human readable description of sensor: Every register holds two ASCII values, one in the MSB and the other in the LSB for a total of 60 characters. "Temparature sensor with two sensors"
|
||||||
|
* 31 : Number of available input registers
|
||||||
|
*
|
||||||
|
* 40 : Temperature reading sensor 1
|
||||||
|
* 41 : Temperature reading sensor 2 (if available)
|
||||||
|
* 42 : Minimum temperature reading sensor 1 since last reset
|
||||||
|
* 43 : Minimum temperature reading sensor 2 since last reset (if available)
|
||||||
|
* 44 : Maximum temperature reading sensor 1 since last reset
|
||||||
|
* 45 : Maximum temperature reading sensor 2 since last reset (if available)
|
||||||
|
*/
|
||||||
|
// Pre-defined register values
|
||||||
|
const uint16_t DefineSensorSerial[4] = {0x4D45,0x00,0x00,0x01};
|
||||||
|
const uint16_t DefineSensorType = 0x01;
|
||||||
|
const uint16_t DefineSensorVersion = 0x01;
|
||||||
|
const uint8_t DefineSensorTypeString[] = "Dual temperature sensor"; // Make sure the string is not longer than 60 charaters
|
||||||
|
const uint16_t DefineNumberOfInputRegisters = 6;
|
||||||
|
const uint16_t DefineNumberOfHoldingRegisters = 0;
|
||||||
|
const uint16_t DefineNumberOfCoilRegisters = 0;
|
||||||
|
const uint16_t DefineNumberOfContactRegisters = 0;
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
const uint16_t SensorID[4] = {0,1,2,3};
|
||||||
|
const uint16_t SensorType = 4;
|
||||||
|
const uint16_t SensorVersion = 5;
|
||||||
|
const uint16_t SensorTypeString[30] = {6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35};
|
||||||
|
const uint16_t NumberOfInputRegisters = 36;
|
||||||
|
const uint16_t NumberOfHoldingRegisters = 37;
|
||||||
|
const uint16_t NumberOfCoilRegisters = 38;
|
||||||
|
const uint16_t NumberOfContactRegisters = 39;
|
||||||
|
|
||||||
|
const uint16_t SensorTemperature[2] = {40,41};
|
||||||
|
const uint16_t SensorTemperatureMin[2] = {42,43};
|
||||||
|
const uint16_t SensorTemperatureMax[2] = {44,45};
|
||||||
|
|
||||||
|
/* Modbus Coil Registers
|
||||||
|
* 0: ResetMinMax (Reset Min/Max values)
|
||||||
|
*/
|
||||||
|
const uint16_t ResetMinMax = 0;
|
||||||
|
|
||||||
|
// RS-485 serial port
|
||||||
|
#define MySerial Serial // define serial port used, Serial most of the time, or Serial1, Serial2 ... if available
|
||||||
|
const uint32_t Baudrate = 9600;
|
||||||
|
/******************************/
|
||||||
|
/* END Configurable variables */
|
||||||
|
/******************************/
|
||||||
|
|
||||||
|
// ModbusSerial object
|
||||||
|
ModbusSerial mb (MySerial, SlaveId, TxenPin);
|
||||||
|
|
||||||
|
uint32_t ts;
|
||||||
|
|
||||||
|
struct MeasuredData {
|
||||||
|
float Temperature01;
|
||||||
|
float Temperature02;
|
||||||
|
|
||||||
|
float MinTemperature01;
|
||||||
|
float MinTemperature02;
|
||||||
|
|
||||||
|
float MaxTemperature01;
|
||||||
|
float MaxTemperature02;
|
||||||
|
|
||||||
|
} MeasuredData;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
uint16_t RegisterIndex;
|
||||||
|
|
||||||
|
MySerial.begin (Baudrate); // works on all boards but the configuration is 8N1 which is incompatible with the MODBUS standard
|
||||||
|
// prefer the line below instead if possible
|
||||||
|
// MySerial.begin (Baudrate, MB_PARITY_EVEN);
|
||||||
|
|
||||||
|
// initialize digital pin LED_BUILTIN as an output and turn it on.
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
|
||||||
|
//Setup control lines for RS485 driver
|
||||||
|
pinMode(RS485_RE,INPUT); // In hardware connected to RS485_DE. Should be input to prevent a short circuit!
|
||||||
|
pinMode(RS485_DE,OUTPUT);
|
||||||
|
digitalWrite(RS485_DE,LOW);
|
||||||
|
|
||||||
|
mb.config (Baudrate);
|
||||||
|
mb.setAdditionalServerData ("TEMP_SENSOR"); // for Report Server ID function (0x11)
|
||||||
|
|
||||||
|
// Add SensorID to ModBus
|
||||||
|
for (RegisterIndex = 0; RegisterIndex < 4; RegisterIndex++) {
|
||||||
|
mb.addIreg (SensorID[RegisterIndex]);
|
||||||
|
mb.Ireg (SensorID[RegisterIndex], DefineSensorSerial[RegisterIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add SensorType to ModBus
|
||||||
|
mb.addIreg (SensorType);
|
||||||
|
|
||||||
|
mb.addIreg (SensorTemperature[0]);
|
||||||
|
mb.addIreg (SensorTemperature[1]);
|
||||||
|
mb.addIreg (SensorTemperatureMin[0]);
|
||||||
|
mb.addIreg (SensorTemperatureMin[1]);
|
||||||
|
mb.addIreg (SensorTemperatureMax[0]);
|
||||||
|
mb.addIreg (SensorTemperatureMax[1]);
|
||||||
|
// Add HeaterCoil register
|
||||||
|
mb.addCoil (ResetMinMax);
|
||||||
|
|
||||||
|
// Set Weather station ID (ModBus)
|
||||||
|
mb.Ireg (SensorType, DefineSensorType);
|
||||||
|
|
||||||
|
// Fill SensorTypeString (ModBus)
|
||||||
|
uint16_t SensorTypeCharacter;
|
||||||
|
uint16_t LastRegister;
|
||||||
|
|
||||||
|
// Get length of pre defined description string
|
||||||
|
LastRegister = strlen(DefineSensorTypeString);
|
||||||
|
|
||||||
|
// Add SensorTypeString to ModBus
|
||||||
|
for (RegisterIndex = 0; RegisterIndex < 30; RegisterIndex++) {
|
||||||
|
|
||||||
|
mb.addIreg (SensorTypeString[RegisterIndex]);
|
||||||
|
|
||||||
|
// Fill MSB of SensorTypeString with character from pre defined string until we reach the end of the description string
|
||||||
|
if (2*RegisterIndex < LastRegister) {
|
||||||
|
SensorTypeCharacter = DefineSensorTypeString[2*RegisterIndex] << 8;
|
||||||
|
// ...otherwise fill with a space
|
||||||
|
} else {
|
||||||
|
SensorTypeCharacter = ' ' << 8;
|
||||||
|
}
|
||||||
|
// Fill LSB of SensorTypeString with character from pre defined string until we reach the end of the description string
|
||||||
|
if ((2*RegisterIndex)+1 < LastRegister) {
|
||||||
|
SensorTypeCharacter += DefineSensorTypeString[(2*RegisterIndex)+1];
|
||||||
|
// ...otherwise fill with a space
|
||||||
|
} else {
|
||||||
|
SensorTypeCharacter += ' ';
|
||||||
|
}
|
||||||
|
mb.Ireg (SensorTypeString[RegisterIndex], SensorTypeCharacter);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mb.addIreg (NumberOfInputRegisters);
|
||||||
|
mb.Ireg (NumberOfInputRegisters, DefineNumberOfInputRegisters);
|
||||||
|
|
||||||
|
mb.addIreg (NumberOfHoldingRegisters);
|
||||||
|
mb.Ireg (NumberOfHoldingRegisters, DefineNumberOfHoldingRegisters);
|
||||||
|
|
||||||
|
mb.addIreg (NumberOfCoilRegisters);
|
||||||
|
mb.Ireg (NumberOfCoilRegisters, DefineNumberOfCoilRegisters);
|
||||||
|
|
||||||
|
mb.addIreg (NumberOfContactRegisters);
|
||||||
|
mb.Ireg (NumberOfContactRegisters, DefineNumberOfContactRegisters);
|
||||||
|
|
||||||
|
Serial.println(F("weather_station_MK2_sensor_temperature v0.1"));
|
||||||
|
Serial.println(F("(C) 2025 M.T. Konstapel"));
|
||||||
|
Serial.println(F("This project is free and open source (GPL-3.0)"));
|
||||||
|
Serial.println(F("More details: https://meezenest.nl/mees/"));
|
||||||
|
|
||||||
|
ts = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Call once inside loop() - all magic here
|
||||||
|
mb.task();
|
||||||
|
|
||||||
|
// Read each two seconds
|
||||||
|
if ( ( millis() - ts) >= 2000) {
|
||||||
|
|
||||||
|
ts = millis();
|
||||||
|
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH); // LED as heartbeat
|
||||||
|
|
||||||
|
// Fill input registers
|
||||||
|
mb.Ireg (SensorTemperature[0], 20);
|
||||||
|
mb.Ireg (SensorTemperature[1], 21);
|
||||||
|
mb.Ireg (SensorTemperatureMin[0], 22);
|
||||||
|
mb.Ireg (SensorTemperatureMax[0], 23);
|
||||||
|
mb.Ireg (SensorTemperatureMin[1], 24);
|
||||||
|
mb.Ireg (SensorTemperatureMax[1], 25);
|
||||||
|
|
||||||
|
// reset min/max temperatures
|
||||||
|
if (mb.Coil (ResetMinMax)) {
|
||||||
|
// reset min/max temperatures
|
||||||
|
} else {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(LED_BUILTIN, LOW); // LED as heartbeat
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user