/*
Arduino code for controlling a servo motor based on temperature readings from a sensor,
with temperature displayed on a 16x2 LCD screen and the option to switch between Celsius and Fahrenheit.
Libraries used:
- LiquidCrystal_I2C.h: Library for driving LiquidCrystal displays (with I2C adapter).
- Servo.h: Library for controlling servo motors.
- Button.h: Library for handling button input.
Hardware setup:
- Connect a temperature sensor to analog pin A0.
- Connect a servo motor to digital pin 3.
- Connect a button to digital pin 2.
- Connect an LED to digital pin 4.
Setup:
- Initializes pins, LCD, servo, button, and LED.
Loop:
- Reads temperature, converts it based on the temperature units mode, and adjusts servo angle.
- Prints the temperature on the LCD screen.
*/
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <Button.h>
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
Servo servo;
const byte servoPin = 3;
const byte tempSensor = A0;
const float BETA = 3950;
Button metricsBtn(2);
bool celsiusMode = true;
const byte metricsLed = 4;
/**
@brief Reads temperature from the sensor and calculates it in Celsius.
@return Temperature in Celsius.
*/
float getTemp() {
int analogValue = analogRead(tempSensor);
return 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
}
/**
@brief Converts temperature from Celsius to Fahrenheit.
@param celsius Temperature in Celsius.
@return Temperature in Fahrenheit.
*/
float celsiusToFahreheit(float celsius) {
return celsius * 9 / 5 + 32;
}
/**
@brief Maps Celsius temperature to servo angle.
@param celsius Temperature in Celsius.
@return Servo angle.
*/
float celsiusToServoAngle(int celsius) {
return map(celsius, -24, 80, 0, 180);
}
/**
@brief Maps Fahrenheit temperature to servo angle.
@param fahrenheit Temperature in Fahrenheit.
@return Servo angle.
*/
float fahrenheitToServoAngle(int fahrenheit) {
return map(fahrenheit, -11, 176, 0, 180);
}
/**
@brief Initializes the LCD and prints the initial message.
*/
void lcdInit() {
lcd.print("Temperature: ");
}
/**
@brief Prints the temperature on the LCD screen.
@param temp Temperature value.
@param maxLen Maximum length of the displayed string.
*/
void printTemp(float temp, int maxLen = 8) {
char tempStr[maxLen - 2]; // -2 to leave space for " C"
dtostrf(temp, maxLen - 2, 2, tempStr); // Convert float to string
String metrics = celsiusMode ? " C" : " F";
String str = String(tempStr) + metrics; // Convert char array to String and concatenate
int len = str.length();
// Pad with spaces if needed
for (int i = len; i < maxLen; i++) {
str += " ";
}
lcd.setCursor(0, 1);
lcd.print(str);
}
/**
@brief Controls the LED indicator based on temperature units mode.
*/
void metricsLedSwitch() {
if (celsiusMode) {
digitalWrite(metricsLed, HIGH);
}
else {
digitalWrite(metricsLed, LOW);
}
}
/**
@brief Handles button press to toggle temperature units mode.
*/
void handleMetricsBtn() {
if(metricsBtn.pressed()) {
celsiusMode = !celsiusMode;
}
}
void setup() {
// Serial.begin(9600);
pinMode(tempSensor, INPUT);
servo.attach(servoPin);
metricsBtn.begin();
pinMode(metricsLed, OUTPUT);
lcd.init();
lcd.backlight();
lcdInit();
}
void loop() {
int angle = 0;
float temp = 0;
handleMetricsBtn();
metricsLedSwitch();
float celsius = getTemp();
if (celsiusMode) {
angle = celsiusToServoAngle(celsius);
temp = celsius;
}
else {
float fahrenheit = celsiusToFahreheit(celsius);
angle = fahrenheitToServoAngle(fahrenheit);
temp = fahrenheit;
}
servo.write(angle);
printTemp(temp);
}