/* * EA5 - Λειτουργία Έξυπνου Θερμοκηπίου * ATmega4808 (AVR-IoT Wx Board) * * ΧΟΥΣΕΙΝ ΑΜΕΤ - ΑΜ: 1080477 * ΓΙΑΝΝΗΣ ΜΑΡΓΕΤΗΣ - ΑΜ: 1084521 * * Ερώτημα 1: ADC (free-running, Window Comparator) με 2 κατώφλια. * Αν result < WINLT → LED0 ON (χαμηλή υγρασία, πότισμα). * Αν result > WINHT → LED1 ON (υψηλή υγρασία, αερισμός). * Ερώτημα 2: SW5 → Timer ποτίσματος (διάρκεια = WINLT - adc_result). * SW6 → PWM αερισμού (T=1ms, D=50%, 4 rising edges). * Ερώτημα 3: Λάθος διακόπτης → Όλα τα LEDs ON (βηματική απενεργοποίηση). */ #include <avr/io.h> #include <avr/interrupt.h> /* --- Κατώφλια υγρασίας --- */ #define WINLT 300 /* κάτω από αυτό: πότισμα */ #define WINHT 700 /* πάνω από αυτό: αερισμός */ /* --- PWM: T=1ms, D=50%, prescaler=1024, fsys=20MHz * f_timer = 20MHz/1024 ≈ 19531 Hz * PER = (19531/1000) - 1 ≈ 18 * CMP0 = PER/2 = 9 (50% duty cycle) */ #define PWM_PER 18 #define PWM_CMP 9 /* --- Bit masks LEDs (PORTD, active-low) --- */ #define LED0 PIN0_bm #define LED1 PIN1_bm #define LED2 PIN2_bm /* --- Global flags --- */ volatile uint16_t adc_result = 0; /* τελευταία τιμή ADC */ volatile uint8_t adc_flag = 0; /* 1 = ADC interrupt ενεργοποιήθηκε */ volatile uint8_t timer_done = 0; /* 1 = timer ποτίσματος τελείωσε */ volatile uint8_t pwm_edges = 0; /* μετρητής rising edges PWM */ volatile uint8_t pwm_mode = 0; /* 1 = TCA σε PWM mode, 0 = timer mode */ /* ===== Αρχικοποίηση ADC (Ερώτημα 1) ===== */ void init_ADC(void) { ADC0.CTRLA = ADC_RESSEL_10BIT_gc | ADC_FREERUN_bm; /* 10-bit, free-running */ ADC0.MUXPOS = ADC_MUXPOS_AIN7_gc; /* είσοδος από PORTD PIN7 */ ADC0.DBGCTRL = ADC_DBGRUN_bm; /* τρέχει και σε debug */ ADC0.WINLT = WINLT; /* κατώτερο κατώφλι */ ADC0.WINHT = WINHT; /* ανώτερο κατώφλι */ /* interrupt όταν η τιμή είναι εκτός του παραθύρου [WINLT, WINHT] */ ADC0.CTRLE = ADC_WINCM_OUTSIDE_gc; ADC0.INTCTRL = ADC_WCMP_bm; /* ενεργοποίηση Window Comparator interrupt */ ADC0.CTRLA |= ADC_ENABLE_bm; /* ενεργοποίηση ADC */ ADC0.COMMAND = ADC_STCONV_bm; /* εκκίνηση μετατροπής */ } /* ===== Εκκίνηση Timer για πότισμα (Ερώτημα 2α) ===== */ void start_timer(uint16_t duration) { pwm_mode = 0; /* timer mode */ TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση */ TCA0.SINGLE.CTRLB = 0; /* Normal mode */ TCA0.SINGLE.CNT = 0; /* μηδένισμα */ TCA0.SINGLE.CMP0 = duration; /* διάρκεια ποτίσματος */ TCA0.SINGLE.INTCTRL = TCA_SINGLE_CMP0_bm; /* interrupt στο CMP0 */ TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc | TCA_SINGLE_ENABLE_bm; /* prescaler=1024, εκκίνηση */ } /* ===== Εκκίνηση PWM για αερισμό (Ερώτημα 2β) ===== */ void start_PWM(void) { pwm_mode = 1; /* PWM mode */ pwm_edges = 0; /* μηδένισμα ακμών */ TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση */ TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc; /* Single-Slope PWM */ TCA0.SINGLE.CNT = 0; TCA0.SINGLE.PER = PWM_PER; /* περίοδος T=1ms */ TCA0.SINGLE.CMP0 = PWM_CMP; /* duty cycle 50% */ /* OVF = rising edge, CMP0 = falling edge */ TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm | TCA_SINGLE_CMP0_bm; TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc | TCA_SINGLE_ENABLE_bm; } /* ===== MAIN ===== */ int main(void) { /* LED0, LED1, LED2 ως έξοδοι — αρχικά OFF (active-low: OUT=1 → off) */ PORTD.OUT |= LED0 | LED1 | LED2; /* SW5 (PIN5) και SW6 (PIN6) του PORTF: pull-up + interrupt στο falling edge */ PORTF.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc; PORTF.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc; init_ADC(); /* Ερώτημα 1: εκκίνηση ADC */ sei(); while (1) { /* Ερώτημα 2α: timer ποτίσματος τέλειωσε */ if (timer_done) { timer_done = 0; PORTD.OUT |= LED0; /* LED0 off */ ADC0.COMMAND = ADC_STCONV_bm; /* επανεκκίνηση ADC */ } /* Ερώτημα 2β: 4 rising edges PWM → σταμάτα αερισμό */ if (pwm_edges >= 4) { TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση PWM */ pwm_edges = 0; pwm_mode = 0; PORTD.OUT |= LED1 | LED2; /* LED1 και LED2 off */ ADC0.COMMAND = ADC_STCONV_bm; /* επανεκκίνηση ADC */ } } } /* ===== ISR: ADC Window Comparator (Ερώτημα 1) ===== */ ISR(ADC0_WCOMP_vect) { cli(); int flags = ADC0.INTFLAGS; ADC0.INTFLAGS = flags; /* καθαρισμός interrupt flag */ adc_result = ADC0.RES; /* αποθήκευση τιμής ADC */ if (adc_result < WINLT) { PORTD.OUTCLR = LED0; /* LED0 ON: χαμηλή υγρασία */ } else { PORTD.OUTCLR = LED1; /* LED1 ON: υψηλή υγρασία */ } sei(); } /* ===== ISR: PORTF — SW5 και SW6 (Ερωτήματα 2 και 3) ===== */ ISR(PORTF_PORT_vect) { cli(); uint8_t flags = PORTF.INTFLAGS; PORTF.INTFLAGS = flags; /* καθαρισμός interrupt flag (bit masking) */ /* SW5: σύστημα ποτίσματος */ if (flags & PIN5_bm) { if (!(PORTD.OUT & LED0)) { /* LED0 αναμμένο → σωστός διακόπτης */ start_timer(WINLT - adc_result); } else { /* Ερώτημα 3: λάθος διακόπτης */ PORTD.OUTCLR = LED0 | LED1 | LED2; } } /* SW6: σύστημα αερισμού */ if (flags & PIN6_bm) { if (!(PORTD.OUT & LED1)) { /* LED1 αναμμένο → σωστός διακόπτης */ PORTD.OUTCLR = LED2; /* LED2 ON για αερισμό */ start_PWM(); } else { /* Ερώτημα 3: λάθος διακόπτης */ PORTD.OUTCLR = LED0 | LED1 | LED2; } } sei(); } /* ===== ISR: TCA0 OVF — rising edge PWM (Ερώτημα 2β) ===== */ ISR(TCA0_OVF_vect) { cli(); int flags = TCA0.SINGLE.INTFLAGS; TCA0.SINGLE.INTFLAGS = flags; /* καθαρισμός interrupt flag */ if (pwm_mode) { PORTD.OUTCLR = LED2; /* LED2 ON στο rising edge */ pwm_edges++; /* μέτρηση rising edges */ } sei(); } /* ===== ISR: TCA0 CMP0 — falling edge PWM ή τέλος timer ===== */ ISR(TCA0_CMP0_vect) { cli(); int flags = TCA0.SINGLE.INTFLAGS; TCA0.SINGLE.INTFLAGS = flags; /* καθαρισμός interrupt flag */ if (pwm_mode) { PORTD.OUT |= LED2; /* LED2 OFF στο falling edge */ } else { TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση timer */ timer_done = 1; /* σήμα στο main */ } sei(); }
Standard input is empty
/*
* EA5 - Λειτουργία Έξυπνου Θερμοκηπίου
* ATmega4808 (AVR-IoT Wx Board)
*
* ΧΟΥΣΕΙΝ ΑΜΕΤ - ΑΜ: 1080477
* ΓΙΑΝΝΗΣ ΜΑΡΓΕΤΗΣ - ΑΜ: 1084521
*
* Ερώτημα 1: ADC (free-running, Window Comparator) με 2 κατώφλια.
* Αν result < WINLT → LED0 ON (χαμηλή υγρασία, πότισμα).
* Αν result > WINHT → LED1 ON (υψηλή υγρασία, αερισμός).
* Ερώτημα 2: SW5 → Timer ποτίσματος (διάρκεια = WINLT - adc_result).
* SW6 → PWM αερισμού (T=1ms, D=50%, 4 rising edges).
* Ερώτημα 3: Λάθος διακόπτης → Όλα τα LEDs ON (βηματική απενεργοποίηση).
*/
#include <avr/io.h>
#include <avr/interrupt.h>
/* --- Κατώφλια υγρασίας --- */
#define WINLT 300 /* κάτω από αυτό: πότισμα */
#define WINHT 700 /* πάνω από αυτό: αερισμός */
/* --- PWM: T=1ms, D=50%, prescaler=1024, fsys=20MHz
* f_timer = 20MHz/1024 ≈ 19531 Hz
* PER = (19531/1000) - 1 ≈ 18
* CMP0 = PER/2 = 9 (50% duty cycle) */
#define PWM_PER 18
#define PWM_CMP 9
/* --- Bit masks LEDs (PORTD, active-low) --- */
#define LED0 PIN0_bm
#define LED1 PIN1_bm
#define LED2 PIN2_bm
/* --- Global flags --- */
volatile uint16_t adc_result = 0; /* τελευταία τιμή ADC */
volatile uint8_t adc_flag = 0; /* 1 = ADC interrupt ενεργοποιήθηκε */
volatile uint8_t timer_done = 0; /* 1 = timer ποτίσματος τελείωσε */
volatile uint8_t pwm_edges = 0; /* μετρητής rising edges PWM */
volatile uint8_t pwm_mode = 0; /* 1 = TCA σε PWM mode, 0 = timer mode */
/* ===== Αρχικοποίηση ADC (Ερώτημα 1) ===== */
void init_ADC(void) {
ADC0.CTRLA = ADC_RESSEL_10BIT_gc | ADC_FREERUN_bm; /* 10-bit, free-running */
ADC0.MUXPOS = ADC_MUXPOS_AIN7_gc; /* είσοδος από PORTD PIN7 */
ADC0.DBGCTRL = ADC_DBGRUN_bm; /* τρέχει και σε debug */
ADC0.WINLT = WINLT; /* κατώτερο κατώφλι */
ADC0.WINHT = WINHT; /* ανώτερο κατώφλι */
/* interrupt όταν η τιμή είναι εκτός του παραθύρου [WINLT, WINHT] */
ADC0.CTRLE = ADC_WINCM_OUTSIDE_gc;
ADC0.INTCTRL = ADC_WCMP_bm; /* ενεργοποίηση Window Comparator interrupt */
ADC0.CTRLA |= ADC_ENABLE_bm; /* ενεργοποίηση ADC */
ADC0.COMMAND = ADC_STCONV_bm; /* εκκίνηση μετατροπής */
}
/* ===== Εκκίνηση Timer για πότισμα (Ερώτημα 2α) ===== */
void start_timer(uint16_t duration) {
pwm_mode = 0; /* timer mode */
TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση */
TCA0.SINGLE.CTRLB = 0; /* Normal mode */
TCA0.SINGLE.CNT = 0; /* μηδένισμα */
TCA0.SINGLE.CMP0 = duration; /* διάρκεια ποτίσματος */
TCA0.SINGLE.INTCTRL = TCA_SINGLE_CMP0_bm; /* interrupt στο CMP0 */
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc
| TCA_SINGLE_ENABLE_bm; /* prescaler=1024, εκκίνηση */
}
/* ===== Εκκίνηση PWM για αερισμό (Ερώτημα 2β) ===== */
void start_PWM(void) {
pwm_mode = 1; /* PWM mode */
pwm_edges = 0; /* μηδένισμα ακμών */
TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση */
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc; /* Single-Slope PWM */
TCA0.SINGLE.CNT = 0;
TCA0.SINGLE.PER = PWM_PER; /* περίοδος T=1ms */
TCA0.SINGLE.CMP0 = PWM_CMP; /* duty cycle 50% */
/* OVF = rising edge, CMP0 = falling edge */
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm | TCA_SINGLE_CMP0_bm;
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc
| TCA_SINGLE_ENABLE_bm;
}
/* ===== MAIN ===== */
int main(void) {
/* LED0, LED1, LED2 ως έξοδοι — αρχικά OFF (active-low: OUT=1 → off) */
PORTD.DIR |= LED0 | LED1 | LED2;
PORTD.OUT |= LED0 | LED1 | LED2;
/* SW5 (PIN5) και SW6 (PIN6) του PORTF: pull-up + interrupt στο falling edge */
PORTF.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTF.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
init_ADC(); /* Ερώτημα 1: εκκίνηση ADC */
sei();
while (1) {
/* Ερώτημα 2α: timer ποτίσματος τέλειωσε */
if (timer_done) {
timer_done = 0;
PORTD.OUT |= LED0; /* LED0 off */
ADC0.COMMAND = ADC_STCONV_bm; /* επανεκκίνηση ADC */
}
/* Ερώτημα 2β: 4 rising edges PWM → σταμάτα αερισμό */
if (pwm_edges >= 4) {
TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση PWM */
pwm_edges = 0;
pwm_mode = 0;
PORTD.OUT |= LED1 | LED2; /* LED1 και LED2 off */
ADC0.COMMAND = ADC_STCONV_bm; /* επανεκκίνηση ADC */
}
}
}
/* ===== ISR: ADC Window Comparator (Ερώτημα 1) ===== */
ISR(ADC0_WCOMP_vect) {
cli();
int flags = ADC0.INTFLAGS;
ADC0.INTFLAGS = flags; /* καθαρισμός interrupt flag */
adc_result = ADC0.RES; /* αποθήκευση τιμής ADC */
if (adc_result < WINLT) {
PORTD.OUTCLR = LED0; /* LED0 ON: χαμηλή υγρασία */
} else {
PORTD.OUTCLR = LED1; /* LED1 ON: υψηλή υγρασία */
}
sei();
}
/* ===== ISR: PORTF — SW5 και SW6 (Ερωτήματα 2 και 3) ===== */
ISR(PORTF_PORT_vect) {
cli();
uint8_t flags = PORTF.INTFLAGS;
PORTF.INTFLAGS = flags; /* καθαρισμός interrupt flag (bit masking) */
/* SW5: σύστημα ποτίσματος */
if (flags & PIN5_bm) {
if (!(PORTD.OUT & LED0)) { /* LED0 αναμμένο → σωστός διακόπτης */
start_timer(WINLT - adc_result);
} else { /* Ερώτημα 3: λάθος διακόπτης */
PORTD.OUTCLR = LED0 | LED1 | LED2;
}
}
/* SW6: σύστημα αερισμού */
if (flags & PIN6_bm) {
if (!(PORTD.OUT & LED1)) { /* LED1 αναμμένο → σωστός διακόπτης */
PORTD.OUTCLR = LED2; /* LED2 ON για αερισμό */
start_PWM();
} else { /* Ερώτημα 3: λάθος διακόπτης */
PORTD.OUTCLR = LED0 | LED1 | LED2;
}
}
sei();
}
/* ===== ISR: TCA0 OVF — rising edge PWM (Ερώτημα 2β) ===== */
ISR(TCA0_OVF_vect) {
cli();
int flags = TCA0.SINGLE.INTFLAGS;
TCA0.SINGLE.INTFLAGS = flags; /* καθαρισμός interrupt flag */
if (pwm_mode) {
PORTD.OUTCLR = LED2; /* LED2 ON στο rising edge */
pwm_edges++; /* μέτρηση rising edges */
}
sei();
}
/* ===== ISR: TCA0 CMP0 — falling edge PWM ή τέλος timer ===== */
ISR(TCA0_CMP0_vect) {
cli();
int flags = TCA0.SINGLE.INTFLAGS;
TCA0.SINGLE.INTFLAGS = flags; /* καθαρισμός interrupt flag */
if (pwm_mode) {
PORTD.OUT |= LED2; /* LED2 OFF στο falling edge */
} else {
TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση timer */
timer_done = 1; /* σήμα στο main */
}
sei();
}