#include "interface.h" #include "pwm.h" TIM_SettingsTypeDef TIM_ENCODER = {0}; extern I2C_HandleTypeDef hi2c1; LCDI2C_HandleTypeDef hlcd1; TIM_EncoderTypeDef henc1; extern PWM_HandleTypeDef hpwm1; Interface_HandleTypeDef hinterface; /** * @brief Read encoder function. * @param henc - хендл энкодера. * @param hlcd - хендл LCD-дисплея. * @note This called from freertos MainTask thread. */ void ReadEncoder(TIM_EncoderTypeDef *henc, LCDI2C_HandleTypeDef *hlcd) { uint8_t *menu = (uint8_t *)&hinterface.MenuItems; uint8_t *disp_menu = (uint8_t *)&hinterface.DisplayingItems; //-----------READ SWITCH------------- if(hinterface.FineChanging == 0) // если кнопка энкодера не в режиме точной настройки { if((~henc->GPIOx->IDR)&henc->GPIO_PIN_SW) // ожидание нажатия кнопки { osDelay(50); if(((~henc->GPIOx->IDR)&henc->GPIO_PIN_SW )&& // если кнопка действительно нажата (HAL_GetTick() - hinterface.Switch_prevTick > hinterface.DoubleClick_Timeout) ) // и это не второй клик даблклика (слишком большая задержка после предыдущего нажатия) { hinterface.Encoder_Shdw = henc->htim->Instance->CNT; while((~henc->GPIOx->IDR)&henc->GPIO_PIN_SW) // ожидаем её отпускания { //------------FINE TUNE-------------- if (hinterface.Encoder_Shdw != henc->htim->Instance->CNT) // если кнопка не отпускается, и енкодер начинает регулироваться { hinterface.FineChanging = 1; // переходим в режим точной настройки break; // выход из цикла } osDelay(1); } //-----------SWITCH PARAM------------ if(hinterface.FineChanging == 0) // если энкодер не перешел в режим точной настройки { hinterface.Switch_prevTick = HAL_GetTick(); // сохраняем время отжатия для регистрации даблклика если он будет hinterface.CurrentSelection++; // переключаем режим // skip item if it isnt displayin, until run out of items while((*disp_menu&(1<<(hinterface.CurrentSelection-1))) == 0) { hinterface.CurrentSelection++; if(hinterface.MenuNumber == 0) // if menu for params (registers) { if(hinterface.CurrentSelection > Menu_Size) { hinterface.CurrentSelection = NOTHING_SELECTED; break; } } else // if menu for modes (coils) { if(hinterface.CurrentSelection - NOTHING_COIL_SELECTED > Menu_Coil_Size) { hinterface.CurrentSelection = NOTHING_COIL_SELECTED; break; } } } if(hinterface.MenuNumber == 0) { if(hinterface.CurrentSelection > (Menu_Size)) hinterface.CurrentSelection = NOTHING_SELECTED; } else { if((hinterface.CurrentSelection - NOTHING_COIL_SELECTED) > (Menu_Coil_Size)) hinterface.CurrentSelection = NOTHING_COIL_SELECTED; } } } else if(((~henc->GPIOx->IDR)&henc->GPIO_PIN_SW )&& // если кнопка действительно нажата (HAL_GetTick() - hinterface.Switch_prevTick < hinterface.DoubleClick_Timeout) ) // и это не второй клик даблклика (слишком большая задержка после предыдущего нажатия) { hinterface.MenuNumber++; if(hinterface.MenuNumber >= 2) { hinterface.MenuNumber = 0; } if (hinterface.MenuNumber == 0) hinterface.CurrentSelection = NOTHING_SELECTED; else if (hinterface.MenuNumber == 1) hinterface.CurrentSelection = NOTHING_COIL_SELECTED; } } } static uint16_t coef_value; if(hinterface.FineChanging == 0) // если енкодер не регулируется coef_value = 100; else coef_value = 2; int16_t encoder_diff = (int32_t)henc->htim->Instance->CNT - hinterface.Encoder_Shdw; int32_t tmpreg; switch(hinterface.CurrentSelection) { case PWM_VALUE_SELECTED: tmpreg = pwm_ctrl[R_PWM_CTRL_PWM_VALUE]; tmpreg += ((encoder_diff*coef_value)/2); if (tmpreg >= 0) pwm_ctrl[R_PWM_CTRL_PWM_VALUE] = tmpreg; else pwm_ctrl[R_PWM_CTRL_PWM_VALUE] = 0; break; case PWM_HZ_SELECTED: tmpreg = pwm_ctrl[R_PWM_CTRL_PWM_HZ]; tmpreg += (encoder_diff*coef_value)/2; if (tmpreg >= 0) pwm_ctrl[R_PWM_CTRL_PWM_HZ] = tmpreg; else pwm_ctrl[R_PWM_CTRL_PWM_HZ] = 0; break; case PWM_DUTYBRIDGE_SELECTED: tmpreg = pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE]; tmpreg += ((encoder_diff*coef_value)/2); if (tmpreg < 0) pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE] = 0; else if (tmpreg > 10000) pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE] = 10000; else pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE] = tmpreg; break; case PWM_COIL_DC_SELECTED: if(encoder_diff) hpwm1.sPWM_Config.PWM_Mode->DC = ~hpwm1.sPWM_Config.PWM_Mode->DC; break; case PWM_COIL_BRIDGE_SELECTED: if(encoder_diff) hpwm1.sPWM_Config.PWM_Mode->BRIDGE = ~hpwm1.sPWM_Config.PWM_Mode->BRIDGE; break; case PWM_COIL_PHASE_SELECTED: if(encoder_diff) hpwm1.sPWM_Config.PWM_Mode->PHASE = ~hpwm1.sPWM_Config.PWM_Mode->PHASE; break; case PWM_COIL_POLARITY_SELECTED: if(encoder_diff) hpwm1.sPWM_Config.PWM_Mode->POLARITY = ~hpwm1.sPWM_Config.PWM_Mode->POLARITY; break; case NOTHING_SELECTED: if(encoder_diff > 0) hinterface.StartMenuItem += 1; else if(encoder_diff < 0) hinterface.StartMenuItem -= 1; if(hinterface.StartMenuItem < 0) hinterface.StartMenuItem = 0; break; case NOTHING_COIL_SELECTED: if(encoder_diff > 0) hinterface.StartMenuItem += 1; else if(encoder_diff < 0) hinterface.StartMenuItem -= 1; if(hinterface.StartMenuItem < 0) hinterface.StartMenuItem = 0; break; default: break; } hinterface.Encoder_Shdw = henc->htim->Instance->CNT; if(hinterface.FineChanging == 1) // если некодер в режиме точной настройки) { if(((~henc->GPIOx->IDR)&henc->GPIO_PIN_SW) == 0) // ожидание отпускания кнопки { osDelay(50); if(((~henc->GPIOx->IDR)&henc->GPIO_PIN_SW) == 0) // если кнопка действительно нажата { hinterface.FineChanging = 0; // отключение режима точной настройки } } } } void UpdateInterfaceStruct(void) { if(hinterface.MenuNumber == 0) { if(hpwm1.sPWM_Config.PWM_Mode->BRIDGE && hpwm1.sPWM_Config.PWM_Mode->DC) hinterface.MenuItems.PWM_DutyBridge = 1; else hinterface.MenuItems.PWM_DutyBridge = 0; hinterface.MenuItems.PWM_Hz = 1; hinterface.MenuItems.PWM_Value = 1; } else { hinterface.MenuItems.PWM_DC = 1; hinterface.MenuItems.PWM_BRIDGE = 1; hinterface.MenuItems.PWM_PHASE = 1; hinterface.MenuItems.PWM_POLARITY = 1; } } void UpdateLCDDisplay(LCDI2C_HandleTypeDef *hlcd) { LCD_Check(hlcd); // clear display LCD_Send_CMD(hlcd, 0x01); osDelay(hlcd->ClearDelay); uint8_t *menu = (uint8_t *)&hinterface.MenuItems; int8_t disp_cnt = 0; disp_cnt -= hinterface.StartMenuItem; hinterface.DisplayingItems = (const Menu_HandleTypeDef){0}; if(hinterface.MenuNumber == 0) disp_cnt = LCD_DisplayMenuRegisters(hlcd, menu, disp_cnt); else disp_cnt = LCD_DisplayMenuCoils(hlcd, menu, disp_cnt); // if less than 2 item displayed - decrease start menu item if(disp_cnt <= 1) hinterface.StartMenuItem--; osDelay(hlcd->DisplayDelay); } uint8_t LCD_DisplayMenuCoils(LCDI2C_HandleTypeDef *hlcd, uint8_t *menu, int8_t disp_cnt) { for(int i = 0; i < Menu_Coil_Size; i++) { // if first sring is printed if (disp_cnt%2 == 0) LCD_Send_CMD(hlcd, 0x80); // set cursor to second string // if first sring is printed if (disp_cnt%2 == 1) LCD_Send_CMD(hlcd, 0xC0); // set cursor to second string switch(*menu&(1<<(i+NOTHING_COIL_SELECTED))) { case Menu_PWM_DC: disp_cnt++; if(disp_cnt > 0) { hinterface.DisplayingItems.PWM_DC = 1; if(hinterface.CurrentSelection == NOTHING_COIL_SELECTED) Display_PWM_DC(hlcd); else if (hinterface.CurrentSelection == PWM_COIL_DC_SELECTED) Display_PWM_DC(hlcd); } break; case Menu_PWM_BRIDGE: disp_cnt++; if(disp_cnt > 0) { hinterface.DisplayingItems.PWM_BRIDGE = 1; if(hinterface.CurrentSelection == NOTHING_COIL_SELECTED) Display_PWM_BRIDGE(hlcd); else if (hinterface.CurrentSelection == PWM_COIL_BRIDGE_SELECTED) Display_PWM_BRIDGE(hlcd); } break; case Menu_PWM_PHASE: disp_cnt++; if(disp_cnt > 0) { hinterface.DisplayingItems.PWM_PHASE = 1; if(hinterface.CurrentSelection == NOTHING_COIL_SELECTED) Display_PWM_PHASE(hlcd); else if (hinterface.CurrentSelection == PWM_COIL_PHASE_SELECTED) Display_PWM_PHASE(hlcd); } break; case Menu_PWM_POLARITY: disp_cnt++; if(disp_cnt > 0) { hinterface.DisplayingItems.PWM_POLARITY = 1; if(hinterface.CurrentSelection == NOTHING_COIL_SELECTED) Display_PWM_POLARITY(hlcd); else if (hinterface.CurrentSelection == PWM_COIL_POLARITY_SELECTED) Display_PWM_POLARITY(hlcd); } break; } // if second sring is printed if (disp_cnt >= 2) break; // stop "displaying" } return disp_cnt; } uint8_t LCD_DisplayMenuRegisters(LCDI2C_HandleTypeDef *hlcd, uint8_t *menu, int8_t disp_cnt) { for(int i = 0; i < Menu_Size; i++) { // if first sring is printed if (disp_cnt%2 == 0) LCD_Send_CMD(hlcd, 0x80); // set cursor to second string // if first sring is printed if (disp_cnt%2 == 1) LCD_Send_CMD(hlcd, 0xC0); // set cursor to second string switch(*menu&(1< 0) { hinterface.DisplayingItems.PWM_Value = 1; if(hinterface.CurrentSelection == NOTHING_SELECTED) Display_PWM_Value(hlcd); else if (hinterface.CurrentSelection == PWM_VALUE_SELECTED) Display_PWM_Value(hlcd); } break; case Menu_PWM_Hz: disp_cnt++; if(disp_cnt > 0) { hinterface.DisplayingItems.PWM_Hz = 1; if(hinterface.CurrentSelection == NOTHING_SELECTED) Display_PWM_Hz(hlcd); else if (hinterface.CurrentSelection == PWM_HZ_SELECTED) Display_PWM_Hz(hlcd); } break; case Menu_PWM_DutyBridge: disp_cnt++; if(disp_cnt > 0) { hinterface.DisplayingItems.PWM_DutyBridge = 1; if(hinterface.CurrentSelection == NOTHING_SELECTED) Display_PWM_DutyBridge(hlcd); else if (hinterface.CurrentSelection == PWM_DUTYBRIDGE_SELECTED) Display_PWM_DutyBridge(hlcd); } break; } // if second sring is printed if (disp_cnt >= 2) break; // stop "displaying" } return disp_cnt; } void Display_PWM_Value(LCDI2C_HandleTypeDef *hlcd) { if(hpwm1.sPWM_Mode&PWM_DC_MODE && ((hpwm1.sPWM_Mode&PWM_BRIDGE_MODE) == 0)) // in dc mode disp pwm duty { LCD_Send_STRING(hlcd, "Duty: "); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_PWM_VALUE]/100, 0); LCD_Send_STRING(hlcd, "."); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_PWM_VALUE]%100, 2); LCD_Send_STRING(hlcd, "%"); } else // in dc mode disp sine freq { LCD_Send_STRING(hlcd, "Sine: "); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_PWM_VALUE]/100, 0); LCD_Send_STRING(hlcd, "."); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_PWM_VALUE]%100, 2); LCD_Send_STRING(hlcd, " Hz"); } } void Display_PWM_Hz(LCDI2C_HandleTypeDef *hlcd) { LCD_Send_STRING(hlcd, "PWM: "); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_PWM_HZ], 0); LCD_Send_STRING(hlcd, " Hz"); } void Display_PWM_DutyBridge(LCDI2C_HandleTypeDef *hlcd) { LCD_Send_STRING(hlcd, "Duty: "); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE]/100, 0); LCD_Send_STRING(hlcd, "."); LCD_Send_INT(hlcd, pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE]%100, 2); LCD_Send_STRING(hlcd, "%"); } void Display_PWM_DC(LCDI2C_HandleTypeDef *hlcd) { LCD_Send_STRING(hlcd, "DC: "); if(hpwm1.sPWM_Config.PWM_Mode->DC) LCD_Send_STRING(hlcd, "DC"); else LCD_Send_STRING(hlcd, "Sine"); } void Display_PWM_BRIDGE(LCDI2C_HandleTypeDef *hlcd) { LCD_Send_STRING(hlcd, "Bridge: "); if(hpwm1.sPWM_Config.PWM_Mode->BRIDGE) LCD_Send_STRING(hlcd, "Bridge"); else LCD_Send_STRING(hlcd, "Single"); } void Display_PWM_PHASE(LCDI2C_HandleTypeDef *hlcd) { LCD_Send_STRING(hlcd, "Phase: "); if(hpwm1.sPWM_Config.PWM_Mode->PHASE) LCD_Send_STRING(hlcd, "3-Phase"); else LCD_Send_STRING(hlcd, "One Phase"); } void Display_PWM_POLARITY(LCDI2C_HandleTypeDef *hlcd) { LCD_Send_STRING(hlcd, "Polarity: "); if(hpwm1.sPWM_Config.PWM_Mode->POLARITY) LCD_Send_STRING(hlcd, "Neg"); else LCD_Send_STRING(hlcd, "Pos"); } /** * @brief First initialization of Encoder Timer. * @note This called from main */ void EncoderFirstInit(void) { hinterface.DoubleClick_Timeout = 200; // tim settings TIM_ENCODER.htim.Instance = TIMER_ENCODER_INSTANCE; TIM_ENCODER.htim.Init.Period = 0xFFFF; TIM_ENCODER.htim.Init.Prescaler = 0; TIM_ENCODER.sTimMode = TIM_IT_MODE; // TIM_ENCODER.sTickBaseMHz = TIMER_ENCODER_TICKBASE; // TIM_ENCODER.sTimAHBFreqMHz = TIMER_ENCODER_AHB_FREQ; // TIM_ENCODER.sTimFreqHz = 0; TIM_Base_Init(&TIM_ENCODER); henc1.sConfig.EncoderMode = TIM_ENCODERMODE_TI2; henc1.sConfig.IC1Polarity = TIM_INPUTCHANNELPOLARITY_FALLING; henc1.sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; henc1.sConfig.IC1Prescaler = TIM_ICPSC_DIV1; henc1.sConfig.IC1Filter = 5; henc1.sConfig.IC2Polarity = TIM_INPUTCHANNELPOLARITY_FALLING; henc1.sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; henc1.sConfig.IC2Prescaler = TIM_ICPSC_DIV1; henc1.sConfig.IC2Filter = 5; henc1.GPIOx = TIMER_ENCODER_PORT; henc1.GPIO_PIN_TI1 = TIMER_ENCODER_PIN1; henc1.GPIO_PIN_TI2 = TIMER_ENCODER_PIN2; henc1.GPIO_PIN_SW = TIMER_ENCODER_PIN_SW; TIM_Encoder_Init(&henc1, &TIM_ENCODER.htim); HAL_TIM_Base_Start(&TIM_ENCODER.htim); } /** * @brief First initialization of LCD. * @note This called from main */ void LCD_FirstInit(void) { hlcd1.hi2c = &hi2c1; hlcd1.DisplayDelay = 250; hlcd1.ClearDelay = 10; LCD_Init(&hlcd1); }