fork download
  1. /*
  2.  * EA5 - Λειτουργία Έξυπνου Θερμοκηπίου
  3.  * ATmega4808 (AVR-IoT Wx Board)
  4.  *
  5.  * ΧΟΥΣΕΙΝ ΑΜΕΤ - ΑΜ: 1080477
  6.  * ΓΙΑΝΝΗΣ ΜΑΡΓΕΤΗΣ - ΑΜ: 1084521
  7.  *
  8.  * Ερώτημα 1: ADC (free-running, Window Comparator) με 2 κατώφλια.
  9.  * Αν result < WINLT → LED0 ON (χαμηλή υγρασία, πότισμα).
  10.  * Αν result > WINHT → LED1 ON (υψηλή υγρασία, αερισμός).
  11.  * Ερώτημα 2: SW5 → Timer ποτίσματος (διάρκεια = WINLT - adc_result).
  12.  * SW6 → PWM αερισμού (T=1ms, D=50%, 4 rising edges).
  13.  * Ερώτημα 3: Λάθος διακόπτης → Όλα τα LEDs ON (βηματική απενεργοποίηση).
  14.  */
  15.  
  16. #include <avr/io.h>
  17. #include <avr/interrupt.h>
  18.  
  19. /* --- Κατώφλια υγρασίας --- */
  20. #define WINLT 300 /* κάτω από αυτό: πότισμα */
  21. #define WINHT 700 /* πάνω από αυτό: αερισμός */
  22.  
  23. /* --- PWM: T=1ms, D=50%, prescaler=1024, fsys=20MHz
  24.  * f_timer = 20MHz/1024 ≈ 19531 Hz
  25.  * PER = (19531/1000) - 1 ≈ 18
  26.  * CMP0 = PER/2 = 9 (50% duty cycle) */
  27. #define PWM_PER 18
  28. #define PWM_CMP 9
  29.  
  30. /* --- Bit masks LEDs (PORTD, active-low) --- */
  31. #define LED0 PIN0_bm
  32. #define LED1 PIN1_bm
  33. #define LED2 PIN2_bm
  34.  
  35. /* --- Global flags --- */
  36. volatile uint16_t adc_result = 0; /* τελευταία τιμή ADC */
  37. volatile uint8_t adc_flag = 0; /* 1 = ADC interrupt ενεργοποιήθηκε */
  38. volatile uint8_t timer_done = 0; /* 1 = timer ποτίσματος τελείωσε */
  39. volatile uint8_t pwm_edges = 0; /* μετρητής rising edges PWM */
  40. volatile uint8_t pwm_mode = 0; /* 1 = TCA σε PWM mode, 0 = timer mode */
  41.  
  42. /* ===== Αρχικοποίηση ADC (Ερώτημα 1) ===== */
  43. void init_ADC(void) {
  44. ADC0.CTRLA = ADC_RESSEL_10BIT_gc | ADC_FREERUN_bm; /* 10-bit, free-running */
  45. ADC0.MUXPOS = ADC_MUXPOS_AIN7_gc; /* είσοδος από PORTD PIN7 */
  46. ADC0.DBGCTRL = ADC_DBGRUN_bm; /* τρέχει και σε debug */
  47.  
  48. ADC0.WINLT = WINLT; /* κατώτερο κατώφλι */
  49. ADC0.WINHT = WINHT; /* ανώτερο κατώφλι */
  50. /* interrupt όταν η τιμή είναι εκτός του παραθύρου [WINLT, WINHT] */
  51. ADC0.CTRLE = ADC_WINCM_OUTSIDE_gc;
  52. ADC0.INTCTRL = ADC_WCMP_bm; /* ενεργοποίηση Window Comparator interrupt */
  53.  
  54. ADC0.CTRLA |= ADC_ENABLE_bm; /* ενεργοποίηση ADC */
  55. ADC0.COMMAND = ADC_STCONV_bm; /* εκκίνηση μετατροπής */
  56. }
  57.  
  58. /* ===== Εκκίνηση Timer για πότισμα (Ερώτημα 2α) ===== */
  59. void start_timer(uint16_t duration) {
  60. pwm_mode = 0; /* timer mode */
  61. TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση */
  62. TCA0.SINGLE.CTRLB = 0; /* Normal mode */
  63. TCA0.SINGLE.CNT = 0; /* μηδένισμα */
  64. TCA0.SINGLE.CMP0 = duration; /* διάρκεια ποτίσματος */
  65. TCA0.SINGLE.INTCTRL = TCA_SINGLE_CMP0_bm; /* interrupt στο CMP0 */
  66. TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc
  67. | TCA_SINGLE_ENABLE_bm; /* prescaler=1024, εκκίνηση */
  68. }
  69.  
  70. /* ===== Εκκίνηση PWM για αερισμό (Ερώτημα 2β) ===== */
  71. void start_PWM(void) {
  72. pwm_mode = 1; /* PWM mode */
  73. pwm_edges = 0; /* μηδένισμα ακμών */
  74. TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση */
  75. TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc; /* Single-Slope PWM */
  76. TCA0.SINGLE.CNT = 0;
  77. TCA0.SINGLE.PER = PWM_PER; /* περίοδος T=1ms */
  78. TCA0.SINGLE.CMP0 = PWM_CMP; /* duty cycle 50% */
  79. /* OVF = rising edge, CMP0 = falling edge */
  80. TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm | TCA_SINGLE_CMP0_bm;
  81. TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc
  82. | TCA_SINGLE_ENABLE_bm;
  83. }
  84.  
  85. /* ===== MAIN ===== */
  86. int main(void) {
  87. /* LED0, LED1, LED2 ως έξοδοι — αρχικά OFF (active-low: OUT=1 → off) */
  88. PORTD.DIR |= LED0 | LED1 | LED2;
  89. PORTD.OUT |= LED0 | LED1 | LED2;
  90.  
  91. /* SW5 (PIN5) και SW6 (PIN6) του PORTF: pull-up + interrupt στο falling edge */
  92. PORTF.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
  93. PORTF.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
  94.  
  95. init_ADC(); /* Ερώτημα 1: εκκίνηση ADC */
  96. sei();
  97.  
  98. while (1) {
  99. /* Ερώτημα 2α: timer ποτίσματος τέλειωσε */
  100. if (timer_done) {
  101. timer_done = 0;
  102. PORTD.OUT |= LED0; /* LED0 off */
  103. ADC0.COMMAND = ADC_STCONV_bm; /* επανεκκίνηση ADC */
  104. }
  105.  
  106. /* Ερώτημα 2β: 4 rising edges PWM → σταμάτα αερισμό */
  107. if (pwm_edges >= 4) {
  108. TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση PWM */
  109. pwm_edges = 0;
  110. pwm_mode = 0;
  111. PORTD.OUT |= LED1 | LED2; /* LED1 και LED2 off */
  112. ADC0.COMMAND = ADC_STCONV_bm; /* επανεκκίνηση ADC */
  113. }
  114. }
  115. }
  116.  
  117. /* ===== ISR: ADC Window Comparator (Ερώτημα 1) ===== */
  118. ISR(ADC0_WCOMP_vect) {
  119. cli();
  120. int flags = ADC0.INTFLAGS;
  121. ADC0.INTFLAGS = flags; /* καθαρισμός interrupt flag */
  122.  
  123. adc_result = ADC0.RES; /* αποθήκευση τιμής ADC */
  124.  
  125. if (adc_result < WINLT) {
  126. PORTD.OUTCLR = LED0; /* LED0 ON: χαμηλή υγρασία */
  127. } else {
  128. PORTD.OUTCLR = LED1; /* LED1 ON: υψηλή υγρασία */
  129. }
  130. sei();
  131. }
  132.  
  133. /* ===== ISR: PORTF — SW5 και SW6 (Ερωτήματα 2 και 3) ===== */
  134. ISR(PORTF_PORT_vect) {
  135. cli();
  136. uint8_t flags = PORTF.INTFLAGS;
  137. PORTF.INTFLAGS = flags; /* καθαρισμός interrupt flag (bit masking) */
  138.  
  139. /* SW5: σύστημα ποτίσματος */
  140. if (flags & PIN5_bm) {
  141. if (!(PORTD.OUT & LED0)) { /* LED0 αναμμένο → σωστός διακόπτης */
  142. start_timer(WINLT - adc_result);
  143. } else { /* Ερώτημα 3: λάθος διακόπτης */
  144. PORTD.OUTCLR = LED0 | LED1 | LED2;
  145. }
  146. }
  147.  
  148. /* SW6: σύστημα αερισμού */
  149. if (flags & PIN6_bm) {
  150. if (!(PORTD.OUT & LED1)) { /* LED1 αναμμένο → σωστός διακόπτης */
  151. PORTD.OUTCLR = LED2; /* LED2 ON για αερισμό */
  152. start_PWM();
  153. } else { /* Ερώτημα 3: λάθος διακόπτης */
  154. PORTD.OUTCLR = LED0 | LED1 | LED2;
  155. }
  156. }
  157. sei();
  158. }
  159.  
  160. /* ===== ISR: TCA0 OVF — rising edge PWM (Ερώτημα 2β) ===== */
  161. ISR(TCA0_OVF_vect) {
  162. cli();
  163. int flags = TCA0.SINGLE.INTFLAGS;
  164. TCA0.SINGLE.INTFLAGS = flags; /* καθαρισμός interrupt flag */
  165. if (pwm_mode) {
  166. PORTD.OUTCLR = LED2; /* LED2 ON στο rising edge */
  167. pwm_edges++; /* μέτρηση rising edges */
  168. }
  169. sei();
  170. }
  171.  
  172. /* ===== ISR: TCA0 CMP0 — falling edge PWM ή τέλος timer ===== */
  173. ISR(TCA0_CMP0_vect) {
  174. cli();
  175. int flags = TCA0.SINGLE.INTFLAGS;
  176. TCA0.SINGLE.INTFLAGS = flags; /* καθαρισμός interrupt flag */
  177.  
  178. if (pwm_mode) {
  179. PORTD.OUT |= LED2; /* LED2 OFF στο falling edge */
  180. } else {
  181. TCA0.SINGLE.CTRLA = 0; /* απενεργοποίηση timer */
  182. timer_done = 1; /* σήμα στο main */
  183. }
  184. sei();
  185. }
  186.  
Success #stdin #stdout 0.02s 25656KB
stdin
Standard input is empty
stdout
/*
 * 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();
}