2022-08-26 02:28 PM
Hi guys
I want to control a DC-DC converter with a PI controller and STM2F103 MCU; first, the ADC unit reads input and output voltage and inductor current, then we have two control loops; voltage control loop and current control loop.
For the PI controller i use this Lib :
github.com>Majid-Derhambakhsh>PID-Library
This is my main.c :
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "pid.h"
//#include <stdlib.h>
#include <math.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
long int k_Ds;
PID_TypeDef PID_Gvd;
PID_TypeDef PID_Gid;
unsigned char flag_1uS ;
uint32_t ADC_Value [3] ;
double V_High , V_Low , I_Lm ;
double V_High_ADC , V_Low_ADC , I_Lm_ADC , Duty_M , Duty_S ;
/** Boost Controller **/
/* Gvd PI Param. */
double I_Ref, V_High_Ref = 100, Kp_Gvd = 0.013 , Ki_Gvd = 200/0.00001 ;
/* Gid PI Param. */
double Duty_PI , Kp_Gid = 0.27 , Ki_Gid = 3218/0.00001 ;
double Duty_aux ;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim4;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM4_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1) ;
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIM_Base_Start_IT(&htim2) ;
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4) ;
/******** ********/
/*PID(PID_TypeDef *uPID, *Input, *Output, *Setpoint, Kp, Ki, Kd, PIDPON_TypeDef POn, PIDCD_TypeDef ControllerDirection); */
/** Gvd PI Setting **/
PID(&PID_Gvd , &V_High , &I_Ref , &V_High_Ref , Kp_Gvd , Ki_Gvd , 0, _PID_P_ON_E , _PID_CD_DIRECT);
PID_SetMode(&PID_Gvd, _PID_MODE_AUTOMATIC);
PID_SetSampleTime(&PID_Gvd, 0.01);
PID_SetOutputLimits(&PID_Gvd, 0, 10.8);
/** Gid PI Setting **/
PID(&PID_Gid , &I_Lm , &Duty_PI , &I_Ref , Kp_Gid , Ki_Gid , 0, _PID_P_ON_E , _PID_CD_DIRECT);
PID_SetMode(&PID_Gid, _PID_MODE_AUTOMATIC);
PID_SetSampleTime(&PID_Gid, 0.01);
PID_SetOutputLimits(&PID_Gid, 0.4, 0.9);
// calibrate ADC for better accuracy and start it w/ interrupt
HAL_ADCEx_Calibration_Start(&hadc1) ;
HAL_ADC_Start_IT(&hadc1) ;
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Value, 3) ; /* Start ADC DMA */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
PID_Compute(&PID_Gvd); /* Calculation of Gvd PI Controller */
PID_Compute(&PID_Gid); /* Calculation of Gid PI Controller */
Duty_M = ( 1 - Duty_PI ) * 719 ;
Aux_Switch_cal() ;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/********** My Functions *********/
/** Timer Flag **/
void System_timeTable(void)
{
flag_1uS = 1;
}
/** Aux Switch calculations **/
void Aux_Switch_cal(void)
{
Duty_aux = ( fabs(I_Lm) * 33 * 0.000001 * 1.2 ) / ( V_High * 0.00001 ) ;
if (Duty_aux > 0.48 )
{
Duty_aux = 0.48 ;
}
else if (Duty_aux < 0 )
{
Duty_aux = 0 ;
}
Duty_S = Duty_aux * 719 ;
k_Ds++;
}
This is my interrupt routines code :
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1)
{
__HAL_TIM_SET_COMPARE(&htim1 , TIM_CHANNEL_1 , round(Duty_M) );
k_pwm++ ;
__HAL_TIM_SET_COMPARE(&htim1 , TIM_CHANNEL_3 , round(Duty_S) );
}
if (htim->Instance == TIM2)
{
System_timeTable() ;
k_flag++ ;
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance == ADC1)
{
// PID_TypeDef PID_Gvd;
// PID_TypeDef PID_Gid;
/* ADC Values */
V_High_ADC = ( ( ADC_Value[0] * 3.3)/4059 ) ;
V_Low_ADC = ( ( ADC_Value[1] * 3.3)/4059 ) ;
I_Lm_ADC = ( ( ADC_Value[2] * 3.3)/4059 ) ;
/* Real Values of Measurments */
V_High = (( V_High_ADC / 16 ) * 150235) / 235 ; /* HCPL Gain = 8 , Voltage Divider: R1 = 150 KOhm , Rsens = 235 Ohm */
V_Low = (( V_Low_ADC / 16 ) * 150470) / 470 ; /* HCPL Gain = 8 , LM358 Gain = 2 , Voltage Divider: R1 = 150 KOhm , Rsens = 470 Ohm */
I_Lm = ( I_Lm_ADC - 2.5 ) / 0.04 ; /* Offset of ASC758 = 2.5 V , Sens of ASC758 = 40mV/A */
k_adc++ ;
}
}
2022-08-26 02:41 PM
V_High_ADC = ( ( ADC_Value[0] * 3.3)/4059 ) ;
I'd imagine that should be 4096.0 or 4095.0
2022-08-27 06:19 AM
4096 is the correct one. 4095 is popular only because people have some subjective wish to get the full VREF+ voltage, which the ADC cannot even measure...
Seems that a more efficient 32-bit float math should be enough for this purpose.