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