518 lines
14 KiB
C
518 lines
14 KiB
C
#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<<i))
|
|
{
|
|
case Menu_PWM_Value:
|
|
disp_cnt++;
|
|
|
|
if(disp_cnt > 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);
|
|
}
|