#include <EEPROM.h>
#include <SoftwareSerial.h>
//--- Pin Definitions ---
const int TEMP_SENSOR_PIN = 1; // ADC1 (Physical pin 7)
const int CONTROL_PIN = 0; // PB0 (Physical pin 5)
const int RX_PIN = 3; // PB3 (Physical pin 2)
const int TX_PIN = 4; // PB4 (Physical pin 3)
//--- EEPROM Addresses ---
const int UPPER_LIMIT_ADDR = 0;
const int LOWER_LIMIT_ADDR = 4; // Use a different address for each value
//--- Global Variables ---
int upperLimitADC = 700; // Default: Corresponds to ~28°C with the example sensor. Will be overwritten from EEPROM
int lowerLimitADC = 300; // Default: Corresponds to ~15°C with the example sensor. Will be overwritten from EEPROM
int temperatureADC;
bool controlPinState = LOW;
SoftwareSerial mySerial(RX_PIN, TX_PIN); // Initialize SoftwareSerial
//--- Function Declarations ---
void readTemperature();
void checkLimitsAndControl();
void updateLimitsFromSerial();
void storeLimitsToEEPROM();
void readLimitsFromEEPROM();
float convertADCtoCelsius(int adc_value); //Added function for converting ADC to celcius
//--- Setup ---
void setup() {
//--- Initialize I/O Pins ---
pinMode(CONTROL_PIN, OUTPUT);
digitalWrite(CONTROL_PIN, controlPinState); //set default value
//--- Initialize ADC ---
analogReference(DEFAULT); // Use default VCC as reference
// No need to set ADPS2, ADPS1, ADPS0 in ADCSRA, because the default value after reset is 0,
// and it means f_osc/2 as ADC clock source, that is less than 200kHz.
//--- Initialize Serial Communication ---
mySerial.begin(9600);
delay(100); // Give serial port time to initialize
//--- Read Limits from EEPROM ---
readLimitsFromEEPROM();
// Send a startup message
mySerial.println("ATtiny85 Temperature Monitor");
mySerial.print("Upper Limit: ");
mySerial.println(upperLimitADC);
mySerial.print("Lower Limit: ");
mySerial.println(lowerLimitADC);
}
//--- Main Loop ---
void loop() {
readTemperature();
checkLimitsAndControl();
updateLimitsFromSerial();
delay(1000); // Delay 1 second
}
//--- Function Definitions ---
void readTemperature() {
// Read the analog value from the temperature sensor
temperatureADC = analogRead(TEMP_SENSOR_PIN);
// No need to discard first reading, because it is not mentioned in the datasheet.
// Send the ADC value for debugging
mySerial.print("Temperature ADC: ");
mySerial.println(temperatureADC);
}
void checkLimitsAndControl() {
// Check if the temperature is outside the limits
if (temperatureADC > upperLimitADC || temperatureADC < lowerLimitADC) {
if (controlPinState == LOW) {
controlPinState = HIGH;
digitalWrite(CONTROL_PIN, controlPinState);
mySerial.println("Temperature OUT OF limits - Activating control");
}
} else {
if (controlPinState == HIGH) {
controlPinState = LOW;
digitalWrite(CONTROL_PIN, controlPinState);
mySerial.println("Temperature WITHIN limits - Deactivating control");
}
}
}
void updateLimitsFromSerial() {
// Check if there is data available on the serial port
if (mySerial.available() > 0) {
String data = mySerial.readStringUntil('\n'); // Read until newline
data.trim(); // Remove leading/trailing whitespace
// Parse the data for the limits. Robust parsing.
int upperIndex = data.indexOf("UPPER=");
int lowerIndex = data.indexOf("LOWER=");
if (upperIndex != -1 && lowerIndex != -1) {
String upperStr = data.substring(upperIndex + 6, lowerIndex); //extract the upper limit value
String lowerStr = data.substring(lowerIndex + 6); // Extract lower limit
//attempt to convert the string to a number.
int newUpperLimit = upperStr.toInt();
int newLowerLimit = lowerStr.toInt();
if(newUpperLimit != 0 && newLowerLimit != 0){ //check if the conversion was successful
upperLimitADC = newUpperLimit;
lowerLimitADC = newLowerLimit;
storeLimitsToEEPROM(); //save to eeprom
mySerial.println("Limits Updated and Stored:");
mySerial.print("Upper Limit: ");
mySerial.println(upperLimitADC);
mySerial.print("Lower Limit: ");
mySerial.println(lowerLimitADC);
}
else{
mySerial.println("Invalid format. Use UPPER=XXX LOWER=YYY");
}
}
else {
mySerial.println("Invalid format. Use UPPER=XXX LOWER=YYY");
}
}
}
void storeLimitsToEEPROM() {
// Store the upper and lower limits in EEPROM
EEPROM.put(UPPER_LIMIT_ADDR, upperLimitADC);
EEPROM.put(LOWER_LIMIT_ADDR, lowerLimitADC);
}
void readLimitsFromEEPROM() {
// Read the upper and lower limits from EEPROM
EEPROM.get(UPPER_LIMIT_ADDR, upperLimitADC);
EEPROM.get(LOWER_LIMIT_ADDR, lowerLimitADC);
}
float convertADCtoCelsius(int adc_value) {
// This is just an example conversion. You MUST replace this with the
// correct formula for your specific temperature sensor.
//
// For example, if you are using a TMP36:
// float voltage = adc_value * (5.0 / 1023.0); // Convert ADC value to voltage (assuming 5V Vref)
// float temperatureC = (voltage - 0.5) * 100; // Convert voltage to temperature in Celsius
//
// If you are using a thermistor, the calculation will be more complex and
// involve the Steinhart-Hart equation or a simplified approximation. You'll
// need the thermistor's datasheet values (R0, T0, B) to do this accurately.
//
// This example is for demonstration ONLY.
return (adc_value * 0.488) - 50; // (5000mV/1024) - 50 made up numbers.
}