#include #include #include #include #include "esp_log.h" #include "ssd1306.h" #include "sdkconfig.h" #include "parsed_pins.h" #include "freertos/task.h" #include "freertos/FreeRTOS.h" #include "driver/gpio.h" #include "GPIO.h" #include "menu.h" #include "esp_timer.h" #include "mcpwm.h" #include "ADC.h" #include "functions.h" /*############################################*/ /*############## Display-Setup ###############*/ /*############################################*/ static SSD1306_t dev; void configure_OLED() { i2c_master_init(&dev, CONFIG_SDA_GPIO, CONFIG_SCL_GPIO, -1); ESP_LOGI("OLED", "Panel is 128x64"); ssd1306_init(&dev, 128, 64); ssd1306_clear_screen(&dev, false); ssd1306_contrast(&dev, 0xff); ssd1306_display_text_x3(&dev, 0, "Power", 5, false); ssd1306_display_text_x3(&dev, 4, " PCB", 4, false); vTaskDelay(2000 / portTICK_PERIOD_MS); ssd1306_clear_screen(&dev, false); } /*############################################*/ /*############ Internal Encoder ##############*/ /*############################################*/ //Variablen static volatile int enc_in_counter = 0; static volatile int64_t last_interrupt_time = 0; static volatile uint16_t last_interrupt_time_but = 0; static volatile bool enc_in_button_flag = false; static volatile uint8_t last_state = 0; static void IRAM_ATTR enc_in_isr_handler(void *arg) { static uint64_t last_interrupt_time = 0; // Aktueller Zustand der Pins lesen uint8_t current_state = (gpio_get_level(CONFIG_IN_ENC_A_GPIO) << 1) | gpio_get_level(CONFIG_IN_ENC_B_GPIO); uint64_t interrupt_time = esp_timer_get_time(); // Zustandswechsel-Logik (FSM) ohne starre Entprellzeit if (current_state != last_state) { // Nur wenn der Wechsel signifikant verzögert ist (gute Flanke) if ((interrupt_time - last_interrupt_time) > CONFIG_IN_ENCODER_DEBOUNCE_TIME) { if ((last_state == 0b01 && current_state == 0b11) || (last_state == 0b10 && current_state == 0b00)) { enc_in_counter++; // Vorwärtsdrehen } else if ((last_state == 0b10 && current_state == 0b11) || (last_state == 0b01 && current_state == 0b00)) { enc_in_counter--; // Rückwärtsdrehen } last_state = current_state; // Zustand aktualisieren last_interrupt_time = interrupt_time; } } } static void IRAM_ATTR enc_in_but_isr_handler(void *arg) { uint64_t interrupt_time = esp_timer_get_time(); // Entprellung: Verhindert die Erfassung von Störungen aufgrund von Prellung if (interrupt_time - last_interrupt_time_but > (CONFIG_IN_ENCODER_DEBOUNCE_TIME*1000)) { // Entprellungszeit last_interrupt_time_but = interrupt_time; // Entprellzeit zurücksetzen if (gpio_get_level(CONFIG_IN_ENC_BUT_GPIO)) { enc_in_button_flag = true; } } } void config_internal_Encoder(){ ESP_ERROR_CHECK(gpio_isr_handler_add(CONFIG_IN_ENC_A_GPIO, enc_in_isr_handler, NULL)); ESP_ERROR_CHECK(gpio_isr_handler_add(CONFIG_IN_ENC_B_GPIO, enc_in_isr_handler, NULL)); ESP_ERROR_CHECK(gpio_isr_handler_add(CONFIG_IN_ENC_BUT_GPIO, enc_in_but_isr_handler, NULL)); } /*############################################*/ /*############### Menu-Setup #################*/ /*############################################*/ typedef enum { MAIN_MENU, CONFIGURE_MENU, MORE_INFO_MENU } MenuState; typedef enum { MCPWM_MODE, BLDC_MODE, DC_BRUSHED_MODE, MODE_COUNT }OperationMode; const char *mode_names[] = { "MCPWM ", "BLDC ", "DC Brush" }; const char *OutCombi_names[]= { "+U -V ", "+U -W ", "+V -W ", "+V -U ", "+W -U ", "+W -V ", " +U ", " +V ", " +W ", "+U+V+W", "ERROR " }; typedef enum { STATE_ACTIVE, STATE_DEAKTIVE, STATE_UV, STATE_OC } BridgeState; const char *state_names[] = { "Active ", "Deaktive ", "UV ", "RFE (OC) " }; //Globalevariablen volatile MenuState current_menu = MAIN_MENU; volatile OperationMode current_mode = MCPWM_MODE; volatile BridgeState current_bridge_state = STATE_DEAKTIVE; volatile OutCombis current_out_combi = OUT_U_V; volatile bool ShouldState = false; //false==deaktive int cursor_position = 0; int max_cursor_pos = 0; bool in_editing = false; char display_message[100]; // Puffer für die Nachricht bool flag; uint16_t PWM_Frequency = 0; static void check_button_pressed(){ if (enc_in_button_flag){ enc_in_button_flag=false; switch (current_menu){ case MAIN_MENU: switch(cursor_position){ case 0: current_mode = (current_mode+1)% MODE_COUNT; break; case 1: ShouldState = !ShouldState; if(ShouldState){ start_mcpwm_output(); }else{ stop_mcpwm_output(); } break; case 2: current_menu = CONFIGURE_MENU; enc_in_counter=0; break; case 3: current_menu = MORE_INFO_MENU; enc_in_counter=0; break; case 4: if (current_mode==DC_BRUSHED_MODE){ current_out_combi =(current_out_combi+1)%10; }else{ current_out_combi =(current_out_combi+1)%6; } stop_mcpwm_output(); configure_mcpwm_output(current_out_combi); ShouldState = false; break; default: snprintf(display_message, sizeof(display_message), "ERROR"); ssd1306_display_text(&dev, 7, display_message, strlen(display_message), false); break; } break; case CONFIGURE_MENU: switch(cursor_position){ case 0: if(in_editing){ set_mcpwm_frequency(enc_in_counter*1000); in_editing = false; enc_in_counter= cursor_position; }else{ in_editing = true; enc_in_counter = get_frequency()/1000; } break; case 1: if(in_editing){ set_mcpwm_duty((float)enc_in_counter); in_editing = false; enc_in_counter = cursor_position; }else{ in_editing = true; enc_in_counter = (int)get_duty(); } break; case 3: current_menu = MAIN_MENU; enc_in_counter=0; break; } break; case MORE_INFO_MENU: current_menu = MAIN_MENU; enc_in_counter=0; break; default: ESP_LOGE("Error","Not yet programmed"); break; } } } static void getset_bridge_state(){ bool RFE_Pulled = !(gpio_get_level(CONFIG_RFE_GPIO)); if(get_voltage_in()<18000){ current_bridge_state=STATE_UV; }else if (RFE_Pulled){ current_bridge_state=STATE_OC; }else if(!ShouldState){ current_bridge_state=STATE_DEAKTIVE; }else{ current_bridge_state=STATE_ACTIVE; } } static void render_main_menu(){ if(current_mode == BLDC_MODE)max_cursor_pos = 3;else max_cursor_pos=4; //Mode snprintf(display_message, sizeof(display_message), "Mode: %s", mode_names[current_mode]); ssd1306_display_text(&dev, 1, display_message, strlen(display_message), cursor_position == 0); //ShouldState Started oder Stopped snprintf(display_message, sizeof(display_message), "%s", ShouldState ? "Started" : "Stopped"); ssd1306_display_text(&dev, 2, display_message, strlen(display_message), cursor_position == 1); //Configure_Menu snprintf(display_message, sizeof(display_message), "Configure ->"); ssd1306_display_text(&dev, 3, display_message, strlen(display_message), cursor_position == 2); //More_Info_Menu snprintf(display_message, sizeof(display_message), "Sensor Info ->"); ssd1306_display_text(&dev, 4, display_message, strlen(display_message),cursor_position == 3); //Output Selection snprintf(display_message, sizeof(display_message), "Out: %s",OutCombi_names[current_out_combi]); ssd1306_display_text(&dev, 5, display_message, strlen(display_message), (current_mode == BLDC_MODE)|(cursor_position == 4)); //State getset_bridge_state(); snprintf(display_message, sizeof(display_message), "State: %s",state_names[current_bridge_state]); ssd1306_display_text(&dev, 6, display_message, strlen(display_message), true); /*snprintf(display_message, sizeof(display_message), "cursor: %i %s",cursor_position,enc_in_button_flag ?"in" : "out"); ssd1306_display_text(&dev, 7, display_message, strlen(display_message), true); */} static void render_config_menu(){ max_cursor_pos = 3; switch(current_mode){ case MCPWM_MODE: case BLDC_MODE: //Titel snprintf(display_message, sizeof(display_message), "Conf. MCPWM"); ssd1306_display_text(&dev, 1, display_message, strlen(display_message), false); //Frequenz if(in_editing && cursor_position == 0){ snprintf(display_message, sizeof(display_message), "PWMFreq.:%ikHz", enc_in_counter); ssd1306_display_text(&dev, 2, display_message, strlen(display_message), true); set_mcpwm_frequency(enc_in_counter*1000); }else{ snprintf(display_message, sizeof(display_message), "PWMFreq.:%lukHz", (get_frequency()/1000)); ssd1306_display_text(&dev, 2, display_message, strlen(display_message), cursor_position == 0); } //Duty cycle if(in_editing && cursor_position == 1){ snprintf(display_message, sizeof(display_message), "Duty: %.1f%%", (float)enc_in_counter); ssd1306_display_text(&dev, 3, display_message, strlen(display_message), cursor_position == 1); set_mcpwm_duty((float)enc_in_counter); }else{ snprintf(display_message, sizeof(display_message), "Duty: %.1f%%", get_duty()); ssd1306_display_text(&dev, 3, display_message, strlen(display_message), cursor_position == 1); } //Todzeit snprintf(display_message, sizeof(display_message), "DeadTime: %ins", CONFIG_DEAD_TIME_PWM); ssd1306_display_text(&dev, 4, display_message, strlen(display_message), cursor_position == 2); //Back snprintf(display_message, sizeof(display_message), "Back"); ssd1306_display_text(&dev, 5, display_message, strlen(display_message), cursor_position == 3); //State getset_bridge_state(); snprintf(display_message, sizeof(display_message), "State: %s",state_names[current_bridge_state]); ssd1306_display_text(&dev, 6, display_message, strlen(display_message), true); break; default: break; } } static void render_info_menu(){ max_cursor_pos = 1; //cur_U & Hall_A snprintf(display_message, sizeof(display_message), "U:%ldmA H_A:%c", get_current_ASC712(CONFIG_I_SENSE_U_ADC),get_Hall(CONFIG_HALL_A_GPIO)?'1':'0'); ssd1306_display_text(&dev, 1, display_message, strlen(display_message), false); //cur_V & Hall_B snprintf(display_message, sizeof(display_message), "V:%ldmA H_B:%c", get_current_ASC712(CONFIG_I_SENSE_V_ADC),get_Hall(CONFIG_HALL_B_GPIO)?'1':'0'); ssd1306_display_text(&dev, 2, display_message, strlen(display_message), false); //cur_W & Hall_C snprintf(display_message, sizeof(display_message), "W:%ldmA H_C:%c", get_current_ASC712(CONFIG_I_SENSE_W_ADC),get_Hall(CONFIG_HALL_C_GPIO)?'1':'0'); ssd1306_display_text(&dev, 3, display_message, strlen(display_message), false); //Bridge Current & Speed snprintf(display_message, sizeof(display_message), "B:%ldmA SP.:%frpm", get_current_bridge(CONFIG_I_SENSE_ADC), get_speed_AB()); ssd1306_display_text(&dev, 4, display_message, strlen(display_message), false); //Bridge Voltage & Torque snprintf(display_message, sizeof(display_message), "U_in:%ldmV Torq.:%ldmV", get_voltage_in(), get_torque()); ssd1306_display_text(&dev, 5, display_message, strlen(display_message), false); //Left/right snprintf(display_message, sizeof(display_message), "Dir.:%s", (get_direction() == -1) ? "Error" : (get_direction() == 0) ? "Right" : "Left"); ssd1306_display_text(&dev, 6, display_message, strlen(display_message), false); //Back snprintf(display_message, sizeof(display_message), "Back"); ssd1306_display_text(&dev, 7, display_message, strlen(display_message), true); } MenuState last_menu = MAIN_MENU; // Initialisiere mit dem Startmenü OutCombis last_out_combi = OUT_U_V; void menu_loop(){ if(current_mode== BLDC_MODE){ current_out_combi = get_output_combination(get_Hall_Combi()); if (current_out_combi != last_out_combi) { configure_mcpwm_output(current_out_combi); if(ShouldState){ start_mcpwm_output(); } last_out_combi = current_out_combi; // Update to the new out_combi }} if(!in_editing){ if (enc_in_counter<0){ enc_in_counter = max_cursor_pos; } if (enc_in_counter> max_cursor_pos){ enc_in_counter =0; } cursor_position = enc_in_counter; } if (current_menu != last_menu) { ssd1306_clear_screen(&dev, false); // Clear the screen on menu change last_menu = current_menu; // Update to the new menu state } switch (current_menu) { case MAIN_MENU: render_main_menu(); break; case CONFIGURE_MENU: render_config_menu(); break; case MORE_INFO_MENU: render_info_menu(); default: break; } check_button_pressed(); }