Added firmware of temperature sensor

This commit is contained in:
marcel
2025-08-01 17:35:02 +02:00
parent fb9de94312
commit 053ab6348e

View File

@@ -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
}
}