#include "FreeRTOS.h" #include "task.h" #include "avr/io.h" #include "zh_avr_160x_i2c.h" #include "zh_avr_encoder.h" #include "zh_avr_ac_dimmer.h" #include "ate0003.h" // #define DEBUG #define SYSTEM_SETUP_STACK 173 #define ENCODER_STACK 171 #define PCF8574_STACK 116 const char *component_cmm[] = {component_1_cmm, component_2_cmm, component_3_cmm, component_4_cmm, component_5_cmm}; const char *component_line_1[] = {component_1_line_1, component_2_line_1, component_3_line_1, component_4_line_1, component_5_line_1}; const char *component_line_2[] = {component_1_line_2, component_2_line_2, component_3_line_2, component_4_line_2, component_5_line_2}; const uint8_t component_channel[] = {0x0F, 0x04, 0x02, 0x08, 0x0C}; #ifdef DEBUG #define BAUD_RATE 9600 #define BAUD_PRESCALE (F_CPU / 16 / BAUD_RATE - 1) int usart(char byte, FILE *stream) { while ((UCSR0A & (1 << UDRE0)) == 0) { } UDR0 = byte; return 0; } FILE uart = FDEV_SETUP_STREAM(usart, NULL, _FDEV_SETUP_WRITE); #endif void system_setup_task(void *pvParameters); void component_setup_function(uint8_t component); TaskHandle_t system_setup_task_handle = {0}; zh_avr_pcf8574_handle_t button_handle = {0}; zh_avr_pcf8574_handle_t led1_handle = {0}; zh_avr_pcf8574_handle_t led2_handle = {0}; zh_avr_pcf8574_handle_t relay_handle = {0}; zh_avr_pcf8574_handle_t lcd_handle = {0}; zh_avr_encoder_handle_t power_encoder_handle = {0}; zh_avr_encoder_handle_t component_encoder_handle = {0}; volatile static bool is_work = false; // Work status. volatile static bool is_dmm = false; // DMM using status. volatile static bool is_fix = false; // FIX button status. volatile static uint8_t used_channels = 0; // Permitted channels. Depends of the selected component. volatile static bool is_initialized = false; // Normal loading status. volatile static bool is_num1_fixed = false; // NUM 1 button FIX status. volatile static bool is_num2_fixed = false; // NUM 2 button FIX status. volatile static bool is_num3_fixed = false; // NUM 3 button FIX status. volatile static bool is_num4_fixed = false; // NUM 4 button FIX status. int main(void) { #ifdef DEBUG UBRR0H = (BAUD_PRESCALE >> 8); UBRR0L = BAUD_PRESCALE; UCSR0B = (1 << RXEN0) | (1 << TXEN0); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); stdout = &uart; #endif xTaskCreate(system_setup_task, "system_setup", SYSTEM_SETUP_STACK, NULL, tskIDLE_PRIORITY, &system_setup_task_handle); vTaskStartScheduler(); return 0; } void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { #ifdef DEBUG printf("Task %s Remaining Stack Size %d.\n", pcTaskName, uxTaskGetStackHighWaterMark(xTask)); printf("Free Heap %d.\n", xPortGetFreeHeapSize()); #endif } void system_setup_task(void *pvParameters) { char text_buffer[LCD_TEXT_BUFFER]; zh_avr_i2c_master_init(false); zh_avr_pcf8574_init_config_t pcf8574_init_config = ZH_AVR_PCF8574_INIT_CONFIG_DEFAULT(); pcf8574_init_config.stack_size = PCF8574_STACK; //** LED 1 extender init. **/ pcf8574_init_config.i2c_address = LED1_I2C_ADDRESS; zh_avr_pcf8574_init(&pcf8574_init_config, &led1_handle); zh_avr_pcf8574_write(&led1_handle, 0xFF); //** LED 2 extender init. **/ pcf8574_init_config.i2c_address = LED2_I2C_ADDRESS; zh_avr_pcf8574_init(&pcf8574_init_config, &led2_handle); zh_avr_pcf8574_write(&led2_handle, 0xFF); //** RELAY extender init. **/ pcf8574_init_config.i2c_address = RELAY_I2C_ADDRESS; zh_avr_pcf8574_init(&pcf8574_init_config, &relay_handle); zh_avr_pcf8574_write(&relay_handle, 0x00); //** LCD init. **/ pcf8574_init_config.i2c_address = LCD_I2C_ADDRESS; zh_avr_pcf8574_init(&pcf8574_init_config, &lcd_handle); zh_avr_160x_init(&lcd_handle, ZH_LCD_16X4); //** BUTTON extender init. **/ pcf8574_init_config.p0_gpio_work_mode = true; pcf8574_init_config.p1_gpio_work_mode = true; pcf8574_init_config.p2_gpio_work_mode = true; pcf8574_init_config.p3_gpio_work_mode = true; pcf8574_init_config.p4_gpio_work_mode = true; pcf8574_init_config.p5_gpio_work_mode = true; pcf8574_init_config.interrupt_port = AVR_PORTD; pcf8574_init_config.interrupt_gpio = PORTD2; pcf8574_init_config.i2c_address = BUTTON_I2C_ADDRESS; zh_avr_pcf8574_init(&pcf8574_init_config, &button_handle); //** Loading. Just for fun. **/ zh_avr_160x_set_cursor(&lcd_handle, 0, 0); strcpy_P(text_buffer, text_company); zh_avr_160x_print_char(&lcd_handle, text_buffer); zh_avr_160x_set_cursor(&lcd_handle, 1, 0); strcpy_P(text_buffer, text_model); zh_avr_160x_print_char(&lcd_handle, text_buffer); zh_avr_160x_set_cursor(&lcd_handle, 2, 0); strcpy_P(text_buffer, text_firmware); zh_avr_160x_print_char(&lcd_handle, text_buffer); for (uint8_t i = 0; i <= 100; i += 10) { zh_avr_160x_print_progress_bar(&lcd_handle, 3, i); vTaskDelay(100 / portTICK_PERIOD_MS); } //** LCD default text print. **/ zh_avr_160x_lcd_clear(&lcd_handle); zh_avr_160x_set_cursor(&lcd_handle, 0, 0); strcpy_P(text_buffer, text_ac_power); zh_avr_160x_print_char(&lcd_handle, text_buffer); zh_avr_160x_set_cursor(&lcd_handle, 0, 11); zh_avr_160x_print_int(&lcd_handle, 100); zh_avr_160x_print_char(&lcd_handle, "%"); zh_avr_160x_set_cursor(&lcd_handle, 1, 0); strcpy_P(text_buffer, text_component); zh_avr_160x_print_char(&lcd_handle, text_buffer); //**"ANY" component setup after loading. **/ zh_avr_pcf8574_write_gpio(&led1_handle, DMM_LED_RED, LED_ON); zh_avr_pcf8574_write_gpio(&led1_handle, FIX_LED_BLUE, LED_ON); zh_avr_pcf8574_write_gpio(&relay_handle, DMM_RELAY, RELAY_ON); component_setup_function(0); //** Encoders init **/ zh_avr_encoder_init_config_t encoder_init_config = ZH_AVR_ENCODER_INIT_CONFIG_DEFAULT(); encoder_init_config.stack_size = ENCODER_STACK; encoder_init_config.queue_size = 5; encoder_init_config.gpio_port = AVR_PORTC; encoder_init_config.a_gpio_number = PORTC0; encoder_init_config.b_gpio_number = PORTC1; encoder_init_config.encoder_min_value = 0; encoder_init_config.encoder_max_value = 100; encoder_init_config.encoder_step = 1; encoder_init_config.encoder_number = POWER_ENCODER; zh_avr_encoder_init(&encoder_init_config, &power_encoder_handle); zh_avr_encoder_set(&power_encoder_handle, 100); encoder_init_config.a_gpio_number = PORTC2; encoder_init_config.b_gpio_number = PORTC3; encoder_init_config.encoder_min_value = 0; encoder_init_config.encoder_max_value = (sizeof(component_cmm) / sizeof(component_cmm[0])) - 1; encoder_init_config.encoder_step = 1; encoder_init_config.encoder_number = COMPONENT_ENCODER; zh_avr_encoder_init(&encoder_init_config, &component_encoder_handle); zh_avr_encoder_set(&component_encoder_handle, 0); //** AC dimmer init **/ zh_avr_ac_dimmer_init_config_t ac_dimmer_init_config = ZH_AVR_AC_DIMMER_INIT_CONFIG_DEFAULT(); ac_dimmer_init_config.ac_dimmer_frequency = ZH_50HZ; ac_dimmer_init_config.zero_cross_port = AVR_PORTD; ac_dimmer_init_config.zero_cross_gpio = PORTD3; ac_dimmer_init_config.triac_port = AVR_PORTD; ac_dimmer_init_config.triac_gpio = PORTD4; zh_avr_ac_dimmer_init(&ac_dimmer_init_config); zh_avr_ac_dimmer_set(100); is_initialized = true; #ifdef DEBUG printf("%d.\n", uxTaskGetStackHighWaterMark(NULL)); #endif vTaskDelete(NULL); } void zh_avr_pcf8574_event_handler(zh_avr_pcf8574_event_on_isr_t *event) { switch (event->gpio_number) { case DMM_BUTTON: if (event->gpio_level == LOW && is_work == false) { if (is_dmm == true) { zh_avr_pcf8574_write_gpio(&led1_handle, DMM_LED_RED, LED_ON); zh_avr_pcf8574_write_gpio(&led1_handle, DMM_LED_GREEN, LED_OFF); zh_avr_pcf8574_write_gpio(&relay_handle, DMM_RELAY, RELAY_ON); is_dmm = false; } else { zh_avr_pcf8574_write_gpio(&led1_handle, DMM_LED_RED, LED_OFF); zh_avr_pcf8574_write_gpio(&led1_handle, DMM_LED_GREEN, LED_ON); zh_avr_pcf8574_write_gpio(&relay_handle, DMM_RELAY, RELAY_OFF); is_dmm = true; } } break; case FIX_BUTTON: if (event->gpio_level == LOW) { zh_avr_pcf8574_write_gpio(&led1_handle, FIX_LED_BLUE, LED_OFF); zh_avr_pcf8574_write_gpio(&led1_handle, FIX_LED_GREEN, LED_ON); is_fix = true; } else { zh_avr_pcf8574_write_gpio(&led1_handle, FIX_LED_BLUE, LED_ON); zh_avr_pcf8574_write_gpio(&led1_handle, FIX_LED_GREEN, LED_OFF); is_fix = false; } break; case NUM1_BUTTON: if ((used_channels & CHANNEL1) == 0) { break; } if (event->gpio_level == LOW) { is_work = true; if (is_num1_fixed == true) { break; } zh_avr_pcf8574_write_gpio(&led1_handle, NUM1_LED_BLUE, LED_OFF); zh_avr_pcf8574_write_gpio(&led1_handle, NUM1_LED_GREEN, LED_ON); zh_avr_pcf8574_write_gpio(&relay_handle, L1_RELAY, RELAY_ON); zh_avr_pcf8574_write_gpio(&relay_handle, GROUND_RELAY, RELAY_ON); // Temporary. vTaskDelay(10); // Temporary. zh_avr_ac_dimmer_start(); // Temporary. } else { // is_work = false; if (is_fix == true) { is_num1_fixed = true; break; } zh_avr_pcf8574_write_gpio(&led1_handle, NUM1_LED_BLUE, LED_ON); zh_avr_pcf8574_write_gpio(&led1_handle, NUM1_LED_GREEN, LED_OFF); zh_avr_ac_dimmer_stop(); // Temporary. vTaskDelay(1); // Temporary. zh_avr_pcf8574_write_gpio(&relay_handle, L1_RELAY, RELAY_OFF); zh_avr_pcf8574_write_gpio(&relay_handle, GROUND_RELAY, RELAY_OFF); // Temporary. is_work = false; is_num1_fixed = false; } break; case NUM2_BUTTON: if ((used_channels & CHANNEL2) == 0) { break; } if (event->gpio_level == LOW) { is_work = true; if (is_num2_fixed == true) { break; } zh_avr_pcf8574_write_gpio(&led1_handle, NUM2_LED_BLUE, LED_OFF); zh_avr_pcf8574_write_gpio(&led1_handle, NUM2_LED_GREEN, LED_ON); zh_avr_pcf8574_write_gpio(&relay_handle, L2_RELAY, RELAY_ON); // zh_avr_pcf8574_write_gpio(&relay_handle, GROUND_RELAY, RELAY_ON); // Temporary. // vTaskDelay(10); // Temporary. // zh_avr_ac_dimmer_start(); // Temporary. } else { is_work = false; if (is_fix == true) { is_num2_fixed = true; break; } zh_avr_pcf8574_write_gpio(&led1_handle, NUM2_LED_BLUE, LED_ON); zh_avr_pcf8574_write_gpio(&led1_handle, NUM2_LED_GREEN, LED_OFF); // zh_avr_ac_dimmer_stop(); // Temporary. // vTaskDelay(1); // Temporary. zh_avr_pcf8574_write_gpio(&relay_handle, L2_RELAY, RELAY_OFF); // zh_avr_pcf8574_write_gpio(&relay_handle, GROUND_RELAY, RELAY_OFF); // Temporary. is_num2_fixed = false; } break; case NUM3_BUTTON: if ((used_channels & CHANNEL3) == 0) { break; } if (event->gpio_level == LOW) { is_work = true; if (is_num3_fixed == true) { break; } zh_avr_pcf8574_write_gpio(&led2_handle, NUM3_LED_BLUE, LED_OFF); zh_avr_pcf8574_write_gpio(&led2_handle, NUM3_LED_GREEN, LED_ON); zh_avr_pcf8574_write_gpio(&relay_handle, L3_RELAY, RELAY_ON); } else { is_work = false; if (is_fix == true) { is_num3_fixed = true; break; } zh_avr_pcf8574_write_gpio(&led2_handle, NUM3_LED_BLUE, LED_ON); zh_avr_pcf8574_write_gpio(&led2_handle, NUM3_LED_GREEN, LED_OFF); zh_avr_pcf8574_write_gpio(&relay_handle, L3_RELAY, RELAY_OFF); is_num3_fixed = false; } break; case NUM4_BUTTON: if ((used_channels & CHANNEL4) == 0) { break; } if (event->gpio_level == LOW) { is_work = true; if (is_num4_fixed == true) { break; } zh_avr_pcf8574_write_gpio(&led2_handle, NUM4_LED_BLUE, LED_OFF); zh_avr_pcf8574_write_gpio(&led2_handle, NUM4_LED_GREEN, LED_ON); zh_avr_pcf8574_write_gpio(&relay_handle, L4_RELAY, RELAY_ON); } else { is_work = false; if (is_fix == true) { is_num4_fixed = true; break; } zh_avr_pcf8574_write_gpio(&led2_handle, NUM4_LED_BLUE, LED_ON); zh_avr_pcf8574_write_gpio(&led2_handle, NUM4_LED_GREEN, LED_OFF); zh_avr_pcf8574_write_gpio(&relay_handle, L4_RELAY, RELAY_OFF); is_num4_fixed = false; } break; default: break; } #ifdef DEBUG printf("%d.\n", uxTaskGetStackHighWaterMark(NULL)); #endif } void zh_avr_encoder_event_handler(zh_avr_encoder_event_on_isr_t *event) { switch (event->encoder_number) { case POWER_ENCODER: zh_avr_160x_set_cursor(&lcd_handle, 0, 11); zh_avr_160x_print_int(&lcd_handle, (uint8_t)event->encoder_position); zh_avr_160x_print_char(&lcd_handle, "% "); zh_avr_ac_dimmer_set(event->encoder_position); break; case COMPONENT_ENCODER: component_setup_function((uint8_t)event->encoder_position); break; default: break; } #ifdef DEBUG printf("%d.\n", uxTaskGetStackHighWaterMark(NULL)); #endif } ISR(PCINT1_vect) { if (is_initialized == false) { return; } // BaseType_t xHigherPriorityTaskWoken = pdFALSE; zh_avr_encoder_isr_handler(&power_encoder_handle); // if (zh_avr_encoder_isr_handler(&power_encoder_handle) == pdTRUE) // { // xHigherPriorityTaskWoken = pdTRUE; // } if (is_work == false) { zh_avr_encoder_isr_handler(&component_encoder_handle); // if (zh_avr_encoder_isr_handler(&component_encoder_handle) == pdTRUE) // { // xHigherPriorityTaskWoken = pdTRUE; // } } // if (xHigherPriorityTaskWoken == pdTRUE) // { // portYIELD(); // } } ISR(PCINT2_vect) { if (is_initialized == false) { return; } // BaseType_t xHigherPriorityTaskWoken = pdFALSE; zh_avr_pcf8574_isr_handler(); zh_avr_ac_dimmer_isr_handler(); // zh_avr_pcf8574_isr_handler(); // if (zh_avr_pcf8574_isr_handler() == pdTRUE) // { // xHigherPriorityTaskWoken = pdTRUE; // } // if (xHigherPriorityTaskWoken == pdTRUE) // { // portYIELD(); // } } void component_setup_function(uint8_t component) { char text_buffer[LCD_TEXT_BUFFER]; used_channels = component_channel[component]; zh_avr_160x_set_cursor(&lcd_handle, 1, 10); strcpy_P(text_buffer, component_cmm[component]); zh_avr_160x_print_char(&lcd_handle, text_buffer); zh_avr_160x_set_cursor(&lcd_handle, 2, 0); strcpy_P(text_buffer, component_line_1[component]); zh_avr_160x_print_char(&lcd_handle, text_buffer); zh_avr_160x_set_cursor(&lcd_handle, 3, 0); strcpy_P(text_buffer, component_line_2[component]); zh_avr_160x_print_char(&lcd_handle, text_buffer); zh_avr_pcf8574_write(&led1_handle, is_dmm == true ? 0xF9 : 0xFA); zh_avr_pcf8574_write(&led2_handle, 0x0F); if ((used_channels & CHANNEL1) == CHANNEL1) { zh_avr_pcf8574_write_gpio(&led1_handle, NUM1_LED_BLUE, LED_ON); } if ((used_channels & CHANNEL2) == CHANNEL2) { zh_avr_pcf8574_write_gpio(&led1_handle, NUM2_LED_BLUE, LED_ON); } if ((used_channels & CHANNEL3) == CHANNEL3) { zh_avr_pcf8574_write_gpio(&led2_handle, NUM3_LED_BLUE, LED_ON); } if ((used_channels & CHANNEL4) == CHANNEL4) { zh_avr_pcf8574_write_gpio(&led2_handle, NUM4_LED_BLUE, LED_ON); } }