#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
// Definizioni delle costanti
#define BETA 3380 // Valore del termistore
#define THRESHOLD_PERCENT 10 // Soglia del 10%
#define FULL_DUTY_CYCLE_PERCENT 50 // Differenza del 50% per duty cycle pieno
// Variabili globali
volatile int temperatura = 0;
volatile int temperatura_desiderata = 0;
volatile int temperatura_di_benessere = 25;
volatile int duty_cycle = 0;
volatile bool ventilatore_attivo = false;
// Funzione per leggere la temperatura dal sensore
void leggiTemperatura() {
int valore_analogico = ADC_read(0); // Leggi dal canale ADC0 (A0)
float celsius = 1.0 / (log(1.0 / (1023.0 / valore_analogico - 1)) / BETA + 1.0 / 298.15) - 273.15;
temperatura = (int)celsius;
}
// Funzione per calcolare il duty cycle del PWM
void calcolaDutyCycle() {
int differenza_temperatura = temperatura - temperatura_desiderata;
if (differenza_temperatura > 0) {
if (differenza_temperatura > temperatura_desiderata * THRESHOLD_PERCENT / 100.0) {
if (differenza_temperatura > temperatura_desiderata * FULL_DUTY_CYCLE_PERCENT / 100.0) {
duty_cycle = 255; // Duty cycle pieno al 100%
} else {
duty_cycle = (differenza_temperatura * 255) / (temperatura_desiderata * FULL_DUTY_CYCLE_PERCENT / 100.0);
}
} else {
duty_cycle = 0; // Duty cycle minimo
}
} else {
duty_cycle = 0; // Duty cycle minimo
}
}
// Funzione per controllare il ventilatore
void controllaVentilatore() {
if (temperatura > temperatura_desiderata) {
if (duty_cycle > 0) {
OCR1A = duty_cycle; // Imposta il duty cycle del PWM
ventilatore_attivo = true;
} else {
OCR1A = 0; // Spegni la ventola
ventilatore_attivo = false;
}
} else {
OCR1A = 0; // Spegni la ventola
ventilatore_attivo = false;
}
}
// Funzione per inizializzare l'ADC
void ADC_init() {
// Configura l'ADC
ADMUX = (1 << REFS0); // Riferimento AVcc
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // Abilita l'ADC e imposta il prescaler a 64
}
// Funzione per leggere un valore dall'ADC
int ADC_read(uint8_t ch) {
ch &= 0b00000111; // Limita il canale a valori validi (0-7)
ADMUX = (ADMUX & 0xF8) | ch; // Seleziona il canale ADC
ADCSRA |= (1 << ADSC); // Avvia la conversione
while (ADCSRA & (1 << ADSC)); // Attendi la fine della conversione
return ADC;
}
// Funzione per inizializzare il PWM
void PWM_init() {
// Configura il PWM su OC1A (Pin 10)
DDRB |= (1 << DDB1); // Imposta il pin OC1A come output
TCCR1A = (1 << COM1A1) | (1 << WGM11); // Clear OC1A on Compare Match, Fast PWM
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); // Fast PWM, Prescaler 8
ICR1 = 255; // Imposta il top del contatore per Fast PWM
}
// Funzione per inizializzare il timer 2
void timer2_init() {
TCCR2A = 0;
TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // Prescaler di 1024
TIMSK2 = (1 << TOIE2); // Abilita l'interrupt di overflow
TCNT2 = 0; // Inizializza il contatore
sei(); // Abilita gli interrupt globali
}
// ISR di overflow del timer 2
ISR(TIMER2_OVF_vect) {
// Aggiornamento di variabili
}
void setup() {
ADC_init(); // Inizializza l'ADC
PWM_init(); // Inizializza il PWM
timer2_init(); // Inizializza il timer 2
// Inizializza LED su pin 10 per indicare lo stato del ventilatore
DDRB |= (1 << PB2); // Imposta il pin 10 come output
PORTB &= ~(1 << PB2); // Assicurati che il LED sia spento inizialmente
}
void loop() {
leggiTemperatura();
// Lettura del potenziometro e mappatura della lettura su un intervallo di temperature desiderate
int valore_potenziometro = ADC_read(1); // Leggi dal canale ADC1 (A1)
temperatura_desiderata = map(valore_potenziometro, 0, 1023, 15, 30); // Mappa su un range 15-30 gradi Celsius
calcolaDutyCycle();
controllaVentilatore();
// Controllo LED: accendi il LED solo se il ventilatore è attivo
if (ventilatore_attivo) {
PORTB |= (1 << PB2); // Accendi il LED su pin 10
} else {
PORTB &= ~(1 << PB2); // Spegni il LED su pin 10
}
}