diff options
author | Santo Cariotti <santo@dcariotti.me> | 2023-01-07 18:51:31 +0100 |
---|---|---|
committer | Santo Cariotti <santo@dcariotti.me> | 2023-01-07 18:51:31 +0100 |
commit | aa0ee3d92b13c70eb749188eb549f9025250defa (patch) | |
tree | e869f1a496d41dc2aabcd5d91143dabfbf36be8e /Year_3 | |
parent | 9240342b366db9999f11659a1f1c396ba418ad78 (diff) |
Add exam for lsm
Diffstat (limited to 'Year_3')
-rw-r--r-- | Year_3/LSM/exam.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/Year_3/LSM/exam.c b/Year_3/LSM/exam.c new file mode 100644 index 0000000..fca2061 --- /dev/null +++ b/Year_3/LSM/exam.c @@ -0,0 +1,272 @@ +#include "stm32_unict_lib.h" +#include <ctype.h> /* For isdigit() */ +#include <stdio.h> +#include <stdlib.h> /* For atoi() */ +#include <string.h> + +typedef int electr_users_t; + +typedef enum { + IDLE, /* Init state */ + CONSUME_ALL, /* Press X */ + CONSUME_PER_SECOND, /* Press Y */ + CONFIG, /* Press T */ +} status_t; + +electr_users_t electr_user[2]; +status_t status = IDLE; +short switch_on = 0; /* Press Z */ +int consumption = 0; +float consumption_per_second = 0.0; +int threshold = 3000; /* Start value */ +short counter_over_threshold = 0; +short alarm_on = 0; + +float +calculate_consume_per_second() +{ + /* E = P * t + * where E is kW/h, P is kW and t is hours + * `energy_hours` is kWh + */ + float energy_hours = ((electr_user[0] + electr_user[1]) / 1000.0) * ((1 / 60.0) / 60.0); + + return energy_hours * 3600; +} + +int +get_new_threshold() +{ + char string[4]; + char ch; + int i; + int error; + int num; + + memset(string, 0, 4); + + do { + printf("\nAdd a threshold in [0, 3000]: "); + fflush(stdout); + + error = 0; + for (i = 0; i < 4; ++i) { + ch = readchar(); + + if (ch == 13) { + if (i == 0) { + error = 1; + } else { + string[i] = '\0'; + } + + break; + } else if (!isdigit(ch)) { + error = 1; + break; + } + + __io_putchar(ch); + string[i] = ch; + } + + if (error) { + printf("\nEnter a number."); + num = 3001; + } else { + /* `num` can't be < 0 because '-' is not a valid character */ + num = atoi(string); + } + } while (num > 3000); + + return num; +} + +void +init() +{ + DISPLAY_init(); + + GPIO_init(GPIOB); + GPIO_init(GPIOC); + + GPIO_config_input(GPIOB, 10); + GPIO_config_EXTI(GPIOB, EXTI10); + EXTI_enable(EXTI10, FALLING_EDGE); + + GPIO_config_input(GPIOB, 4); + GPIO_config_EXTI(GPIOB, EXTI4); + EXTI_enable(EXTI4, FALLING_EDGE); + + GPIO_config_input(GPIOB, 5); + GPIO_config_EXTI(GPIOB, EXTI5); + EXTI_enable(EXTI5, FALLING_EDGE); + + GPIO_config_input(GPIOB, 6); + GPIO_config_EXTI(GPIOB, EXTI6); + EXTI_enable(EXTI6, FALLING_EDGE); + + GPIO_config_output(GPIOB, 0); + GPIO_config_output(GPIOC, 3); + + TIM_init(TIM2); + TIM_set(TIM2, 0); + /* TIM2 is 32-bits */ + /* (42000/84e3) * 2000 = 1000 ms */ + TIM_config_timebase(TIM2, 42000, 2000); + TIM_enable_irq(TIM2, IRQ_UPDATE); + TIM_on(TIM2); + + ADC_init(ADC1, ADC_RES_8, ADC_ALIGN_RIGHT); + ADC_channel_config(ADC1, GPIOC, 0, 10); + ADC_channel_config(ADC1, GPIOC, 1, 11); + ADC_on(ADC1); + + CONSOLE_init(); +} + +int +main() +{ + int adc_read; + char s[5]; + + init(); + + for (;;) { + ADC_sample_channel(ADC1, 11); + ADC_start(ADC1); + while (!ADC_completed(ADC1)) + ; + adc_read = ADC_read(ADC1); + electr_user[0] = (adc_read * 500 / 255); + + ADC_sample_channel(ADC1, 10); + ADC_start(ADC1); + while (!ADC_completed(ADC1)) + ; + adc_read = ADC_read(ADC1); + electr_user[1] = (adc_read * 1000 / 255); + + switch (status) { + case CONSUME_ALL: + /* Handle the case if the integer value is greater + * than the maximum length of the screen. + * In that case use KWatt + */ + + if (consumption <= 9999) { + sprintf(s, "%4d", consumption); + } else { + sprintf(s, "%4f", consumption / 1000.0); + } + break; + case CONSUME_PER_SECOND: + sprintf(s, "%4f", consumption_per_second); + break; + case CONFIG: + threshold = get_new_threshold(); + status = IDLE; + counter_over_threshold = 0; + break; + default: + memset(s, ' ', 4); + } + + DISPLAY_puts(0, s); + } + + return 0; +} + +void +EXTI15_10_IRQHandler(void) +{ + if (EXTI_isset(EXTI10)) { + /* X */ + + if (status != CONFIG) { + status = CONSUME_ALL; + } + + EXTI_clear(EXTI10); + } +} + +void +EXTI9_5_IRQHandler(void) +{ + if (EXTI_isset(EXTI6)) { + /* T */ + + status = CONFIG; + + EXTI_clear(EXTI6); + } + + if (EXTI_isset(EXTI5)) { + /* Z */ + + if (status != CONFIG) { + switch_on = !switch_on; + + /* GPIO_toggle() does not assure 1 for ON and 0 for OFF */ + if (switch_on) { + alarm_on = 0; + counter_over_threshold = 0; + GPIO_write(GPIOB, 0, 0); /* Turn off red led */ + GPIO_write(GPIOC, 3, 1); + } else { + status = IDLE; + GPIO_write(GPIOC, 3, 0); + } + + consumption = 0; + consumption_per_second = 0; + } + + EXTI_clear(EXTI5); + } +} + +void +EXTI4_IRQHandler(void) +{ + if (EXTI_isset(EXTI4)) { + /* Y */ + + if (status != CONFIG) { + status = CONSUME_PER_SECOND; + } + + EXTI_clear(EXTI4); + } +} + +void +TIM2_IRQHandler(void) +{ + if (TIM_update_check(TIM2)) { + if (!alarm_on && status != CONFIG) { + if (switch_on) { + int current_watts = (electr_user[0] + electr_user[1]); + consumption += current_watts; + + if (current_watts > threshold) { + counter_over_threshold++; + + if (counter_over_threshold > 10) { + alarm_on = 1; + GPIO_write(GPIOB, 0, 1); /* Turn on red led */ + GPIO_write(GPIOC, 3, 0); /* Turn off green led */ + switch_on = 0; + } + } + + consumption_per_second = calculate_consume_per_second(); + } + } + + TIM_update_clear(TIM2); + } +} |