/* ===================================================================
Transformer Monitor - WOKWI SIMULATION VERSION 3 (Blue Pill, stm32duino)
Temperature source (choose one with the switch below):
USE_POTENTIOMETER 0 -> DS18B20 on PB0 (own 1-Wire routine, skip-ROM + CRC)
USE_POTENTIOMETER 1 -> potentiometer on PA0 (0..100 degrees C), a
simulation stand-in if Wokwi's DS18B20 does not
cooperate with the STM32 timing.
Pins: PA4 green LED | PA5 yellow LED | PA6 red LED
PB1 buzzer indicator | PB0 DS18B20 data | PA0 potentiometer
PC13 heartbeat LED
=================================================================== */
#define USE_POTENTIOMETER 1 // <-- change to 1 to use the potentiometer
#define PIN_GREEN PA4
#define PIN_YELLOW PA5
#define PIN_RED PA6
#define PIN_BUZZER PB1
#define PIN_ONEWIRE PB0
#define PIN_POT PA0
#define PIN_HEART PC13
// Example thresholds - set them from your transformer's rating/datasheet
const float TEMP_WARN_ON = 55.0; // enter WARNING at or above this
const float TEMP_WARN_OFF = 52.0; // leave WARNING only below this
const float TEMP_CRIT_ON = 70.0; // enter CRITICAL at or above this
const float TEMP_CRIT_OFF = 66.0; // leave CRITICAL only below this
const float TEMP_MIN_VALID = -20.0; // readings outside this range = fault
const float TEMP_MAX_VALID = 110.0;
const uint8_t FAULT_AFTER_FAILS = 3;
enum MonitorState { ST_NORMAL = 0, ST_WARNING, ST_CRITICAL, ST_FAULT };
const char *stateNames[] = { "NORMAL", "WARNING", "CRITICAL", "SENSOR FAULT" };
MonitorState currentState = ST_NORMAL;
uint8_t fails = 0;
/* ---------------- 1-Wire / DS18B20 (bit-banged) ---------------- */
static inline void owLow() { digitalWrite(PIN_ONEWIRE, LOW); }
static inline void owRelease() { digitalWrite(PIN_ONEWIRE, HIGH); } // open-drain: line floats high
// Returns 1 if a sensor answered with a presence pulse
uint8_t owReset() {
uint8_t presence;
noInterrupts();
owLow();
delayMicroseconds(480);
owRelease();
delayMicroseconds(70);
presence = (digitalRead(PIN_ONEWIRE) == LOW) ? 1 : 0;
interrupts();
delayMicroseconds(410);
return presence;
}
void owWriteBit(uint8_t bit) {
noInterrupts();
owLow();
if (bit) {
delayMicroseconds(6);
owRelease();
delayMicroseconds(64);
} else {
delayMicroseconds(60);
owRelease();
delayMicroseconds(10);
}
interrupts();
}
uint8_t owReadBit() {
uint8_t bit;
noInterrupts();
owLow();
delayMicroseconds(3);
owRelease();
delayMicroseconds(7); // sample about 10 us after the falling edge
bit = (digitalRead(PIN_ONEWIRE) == HIGH) ? 1 : 0;
delayMicroseconds(55);
interrupts();
return bit;
}
void owWriteByte(uint8_t data) {
for (uint8_t i = 0; i < 8; i++) {
owWriteBit(data & 0x01);
data >>= 1;
}
}
uint8_t owReadByte() {
uint8_t value = 0;
for (uint8_t i = 0; i < 8; i++) {
value |= (uint8_t)(owReadBit() << i);
}
return value;
}
// Dallas/Maxim CRC-8
uint8_t owCrc8(const uint8_t *data, uint8_t len) {
uint8_t crc = 0;
while (len--) {
uint8_t b = *data++;
for (uint8_t i = 0; i < 8; i++) {
uint8_t mix = (crc ^ b) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
b >>= 1;
}
}
return crc;
}
// Returns true and fills temp (deg C) on success, false on any failure
bool readTemperature(float &temp) {
uint8_t sp[9];
if (!owReset()) return false;
owWriteByte(0xCC); // skip ROM (single sensor on the bus)
owWriteByte(0x44); // start temperature conversion
delay(750); // 12-bit conversion time
if (!owReset()) return false;
owWriteByte(0xCC);
owWriteByte(0xBE); // read scratchpad
for (uint8_t i = 0; i < 9; i++) sp[i] = owReadByte();
if (owCrc8(sp, 8) != sp[8]) return false; // corrupted data -> reject
// An all-zero block has a "valid" CRC of 0, so a line stuck low would
// look like 0.0 C. The config register's low 5 bits are always 1 on a
// real DS18B20, so a block without them is not genuine sensor data.
if ((sp[4] & 0x1F) != 0x1F) return false;
int16_t raw = (int16_t)(((uint16_t)sp[1] << 8) | sp[0]);
temp = (float)raw / 16.0;
return true;
}
/* One entry point for the temperature, whichever source is selected */
bool getTemperature(float &t) {
#if USE_POTENTIOMETER
t = analogRead(PIN_POT) * 100.0 / 1023.0; // 0..100 deg C
return true;
#else
return readTemperature(t);
#endif
}
/* ---------------- Monitor logic ---------------- */
// Threshold logic with hysteresis
void updateState(float t) {
switch (currentState) {
case ST_FAULT:
case ST_NORMAL:
if (t >= TEMP_CRIT_ON) currentState = ST_CRITICAL;
else if (t >= TEMP_WARN_ON) currentState = ST_WARNING;
else currentState = ST_NORMAL;
break;
case ST_WARNING:
if (t >= TEMP_CRIT_ON) currentState = ST_CRITICAL;
else if (t < TEMP_WARN_OFF) currentState = ST_NORMAL;
break;
case ST_CRITICAL:
if (t < TEMP_CRIT_OFF) {
currentState = (t >= TEMP_WARN_OFF) ? ST_WARNING : ST_NORMAL;
}
break;
}
}
// NORMAL = green | WARNING = yellow | CRITICAL = red + buzzer |
// SENSOR FAULT = yellow + red together (never shown as normal)
void setOutputs() {
digitalWrite(PIN_GREEN, currentState == ST_NORMAL ? HIGH : LOW);
digitalWrite(PIN_YELLOW, (currentState == ST_WARNING || currentState == ST_FAULT) ? HIGH : LOW);
digitalWrite(PIN_RED, (currentState == ST_CRITICAL || currentState == ST_FAULT) ? HIGH : LOW);
digitalWrite(PIN_BUZZER, currentState == ST_CRITICAL ? HIGH : LOW);
}
void setup() {
Serial.begin(115200);
delay(500); // give the serial monitor time to attach
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_YELLOW, OUTPUT);
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_HEART, OUTPUT);
pinMode(PIN_ONEWIRE, OUTPUT_OPEN_DRAIN);
owRelease();
delay(10);
Serial.println("Transformer Monitor - Wokwi simulation v3");
#if USE_POTENTIOMETER
Serial.println("Temperature source: potentiometer on PA0 (0-100 C)");
#else
Serial.println("Temperature source: DS18B20 on PB0");
Serial.print("Presence pulse (1 = sensor answered): ");
Serial.println(owReset());
#endif
setOutputs();
}
void loop() {
float t = 0.0;
bool ok = getTemperature(t) && (t > TEMP_MIN_VALID) && (t < TEMP_MAX_VALID);
if (ok) {
fails = 0;
updateState(t);
Serial.print("Temp: ");
Serial.print(t, 1);
Serial.print(" C | State: ");
Serial.println(stateNames[currentState]);
} else {
if (fails < 255) fails++;
if (fails >= FAULT_AFTER_FAILS) currentState = ST_FAULT;
Serial.print("Sensor read failed | State: ");
Serial.println(stateNames[currentState]);
}
setOutputs();
digitalWrite(PIN_HEART, !digitalRead(PIN_HEART)); // heartbeat LED
delay(250);
}
Loading
stm32-bluepill
stm32-bluepill