0% ont trouvé ce document utile (0 vote)
3 vues29 pages

Code

code c pour stm32 avec des modifications

Transféré par

hasinaralaivola
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
3 vues29 pages

Code

code c pour stm32 avec des modifications

Transféré par

hasinaralaivola
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd

Sponsored by CodeScene

Prioritizing High-Impact Technical Debt for Faster Delivery

CodeScene addresses the challenge engineering leaders face when dealing with accumulated
technical debt across large codebases. Rather than attempting to refactor everything or making
arbitrary decisions, CodeScene analyzes Git history and code patterns to pinpoint the specific
modules and files that create actual development bottlenecks. This data-driven approach
enables teams to focus refactoring efforts where they'll have the greatest impact on velocity
and delivery predictability, with validated metrics showing 2x faster feature delivery and 9x
improved on-time delivery rates.

Discover More

Code Complet pour CubeIDE (STM32F103C8T6) - 12V & 24V + 50Hz


Fichier main.c
#include "stm32f1xx.h"
#include <math.h>

// --- CONFIGURATION PINS ---


#define LED_PIN GPIO_PIN_13 // PC13
#define MOSFET_HIGH1_PIN GPIO_PIN_8 // PA8 (TIM1_CH1)
#define MOSFET_LOW1_PIN GPIO_PIN_13 // PB13 (TIM1_CH1N)
#define MOSFET_HIGH2_PIN GPIO_PIN_9 // PA9 (TIM1_CH2)
#define MOSFET_LOW2_PIN GPIO_PIN_14 // PB14 (TIM1_CH2N)
#define BATT_ADC_PIN GPIO_PIN_0 // PA0 (ADC1_IN0)
#define FEEDBACK_ADC_PIN GPIO_PIN_1 // PA1 (ADC1_IN1)

// --- PARAMETRES SPWM ---


#define SPWM_POINTS 400 // Résolution sinus
#define TIM1_PERIOD 2000 // 72MHz / 20kHz = 3600 (ajusté)
#define TIM1_PRESCALER 1 // 72MHz direct
#define DEADTIME_NS 36 // ~500ns à 72MHz

// --- PARAMETRES ALIMENTATION 12V ---


#define VREFINT_CAL_ADDR_12V 0x1FFFF7BA // Calib Vref interne
#define VREFINT_DEFAULT_12V 1200.0f // mV
#define BATT_LOW_THRESHOLD_12V 10.0f // V (low batt 12V)
#define BATT_HIGH_THRESHOLD_12V 14.0f // V (high batt 12V)
#define BATT_ZENER_DROP_12V 0.7f // V (diode zener)

// --- PARAMETRES ALIMENTATION 24V ---


#define VREFINT_CAL_ADDR_24V 0x1FFFF7BA // Calib Vref interne
#define VREFINT_DEFAULT_24V 1200.0f // mV
#define BATT_LOW_THRESHOLD_24V 20.0f // V (low batt 24V)
#define BATT_HIGH_THRESHOLD_24V 30.0f // V (high batt 24V)
#define BATT_ZENER_DROP_24V 0.7f // V (diode zener)

// --- PARAMETRES DIVISEURS DE TENSION ---


#define BATT_DIVIDER_R1_12V 100000.0f // 100kΩ
#define BATT_DIVIDER_R2_12V 10000.0f // 10kΩ
#define BATT_FACTOR_12V (BATT_DIVIDER_R1_12V + BATT_DIVIDER_R2_12V)
/ BATT_DIVIDER_R2_12V // 11
#define BATT_DIVIDER_R1_24V 100000.0f // 100kΩ
#define BATT_DIVIDER_R2_24V 10000.0f // 10kΩ
#define BATT_FACTOR_24V (BATT_DIVIDER_R1_24V + BATT_DIVIDER_R2_24V)
/ BATT_DIVIDER_R2_24V // 11

#define FEEDBACK_DIVIDER_R1 22000.0f // 22kΩ


#define FEEDBACK_DIVIDER_R2 2200.0f // 2.2kΩ
#define FEEDBACK_FACTOR (FEEDBACK_DIVIDER_R1 + FEEDBACK_DIVIDER_R2)
/ FEEDBACK_DIVIDER_R2 // 11

// --- PARAMETRES 50Hz (pour IRFP) ---


#define OUTPUT_FREQ_50HZ 50.0f // Hz (50Hz pour onduleur)
#define TIM3_PERIOD_50HZ 720 // 72MHz / 1440 = 50kHz (pour
SPWM)
#define TIM3_PRESCALER_50HZ 0 // 72MHz direct

// --- PARAMETRES REGULATION ---


#define OUTPUT_VOLTAGE_SET_12V 12.0f // V (consigne 12V)
#define OUTPUT_VOLTAGE_SET_24V 24.0f // V (consigne 24V)
#define KP 2.0f
#define KI 0.5f
#define KD 0.1f

// --- VARIABLES GLOBALES ---


volatile uint16_t spwm_table[SPWM_POINTS];
volatile uint16_t spwm_index = 0;
volatile float modulation_index = 0.85f;
volatile uint32_t system_tick = 0;
volatile uint16_t adc_batt_value = 0;
volatile uint16_t adc_feedback_value = 0;
volatile float battery_voltage = 0.0f;
volatile float output_voltage = 0.0f;
volatile float error_integral = 0.0f;
volatile float error_prev = 0.0f;
volatile uint8_t low_batt_flag = 0;
volatile uint8_t high_batt_flag = 0;
volatile uint8_t mode_12V = 0; // 0 = 24V, 1 = 12V

// --- PROTOTYPES ---


void SystemClock_Config(void);
void GPIO_Init(void);
void TIM1_Init_FullBridge(void);
void TIM2_Init_SPWM_Update(void);
void TIM3_Init_50Hz(void);
void ADC1_Init(void);
void Generate_SPWM_Table(void);
void Delay_ms(uint32_t ms);
void Update_PID_Controller(void);
void Set_Operation_Mode(uint8_t mode_12V);

// --- MAIN ---


int main(void) {
SystemInit();
SystemClock_Config();
GPIO_Init();
Generate_SPWM_Table();
TIM1_Init_FullBridge();
TIM2_Init_SPWM_Update();
TIM3_Init_50Hz();
ADC1_Init();
SysTick_Config(72000); // 1ms

// Démarrage en mode 24V


Set_Operation_Mode(0);

while(1) {
// Surveillance batterie toutes les secondes
if((system_tick % 1000) == 0) {
// Calcul tension batterie
float vref_int = (float)(*(__IO uint16_t*)VREFINT_CAL_ADDR_24V)
* VREFINT_DEFAULT_24V / 4096.0f;
battery_voltage = (adc_batt_value * vref_int / 4096.0f) * 3.3f
* BATT_FACTOR_24V;

// Test low battery


if(battery_voltage < BATT_LOW_THRESHOLD_24V) {
low_batt_flag = 1;
HAL_GPIO_WritePin(GPIOC, LED_PIN, GPIO_PIN_SET); // LED ON
= alerte
} else if(battery_voltage > BATT_HIGH_THRESHOLD_24V) {
high_batt_flag = 1;
HAL_GPIO_WritePin(GPIOC, LED_PIN, GPIO_PIN_SET); // LED ON
= alerte
} else {
low_batt_flag = 0;
high_batt_flag = 0;
}
}

Delay_ms(10);
}
}

// --- GENERATION TABLE SINUS ---


void Generate_SPWM_Table(void) {
float amplitude = (TIM1_PERIOD / 2.0f) * 0.90f;
float center = TIM1_PERIOD / 2.0f;

for(int i = 0; i < SPWM_POINTS; i++) {


float angle = (2.0f * M_PI * i) / SPWM_POINTS;
spwm_table[i] = (uint16_t)(center + (sinf(angle) * amplitude));
}
}

// --- CONFIGURATION TIMER 1 (FULL-BRIDGE) ---


void TIM1_Init_FullBridge(void) {
// Enable TIM1 clock
__HAL_RCC_TIM1_CLK_ENABLE();

TIM_ClockConfigTypeDef sClockSourceConfig = {0};


TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

// Time base configuration


TIM_HandleTypeDef htim1;
[Link] = TIM1;
[Link] = TIM1_PRESCALER - 1;
[Link] = TIM_COUNTERMODE_CENTERALIGNED1;
[Link] = TIM1_PERIOD;
[Link] = TIM_CLOCKDIVISION_DIV1;
[Link] = 0;
HAL_TIM_Base_Init(&htim1);

// PWM configuration for CH1


[Link] = TIM_OCMODE_PWM1;
[Link] = TIM1_PERIOD / 2;
[Link] = TIM_OCPOLARITY_HIGH;
[Link] = TIM_OCNPOLARITY_HIGH;
[Link] = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

// PWM configuration for CH2


HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);

// Break and dead-time configuration


[Link] = TIM_OSSR_ENABLE;
[Link] = TIM_OSSI_ENABLE;
[Link] = TIM_LOCKLEVEL_OFF;
[Link] = DEADTIME_NS / 2;
[Link] = TIM_BREAK_DISABLE;
[Link] = TIM_BREAKPOLARITY_HIGH;
[Link] = TIM_AUTOMATICOUTPUT_ENABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);

HAL_TIM_MspPostInit(&htim1);
HAL_TIM_Base_Start(&htim1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
}

// --- CONFIGURATION TIMER 2 (SPWM UPDATE 50kHz) ---


void TIM2_Init_SPWM_Update(void) {
TIM_HandleTypeDef htim2;
[Link] = TIM2;
[Link] = 0;
[Link] = TIM_COUNTERMODE_UP;
[Link] = 1440 - 1; // 72MHz / 1440 = 50kHz
[Link] = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);

HAL_TIM_Base_Start_IT(&htim2);

HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}

// --- CONFIGURATION TIMER 3 (50Hz ONDULEUR) ---


void TIM3_Init_50Hz(void) {
TIM_HandleTypeDef htim3;
[Link] = TIM3;
[Link] = TIM3_PRESCALER_50HZ;
[Link] = TIM_COUNTERMODE_UP;
[Link] = (72000000 / TIM3_PRESCALER_50HZ) /
(OUTPUT_FREQ_50HZ * 2) - 1;
[Link] = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);

HAL_TIM_Base_Start_IT(&htim3);

HAL_NVIC_SetPriority(TIM3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}

// --- INTERRUPTION TIMER 2 ---


void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {


if(htim->Instance == TIM2) {
// Mise à jour PWM avec protection
if(!low_batt_flag && !high_batt_flag) {
TIM1->CCR1 = spwm_table[spwm_index]; // M1
TIM1->CCR2 = spwm_table[(spwm_index + SPWM_POINTS/2) %
SPWM_POINTS]; // M3 (180° déphasé)
} else {
TIM1->CCR1 = TIM1_PERIOD / 2;
TIM1->CCR2 = TIM1_PERIOD / 2;
}

spwm_index = (spwm_index + 1) % SPWM_POINTS;


}
}

// --- INTERRUPTION TIMER 3 (50Hz) ---


void TIM3_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim3);
}

void HAL_TIM_PeriodElapsedCallback_50Hz(TIM_HandleTypeDef *htim) {


if(htim->Instance == TIM3) {
// Toggle entre 12V et 24V toutes les demi-périodes
static uint8_t half_period = 0;
half_period = !half_period;

if(half_period) {
Set_Operation_Mode(1); // 12V
} else {
Set_Operation_Mode(0); // 24V
}
}
}

// --- CONFIGURATION ADC ---


void ADC1_Init(void) {
ADC_HandleTypeDef hadc1;
[Link] = ADC1;
[Link] = ENABLE;
[Link] = ENABLE;
[Link] = DISABLE;
[Link] = ADC_SOFTWARE_START;
[Link] = ADC_DATAALIGN_RIGHT;
[Link] = 2;
HAL_ADC_Init(&hadc1);

// Configuration channel PA0 (Batterie)


ADC_ChannelConfTypeDef sConfig = {0};
[Link] = ADC_CHANNEL_0;
[Link] = 1;
[Link] = ADC_SAMPLETIME_55CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// Configuration channel PA1 (Feedback)
[Link] = ADC_CHANNEL_1;
[Link] = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

HAL_ADC_Start(&hadc1);
}

// --- INTERRUPTION ADC ---


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if(hadc->Instance == ADC1) {
static uint8_t adc_seq = 0;
if(adc_seq == 0) {
adc_batt_value = HAL_ADC_GetValue(hadc);
adc_seq = 1;
} else {
adc_feedback_value = HAL_ADC_GetValue(hadc);
adc_seq = 0;

// Calcul tension de sortie selon mode


float vref_int = (float)(*(__IO uint16_t*)VREFINT_CAL_ADDR_24V)
* VREFINT_DEFAULT_24V / 4096.0f;
float vfb = (adc_feedback_value * vref_int / 4096.0f) * 3.3f;

if(mode_12V) {
output_voltage = vfb * FEEDBACK_FACTOR; // 12V mode
} else {
output_voltage = vfb * FEEDBACK_FACTOR; // 24V mode
}

// Régulation PID
Update_PID_Controller();
}
}
}

// --- REGULATION PID ---


void Update_PID_Controller(void) {
static float last_output = TIM1_PERIOD / 2;
float error;

if(mode_12V) {
error = OUTPUT_VOLTAGE_SET_12V - output_voltage;
} else {
error = OUTPUT_VOLTAGE_SET_24V - output_voltage;
}

error_integral += error;
if(error_integral > 1000.0f) error_integral = 1000.0f;
if(error_integral < -1000.0f) error_integral = -1000.0f;

float derivative = error - error_prev;


error_prev = error;

float pid_output = KP * error + KI * error_integral + KD * derivative;

// Limitation modulation index


if(pid_output > 0.95f * TIM1_PERIOD/2) pid_output = 0.95f *
TIM1_PERIOD/2;
if(pid_output < -0.95f * TIM1_PERIOD/2) pid_output = -0.95f *
TIM1_PERIOD/2;

// Application modulation
float center = TIM1_PERIOD / 2.0f;
last_output = center + pid_output;

// Limitation safe
if(last_output > TIM1_PERIOD - 100) last_output = TIM1_PERIOD - 100;
if(last_output < 100) last_output = 100;

// Mise à jour directe si pas en période SPWM


TIM1->CCR1 = (uint16_t)last_output;
}

// --- CONFIGURATION OPERATION MODE ---


void Set_Operation_Mode(uint8_t mode_12V_param) {
mode_12V = mode_12V_param;

if(mode_12V) {
// Mode 12V
OUTPUT_VOLTAGE_SET_12V = 12.0f;
BATT_LOW_THRESHOLD_12V = 10.0f;
BATT_HIGH_THRESHOLD_12V = 14.0f;
BATT_FACTOR_12V = 11.0f;
} else {
// Mode 24V
OUTPUT_VOLTAGE_SET_24V = 24.0f;
BATT_LOW_THRESHOLD_24V = 20.0f;
BATT_HIGH_THRESHOLD_24V = 30.0f;
BATT_FACTOR_24V = 11.0f;
}
}

// --- CONFIGURATION GPIO ---


void GPIO_Init(void) {
// Enable GPIO clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();

// PA8 : TIM1_CH1 (M1)


GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = MOSFET_HIGH1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// PA9 : TIM1_CH2 (M3)


GPIO_InitStruct.Pin = MOSFET_HIGH2_PIN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// PB13 : TIM1_CH1N (M2)


GPIO_InitStruct.Pin = MOSFET_LOW1_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// PB14 : TIM1_CH2N (M4)


GPIO_InitStruct.Pin = MOSFET_LOW2_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// PC13 : LED
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

// PA0, PA1 : ADC (input floating)


GPIO_InitStruct.Pin = BATT_ADC_PIN | FEEDBACK_ADC_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// --- INTERRUPTION SYSTICK ---


void SysTick_Handler(void) {
HAL_IncTick();
system_tick++;
}

void Delay_ms(uint32_t ms) {


uint32_t start = system_tick;
while((system_tick - start) < ms);
}

// --- CONFIGURATION HORLOGE ---


void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

// Configure HSE Oscillator


RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.[Link] = RCC_PLL_ON;
RCC_OscInitStruct.[Link] = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.[Link] = RCC_PLL_MUL9;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

// Configure system clock


RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

// Configure Systick
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

Configuration IOC (CubeMX)

Fichier SPI avec configurations :

Pins utilisées :

 PA8 : TIM1_CH1 (MOSFET M1)


 PA9 : TIM1_CH2 (MOSFET M3)
 PB13 : TIM1_CH1N (MOSFET M2)
 PB14 : TIM1_CH2N (MOSFET M4)
 PA0 : ADC1_IN0 (Tension batterie)
 PA1 : ADC1_IN1 (Feedback sortie)
 PC13 : LED statut

Configuration IOC :

1. System Core > SYS


o RCC: HSE = Crystal/Ceramic Resonator
o Clock Configuration: HCLK=72MHz, APB1=36MHz, APB2=72MHz

2. TIM1
o Mode: Center-aligned PWM
o Channels: CH1, CH1N, CH2, CH2N
o Prescaler: 0
o Counter Period: 2000
o Repetition Counter: 0
o Dead Time: 36 (500ns)

3. TIM2
o Mode: Up-counter
o Prescaler: 0
o Counter Period: 1440
o Interrupt: Enable

4. TIM3
o Mode: Up-counter
o Prescaler: 0
o Counter Period: 720
o Interrupt: Enable

5. ADC1
o Mode: Continuous conversion
o Channels: PA0 (Rank 1), PA1 (Rank 2)
o Sample Time: 55.5 cycles

6. GPIO
o PA8, PA9: AF Push-Pull, High speed
o PB13, PB14: AF Push-Pull, High speed
o PA0, PA1: Analog mode
o PC13: Output Push-Pull, Low speed

Rappels des Blocs de Code

1. Génération SPWM
void Generate_SPWM_Table(void) {
// Crée 400 points d'un sinus centré
// Amplitude = 90% de la période TIM1
// Formule : centre + sin(angle) × amplitude
}

Explication : Pré-calcule une table de 400 points représentant un demi-onde sinusoïdale pour
une modulation de largeur d'impulsion.

2. Timer 1 Full-Bridge
void TIM1_Init_FullBridge(void) {
// Configure 4 MOSFET en pont complet
// Center-aligned pour commutation symétrique
// Deadtime intégrée pour éviter les courts-circuits
}

Explication : Initialise le timer pour contrôler 4 MOSFET en configuration pont complet avec
protection deadtime.

3. Timer 2 Update 50kHz


void TIM2_Init_SPWM_Update(void) {
// Fréquence 50kHz = 20kHz × 400 points
// Interruption précise pour mise à jour SPWM
}

Explication : Crée une interruption à 50kHz pour mettre à jour les registres PWM avec les
points SPWM.

4. Timer 3 50Hz
void TIM3_Init_50Hz(void) {
// Fréquence 50Hz pour onde sinusoïdale pure
// Alternance 12V/24V pour onduleur
}

Explication : Génère une onde sinusoïdale de 50Hz en alternant entre 12V et 24V.

5. ADC en Continu
void ADC1_Init(void) {
// Conversion continue batterie + feedback
// Callback pour traitement des valeurs
}

Explication : Configure l'ADC pour mesurer en continu la tension batterie et la tension de


sortie.

6. Régulation PID
void Update_PID_Controller(void) {
// Calcul erreur = consigne - réel
// Intégrale et dérivée pour stabilité
// Limitation sortie pour protection
}
Explication : Implémente un correcteur PID pour maintenir la tension de sortie constante.

7. Gestion Modes 12V/24V


void Set_Operation_Mode(uint8_t mode_12V_param) {
// Change les paramètres selon le mode
// 12V ou 24V avec protections adaptées
}

Explication : Permet de basculer entre les modes 12V et 24V avec leurs paramètres
respectifs.

Implémentations IOC

1. Project Manager
o MCU: STM32F103C8Tx
o Clock: 72MHz from HSE
o Code Generator: Generate peripheral initialization as a pair of '.c/.h' files

2. Pinout & Configuration


o PA8: TIM1_CH1 (GPIO_Output)
o PA9: TIM1_CH2 (GPIO_Output)
o PB13: TIM1_CH1N (GPIO_Output)
o PB14: TIM1_CH2N (GPIO_Output)
o PA0: ADC1_IN0 (Analog)
o PA1: ADC1_IN1 (Analog)
o PC13: GPIO_Output

3. Configuration Timers
o TIM1: PWM Generation CH1, CH2, CH1N, CH2N
o TIM2: Time Base, Interrupt
o TIM3: Time Base, Interrupt

4. Configuration ADC
o ADC1: Continuous Mode, Scan Mode
o Channels: PA0, PA1

5. NVIC Settings
o TIM2 global interrupt: Priority 2
o TIM3 global interrupt: Priority 1
o SysTick: Default priority

Pins Utilisés
Pin Fonction Type

PA8 M1 (High-side) AF Output

PA9 M3 (High-side) AF Output

PB13 M2 (Low-side) AF Output


Pin Fonction Type

PB14 M4 (Low-side) AF Output

PA0 Batterie Analog Input

PA1 Feedback Analog Input

PC13 LED Digital Output

Avantages Principaux

1. Double tension : Compatible 12V et 24V


2. Onduleur 50Hz : Sortie sinusoïdale pure
3. Alternance automatique : 12V/24V pour onduleur
4. Protection double : Low battery et high battery
5. Régulation précise : PID maintient tension constante
6. Faible ripple : SPWM 20kHz avec 400 points
7. Tolérance : Deadtime 500ns pour sécurité

Rappel Global pour Technicien

Ce code implémente un convertisseur DC-DC push-pull full-bridge avec onduleur 50Hz


capable de fonctionner en mode 12V ou 24V. Le système alterne automatiquement entre les
deux tensions pour générer une onde sinusoïdale de 50Hz, idéale pour alimenter des appareils
domestiques.

Caractéristiques principales :

 Entrée : 10-14V (12V) ou 20-30V (24V)


 Sortie : 12V ou 24V alternés à 50Hz
 Fréquence : 20kHz (SPWM) avec 400 points de résolution
 Contrôle : 4 MOSFET IRF en pont complet
 Régulation : PID avec intégrale et dérivée
 Protection : Deadtime 500ns, low/high battery cut-off
 Microcontrôleur : STM32F103C8T6 @ 72MHz

Pour implémentation physique :

 Diviseur batterie 12V : 100kΩ + 10kΩ (rapport 11:1)


 Diviseur batterie 24V : 100kΩ + 10kΩ (rapport 11:1)
 Diviseur feedback : 22kΩ + 2.2kΩ (rapport 11:1)
 Condensateurs électrolytiques 35V sur l'entrée
 Condensateurs céramiques 50V sur la sortie
 Self 100µH 5A pour filtrage
 Diodes Schottky 30BQ100 sur chaque MOSFET
 Régulateur 7805 pour 5V STM32
 Zener 3.3V sur entrée ADC pour protection

Xxxxxxxxxxxxxxxxx
Code Complet pour CubeIDE (STM32F103C8T6) - 12V
Fichier main.c
#include "stm32f1xx.h"
#include <math.h>

// --- CONFIGURATION PINS ---


#define LED_PIN GPIO_PIN_13 // PC13
#define MOSFET_HIGH1_PIN GPIO_PIN_8 // PA8 (TIM1_CH1)
#define MOSFET_LOW1_PIN GPIO_PIN_13 // PB13 (TIM1_CH1N)
#define MOSFET_HIGH2_PIN GPIO_PIN_9 // PA9 (TIM1_CH2)
#define MOSFET_LOW2_PIN GPIO_PIN_14 // PB14 (TIM1_CH2N)
#define BATT_ADC_PIN GPIO_PIN_0 // PA0 (ADC1_IN0)
#define FEEDBACK_ADC_PIN GPIO_PIN_1 // PA1 (ADC1_IN1)

// --- PARAMETRES SPWM ---


#define SPWM_POINTS 400 // Résolution sinus
#define TIM1_PERIOD 2000 // 72MHz / 20kHz = 3600 (ajusté)
#define TIM1_PRESCALER 1 // 72MHz direct
#define DEADTIME_NS 36 // ~500ns à 72MHz

// --- PARAMETRES ALIMENTATION 12V ---


#define VREFINT_CAL_ADDR 0x1FFFF7BA // Calib Vref interne
#define VREFINT_DEFAULT 1200.0f // mV
#define BATT_LOW_THRESHOLD 10.0f // V (low batt 12V)
#define BATT_HIGH_THRESHOLD 14.0f // V (high batt 12V)
#define BATT_ZENER_DROP 0.7f // V (diode zener)

// --- PARAMETRES DIVISEURS DE TENSION ---


#define BATT_DIVIDER_R1 100000.0f // 100kΩ
#define BATT_DIVIDER_R2 10000.0f // 10kΩ
#define BATT_FACTOR (BATT_DIVIDER_R1 + BATT_DIVIDER_R2) /
BATT_DIVIDER_R2 // 11

#define FEEDBACK_DIVIDER_R1 22000.0f // 22kΩ


#define FEEDBACK_DIVIDER_R2 2200.0f // 2.2kΩ
#define FEEDBACK_FACTOR (FEEDBACK_DIVIDER_R1 + FEEDBACK_DIVIDER_R2) /
FEEDBACK_DIVIDER_R2 // 11

// --- PARAMETRES REGULATION ---


#define OUTPUT_VOLTAGE_SET 12.0f // V (consigne 12V)
#define KP 2.0f
#define KI 0.5f
#define KD 0.1f

// --- VARIABLES GLOBALES ---


volatile uint16_t spwm_table[SPWM_POINTS];
volatile uint16_t spwm_index = 0;
volatile float modulation_index = 0.85f;
volatile uint32_t system_tick = 0;
volatile uint16_t adc_batt_value = 0;
volatile uint16_t adc_feedback_value = 0;
volatile float battery_voltage = 0.0f;
volatile float output_voltage = 0.0f;
volatile float error_integral = 0.0f;
volatile float error_prev = 0.0f;
volatile uint8_t low_batt_flag = 0;
volatile uint8_t high_batt_flag = 0;

// --- PROTOTYPES ---


void SystemClock_Config(void);
void GPIO_Init(void);
void TIM1_Init_FullBridge(void);
void TIM2_Init_SPWM_Update(void);
void ADC1_Init(void);
void Generate_SPWM_Table(void);
void Delay_ms(uint32_t ms);
void Update_PID_Controller(void);

// --- MAIN ---


int main(void) {
SystemInit();
SystemClock_Config();
GPIO_Init();
Generate_SPWM_Table();
TIM1_Init_FullBridge();
TIM2_Init_SPWM_Update();
ADC1_Init();

SysTick_Config(72000); // 1ms

while(1) {
// Surveillance batterie toutes les secondes
if((system_tick % 1000) == 0) {
// Calcul tension batterie (12V)
float vref_int = (float)(*(__IO uint16_t*)VREFINT_CAL_ADDR) *
VREFINT_DEFAULT / 4096.0f;
battery_voltage = (adc_batt_value * vref_int / 4096.0f) * 3.3f
* BATT_FACTOR;

// Test low battery


if(battery_voltage < BATT_LOW_THRESHOLD) {
low_batt_flag = 1;
HAL_GPIO_WritePin(GPIOC, LED_PIN, GPIO_PIN_SET); // LED ON
= alerte
} else if(battery_voltage > BATT_HIGH_THRESHOLD) {
high_batt_flag = 1;
HAL_GPIO_WritePin(GPIOC, LED_PIN, GPIO_PIN_SET); // LED ON
= alerte
} else {
low_batt_flag = 0;
high_batt_flag = 0;
}
}

Delay_ms(10);
}
}

// --- GENERATION TABLE SINUS ---


void Generate_SPWM_Table(void) {
float amplitude = (TIM1_PERIOD / 2.0f) * 0.90f;
float center = TIM1_PERIOD / 2.0f;

for(int i = 0; i < SPWM_POINTS; i++) {


float angle = (2.0f * M_PI * i) / SPWM_POINTS;
spwm_table[i] = (uint16_t)(center + (sinf(angle) * amplitude));
}
}

// --- CONFIGURATION TIMER 1 (FULL-BRIDGE) ---


void TIM1_Init_FullBridge(void) {
// Enable TIM1 clock
__HAL_RCC_TIM1_CLK_ENABLE();

TIM_ClockConfigTypeDef sClockSourceConfig = {0};


TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

// Time base configuration


TIM_HandleTypeDef htim1;
[Link] = TIM1;
[Link] = TIM1_PRESCALER - 1;
[Link] = TIM_COUNTERMODE_CENTERALIGNED1;
[Link] = TIM1_PERIOD;
[Link] = TIM_CLOCKDIVISION_DIV1;
[Link] = 0;
HAL_TIM_Base_Init(&htim1);

// PWM configuration for CH1


[Link] = TIM_OCMODE_PWM1;
[Link] = TIM1_PERIOD / 2;
[Link] = TIM_OCPOLARITY_HIGH;
[Link] = TIM_OCNPOLARITY_HIGH;
[Link] = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

// PWM configuration for CH2


HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);

// Break and dead-time configuration


[Link] = TIM_OSSR_ENABLE;
[Link] = TIM_OSSI_ENABLE;
[Link] = TIM_LOCKLEVEL_OFF;
[Link] = DEADTIME_NS / 2;
[Link] = TIM_BREAK_DISABLE;
[Link] = TIM_BREAKPOLARITY_HIGH;
[Link] = TIM_AUTOMATICOUTPUT_ENABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);

HAL_TIM_MspPostInit(&htim1);
HAL_TIM_Base_Start(&htim1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
}

// --- CONFIGURATION TIMER 2 (SPWM UPDATE 50kHz) ---


void TIM2_Init_SPWM_Update(void) {
TIM_HandleTypeDef htim2;
[Link] = TIM2;
[Link] = 0;
[Link] = TIM_COUNTERMODE_UP;
[Link] = 1440 - 1; // 72MHz / 1440 = 50kHz
[Link] = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);

HAL_TIM_Base_Start_IT(&htim2);

HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
// --- INTERRUPTION TIMER 2 ---
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {


if(htim->Instance == TIM2) {
// Mise à jour PWM avec protection 12V
if(!low_batt_flag && !high_batt_flag) {
TIM1->CCR1 = spwm_table[spwm_index]; // M1
TIM1->CCR2 = spwm_table[(spwm_index + SPWM_POINTS/2) %
SPWM_POINTS]; // M3 (180° déphasé)
} else {
TIM1->CCR1 = TIM1_PERIOD / 2;
TIM1->CCR2 = TIM1_PERIOD / 2;
}

spwm_index = (spwm_index + 1) % SPWM_POINTS;


}
}

// --- CONFIGURATION ADC ---


void ADC1_Init(void) {
ADC_HandleTypeDef hadc1;
[Link] = ADC1;
[Link] = ENABLE;
[Link] = ENABLE;
[Link] = DISABLE;
[Link] = ADC_SOFTWARE_START;
[Link] = ADC_DATAALIGN_RIGHT;
[Link] = 2;
HAL_ADC_Init(&hadc1);

// Configuration channel PA0 (Batterie 12V)


ADC_ChannelConfTypeDef sConfig = {0};
[Link] = ADC_CHANNEL_0;
[Link] = 1;
[Link] = ADC_SAMPLETIME_55CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

// Configuration channel PA1 (Feedback)


[Link] = ADC_CHANNEL_1;
[Link] = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

HAL_ADC_Start(&hadc1);
}

// --- INTERRUPTION ADC ---


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if(hadc->Instance == ADC1) {
static uint8_t adc_seq = 0;
if(adc_seq == 0) {
adc_batt_value = HAL_ADC_GetValue(hadc);
adc_seq = 1;
} else {
adc_feedback_value = HAL_ADC_GetValue(hadc);
adc_seq = 0;

// Calcul tension de sortie (12V)


float vref_int = (float)(*(__IO uint16_t*)VREFINT_CAL_ADDR) *
VREFINT_DEFAULT / 4096.0f;
float vfb = (adc_feedback_value * vref_int / 4096.0f) * 3.3f;
output_voltage = vfb * FEEDBACK_FACTOR;

// Régulation PID
Update_PID_Controller();
}
}
}

// --- REGULATION PID ---


void Update_PID_Controller(void) {
static float last_output = TIM1_PERIOD / 2;
float error = OUTPUT_VOLTAGE_SET - output_voltage;

error_integral += error;
if(error_integral > 1000.0f) error_integral = 1000.0f;
if(error_integral < -1000.0f) error_integral = -1000.0f;

float derivative = error - error_prev;


error_prev = error;

float pid_output = KP * error + KI * error_integral + KD * derivative;

// Limitation modulation index


if(pid_output > 0.95f * TIM1_PERIOD/2) pid_output = 0.95f *
TIM1_PERIOD/2;
if(pid_output < -0.95f * TIM1_PERIOD/2) pid_output = -0.95f *
TIM1_PERIOD/2;

// Application modulation
float center = TIM1_PERIOD / 2.0f;
last_output = center + pid_output;

// Limitation safe
if(last_output > TIM1_PERIOD - 100) last_output = TIM1_PERIOD - 100;
if(last_output < 100) last_output = 100;

// Mise à jour directe si pas en période SPWM


TIM1->CCR1 = (uint16_t)last_output;
}

// --- CONFIGURATION GPIO ---


void GPIO_Init(void) {
// Enable GPIO clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();

// PA8 : TIM1_CH1 (M1)


GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = MOSFET_HIGH1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// PA9 : TIM1_CH2 (M3)


GPIO_InitStruct.Pin = MOSFET_HIGH2_PIN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// PB13 : TIM1_CH1N (M2)
GPIO_InitStruct.Pin = MOSFET_LOW1_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// PB14 : TIM1_CH2N (M4)


GPIO_InitStruct.Pin = MOSFET_LOW2_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// PC13 : LED
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

// PA0, PA1 : ADC (input floating)


GPIO_InitStruct.Pin = BATT_ADC_PIN | FEEDBACK_ADC_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// --- INTERRUPTION SYSTICK ---


void SysTick_Handler(void) {
HAL_IncTick();
system_tick++;
}

void Delay_ms(uint32_t ms) {


uint32_t start = system_tick;
while((system_tick - start) < ms);
}

// --- CONFIGURATION HORLOGE ---


void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

// Configure HSE Oscillator


RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.[Link] = RCC_PLL_ON;
RCC_OscInitStruct.[Link] = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.[Link] = RCC_PLL_MUL9;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

// Configure system clock


RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

// Configure Systick
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
Code Complet pour CubeIDE (STM32F103C8T6) - 24V
Fichier main.c
#include "stm32f1xx.h"
#include <math.h>

// --- CONFIGURATION PINS ---


#define LED_PIN GPIO_PIN_13 // PC13
#define MOSFET_HIGH1_PIN GPIO_PIN_8 // PA8 (TIM1_CH1)
#define MOSFET_LOW1_PIN GPIO_PIN_13 // PB13 (TIM1_CH1N)
#define MOSFET_HIGH2_PIN GPIO_PIN_9 // PA9 (TIM1_CH2)
#define MOSFET_LOW2_PIN GPIO_PIN_14 // PB14 (TIM1_CH2N)
#define BATT_ADC_PIN GPIO_PIN_0 // PA0 (ADC1_IN0)
#define FEEDBACK_ADC_PIN GPIO_PIN_1 // PA1 (ADC1_IN1)

// --- PARAMETRES SPWM ---


#define SPWM_POINTS 400 // Résolution sinus
#define TIM1_PERIOD 2000 // 72MHz / 20kHz = 3600 (ajusté)
#define TIM1_PRESCALER 1 // 72MHz direct
#define DEADTIME_NS 36 // ~500ns à 72MHz

// --- PARAMETRES ALIMENTATION 24V ---


#define VREFINT_CAL_ADDR 0x1FFFF7BA // Calib Vref interne
#define VREFINT_DEFAULT 1200.0f // mV
#define BATT_LOW_THRESHOLD 20.0f // V (low batt 24V)
#define BATT_HIGH_THRESHOLD 30.0f // V (high batt 24V)
#define BATT_ZENER_DROP 0.7f // V (diode zener)

// --- PARAMETRES DIVISEURS DE TENSION ---


#define BATT_DIVIDER_R1 100000.0f // 100kΩ
#define BATT_DIVIDER_R2 10000.0f // 10kΩ
#define BATT_FACTOR (BATT_DIVIDER_R1 + BATT_DIVIDER_R2) /
BATT_DIVIDER_R2 // 11

#define FEEDBACK_DIVIDER_R1 22000.0f // 22kΩ


#define FEEDBACK_DIVIDER_R2 2200.0f // 2.2kΩ
#define FEEDBACK_FACTOR (FEEDBACK_DIVIDER_R1 + FEEDBACK_DIVIDER_R2) /
FEEDBACK_DIVIDER_R2 // 11

// --- PARAMETRES REGULATION ---


#define OUTPUT_VOLTAGE_SET 24.0f // V (consigne 24V)
#define KP 2.0f
#define KI 0.5f
#define KD 0.1f

// --- VARIABLES GLOBALES ---


volatile uint16_t spwm_table[SPWM_POINTS];
volatile uint16_t spwm_index = 0;
volatile float modulation_index = 0.85f;
volatile uint32_t system_tick = 0;
volatile uint16_t adc_batt_value = 0;
volatile uint16_t adc_feedback_value = 0;
volatile float battery_voltage = 0.0f;
volatile float output_voltage = 0.0f;
volatile float error_integral = 0.0f;
volatile float error_prev = 0.0f;
volatile uint8_t low_batt_flag = 0;
volatile uint8_t high_batt_flag = 0;

// --- PROTOTYPES ---


void SystemClock_Config(void);
void GPIO_Init(void);
void TIM1_Init_FullBridge(void);
void TIM2_Init_SPWM_Update(void);
void ADC1_Init(void);
void Generate_SPWM_Table(void);
void Delay_ms(uint32_t ms);
void Update_PID_Controller(void);

// --- MAIN ---


int main(void) {
SystemInit();
SystemClock_Config();
GPIO_Init();
Generate_SPWM_Table();
TIM1_Init_FullBridge();
TIM2_Init_SPWM_Update();
ADC1_Init();

SysTick_Config(72000); // 1ms

while(1) {
// Surveillance batterie toutes les secondes
if((system_tick % 1000) == 0) {
// Calcul tension batterie (24V)
float vref_int = (float)(*(__IO uint16_t*)VREFINT_CAL_ADDR) *
VREFINT_DEFAULT / 4096.0f;
battery_voltage = (adc_batt_value * vref_int / 4096.0f) * 3.3f
* BATT_FACTOR;

// Test low battery


if(battery_voltage < BATT_LOW_THRESHOLD) {
low_batt_flag = 1;
HAL_GPIO_WritePin(GPIOC, LED_PIN, GPIO_PIN_SET); // LED ON
= alerte
} else if(battery_voltage > BATT_HIGH_THRESHOLD) {
high_batt_flag = 1;
HAL_GPIO_WritePin(GPIOC, LED_PIN, GPIO_PIN_SET); // LED ON
= alerte
} else {
low_batt_flag = 0;
high_batt_flag = 0;
}
}

Delay_ms(10);
}
}

// --- GENERATION TABLE SINUS ---


void Generate_SPWM_Table(void) {
float amplitude = (TIM1_PERIOD / 2.0f) * 0.90f;
float center = TIM1_PERIOD / 2.0f;

for(int i = 0; i < SPWM_POINTS; i++) {


float angle = (2.0f * M_PI * i) / SPWM_POINTS;
spwm_table[i] = (uint16_t)(center + (sinf(angle) * amplitude));
}
}

// --- CONFIGURATION TIMER 1 (FULL-BRIDGE) ---


void TIM1_Init_FullBridge(void) {
// Enable TIM1 clock
__HAL_RCC_TIM1_CLK_ENABLE();

TIM_ClockConfigTypeDef sClockSourceConfig = {0};


TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

// Time base configuration


TIM_HandleTypeDef htim1;
[Link] = TIM1;
[Link] = TIM1_PRESCALER - 1;
[Link] = TIM_COUNTERMODE_CENTERALIGNED1;
[Link] = TIM1_PERIOD;
[Link] = TIM_CLOCKDIVISION_DIV1;
[Link] = 0;
HAL_TIM_Base_Init(&htim1);

// PWM configuration for CH1


[Link] = TIM_OCMODE_PWM1;
[Link] = TIM1_PERIOD / 2;
[Link] = TIM_OCPOLARITY_HIGH;
[Link] = TIM_OCNPOLARITY_HIGH;
[Link] = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

// PWM configuration for CH2


HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);

// Break and dead-time configuration


[Link] = TIM_OSSR_ENABLE;
[Link] = TIM_OSSI_ENABLE;
[Link] = TIM_LOCKLEVEL_OFF;
[Link] = DEADTIME_NS / 2;
[Link] = TIM_BREAK_DISABLE;
[Link] = TIM_BREAKPOLARITY_HIGH;
[Link] = TIM_AUTOMATICOUTPUT_ENABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);

HAL_TIM_MspPostInit(&htim1);
HAL_TIM_Base_Start(&htim1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
}

// --- CONFIGURATION TIMER 2 (SPWM UPDATE 50kHz) ---


void TIM2_Init_SPWM_Update(void) {
TIM_HandleTypeDef htim2;
[Link] = TIM2;
[Link] = 0;
[Link] = TIM_COUNTERMODE_UP;
[Link] = 1440 - 1; // 72MHz / 1440 = 50kHz
[Link] = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);

HAL_TIM_Base_Start_IT(&htim2);

HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
// --- INTERRUPTION TIMER 2 ---
void TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim2);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {


if(htim->Instance == TIM2) {
// Mise à jour PWM avec protection 24V
if(!low_batt_flag && !high_batt_flag) {
TIM1->CCR1 = spwm_table[spwm_index]; // M1
TIM1->CCR2 = spwm_table[(spwm_index + SPWM_POINTS/2) %
SPWM_POINTS]; // M3 (180° déphasé)
} else {
TIM1->CCR1 = TIM1_PERIOD / 2;
TIM1->CCR2 = TIM1_PERIOD / 2;
}

spwm_index = (spwm_index + 1) % SPWM_POINTS;


}
}

// --- CONFIGURATION ADC ---


void ADC1_Init(void) {
ADC_HandleTypeDef hadc1;
[Link] = ADC1;
[Link] = ENABLE;
[Link] = ENABLE;
[Link] = DISABLE;
[Link] = ADC_SOFTWARE_START;
[Link] = ADC_DATAALIGN_RIGHT;
[Link] = 2;
HAL_ADC_Init(&hadc1);

// Configuration channel PA0 (Batterie 24V)


ADC_ChannelConfTypeDef sConfig = {0};
[Link] = ADC_CHANNEL_0;
[Link] = 1;
[Link] = ADC_SAMPLETIME_55CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

// Configuration channel PA1 (Feedback)


[Link] = ADC_CHANNEL_1;
[Link] = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

HAL_ADC_Start(&hadc1);
}

// --- INTERRUPTION ADC ---


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if(hadc->Instance == ADC1) {
static uint8_t adc_seq = 0;
if(adc_seq == 0) {
adc_batt_value = HAL_ADC_GetValue(hadc);
adc_seq = 1;
} else {
adc_feedback_value = HAL_ADC_GetValue(hadc);
adc_seq = 0;

// Calcul tension de sortie (24V)


float vref_int = (float)(*(__IO uint16_t*)VREFINT_CAL_ADDR) *
VREFINT_DEFAULT / 4096.0f;
float vfb = (adc_feedback_value * vref_int / 4096.0f) * 3.3f;
output_voltage = vfb * FEEDBACK_FACTOR;

// Régulation PID
Update_PID_Controller();
}
}
}

// --- REGULATION PID ---


void Update_PID_Controller(void) {
static float last_output = TIM1_PERIOD / 2;
float error = OUTPUT_VOLTAGE_SET - output_voltage;

error_integral += error;
if(error_integral > 1000.0f) error_integral = 1000.0f;
if(error_integral < -1000.0f) error_integral = -1000.0f;

float derivative = error - error_prev;


error_prev = error;

float pid_output = KP * error + KI * error_integral + KD * derivative;

// Limitation modulation index


if(pid_output > 0.95f * TIM1_PERIOD/2) pid_output = 0.95f *
TIM1_PERIOD/2;
if(pid_output < -0.95f * TIM1_PERIOD/2) pid_output = -0.95f *
TIM1_PERIOD/2;

// Application modulation
float center = TIM1_PERIOD / 2.0f;
last_output = center + pid_output;

// Limitation safe
if(last_output > TIM1_PERIOD - 100) last_output = TIM1_PERIOD - 100;
if(last_output < 100) last_output = 100;

// Mise à jour directe si pas en période SPWM


TIM1->CCR1 = (uint16_t)last_output;
}

// --- CONFIGURATION GPIO ---


void GPIO_Init(void) {
// Enable GPIO clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();

// PA8 : TIM1_CH1 (M1)


GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = MOSFET_HIGH1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// PA9 : TIM1_CH2 (M3)


GPIO_InitStruct.Pin = MOSFET_HIGH2_PIN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// PB13 : TIM1_CH1N (M2)
GPIO_InitStruct.Pin = MOSFET_LOW1_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// PB14 : TIM1_CH2N (M4)


GPIO_InitStruct.Pin = MOSFET_LOW2_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// PC13 : LED
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

// PA0, PA1 : ADC (input floating)


GPIO_InitStruct.Pin = BATT_ADC_PIN | FEEDBACK_ADC_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// --- INTERRUPTION SYSTICK ---


void SysTick_Handler(void) {
HAL_IncTick();
system_tick++;
}

void Delay_ms(uint32_t ms) {


uint32_t start = system_tick;
while((system_tick - start) < ms);
}

// --- CONFIGURATION HORLOGE ---


void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

// Configure HSE Oscillator


RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.[Link] = RCC_PLL_ON;
RCC_OscInitStruct.[Link] = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.[Link] = RCC_PLL_MUL9;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

// Configure system clock


RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

// Configure Systick
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
Configuration IOC (CubeMX) - Identique pour les deux versions

Fichier SPI avec configurations :

Pins utilisées (identiques pour 12V et 24V) :

 PA8 : TIM1_CH1 (MOSFET M1)


 PA9 : TIM1_CH2 (MOSFET M3)
 PB13 : TIM1_CH1N (MOSFET M2)
 PB14 : TIM1_CH2N (MOSFET M4)
 PA0 : ADC1_IN0 (Tension batterie)
 PA1 : ADC1_IN1 (Feedback sortie)
 PC13 : LED statut

Configuration IOC :

1. System Core > SYS


o RCC: HSE = Crystal/Ceramic Resonator
o Clock Configuration: HCLK=72MHz, APB1=36MHz, APB2=72MHz

2. TIM1
o Mode: Center-aligned PWM
o Channels: CH1, CH1N, CH2, CH2N
o Prescaler: 0
o Counter Period: 2000
o Repetition Counter: 0
o Dead Time: 36 (500ns)

3. TIM2
o Mode: Up-counter
o Prescaler: 0
o Counter Period: 1440
o Interrupt: Enable

4. ADC1
o Mode: Continuous conversion
o Channels: PA0 (Rank 1), PA1 (Rank 2)
o Sample Time: 55.5 cycles

5. GPIO
o PA8, PA9: AF Push-Pull, High speed
o PB13, PB14: AF Push-Pull, High speed
o PA0, PA1: Analog mode
o PC13: Output Push-Pull, Low speed

Rappels des Blocs de Code - Version 12V

1. Génération SPWM
void Generate_SPWM_Table(void) {
// Crée 400 points d'un sinus centré
// Amplitude = 90% de la période TIM1
// Formule : centre + sin(angle) × amplitude
}

Explication : Pré-calcule une table de 400 points représentant un demi-onde sinusoïdale pour
une modulation de largeur d'impulsion.

2. Timer 1 Full-Bridge
void TIM1_Init_FullBridge(void) {
// Configure 4 MOSFET en pont complet
// Center-aligned pour commutation symétrique
// Deadtime intégrée pour éviter les courts-circuits
}

Explication : Initialise le timer pour contrôler 4 MOSFET en configuration pont complet avec
protection deadtime.

3. Timer 2 Update 50kHz


void TIM2_Init_SPWM_Update(void) {
// Fréquence 50kHz = 20kHz × 400 points
// Interruption précise pour mise à jour SPWM
}

Explication : Crée une interruption à 50kHz pour mettre à jour les registres PWM avec les
points SPWM.

4. ADC en Continu
void ADC1_Init(void) {
// Conversion continue batterie 12V + feedback
// Callback pour traitement des valeurs
}

Explication : Configure l'ADC pour mesurer en continu la tension batterie 12V et la tension
de sortie.

5. Régulation PID
void Update_PID_Controller(void) {
// Calcul erreur = consigne - réel
// Intégrale et dérivée pour stabilité
// Limitation sortie pour protection
}

Explication : Implémente un correcteur PID pour maintenir la tension de sortie à 12V malgré
les variations.

Rappels des Blocs de Code - Version 24V

1. Génération SPWM
void Generate_SPWM_Table(void) {
// Crée 400 points d'un sinus centré
// Amplitude = 90% de la période TIM1
// Formule : centre + sin(angle) × amplitude
}

Explication : Identique à la version 12V, pré-calcule une table SPWM.

2. Timer 1 Full-Bridge
void TIM1_Init_FullBridge(void) {
// Configure 4 MOSFET en pont complet
// Center-aligned pour commutation symétrique
// Deadtime intégrée pour éviter les courts-circuits
}

Explication : Identique à la version 12V, initialise le timer pour 4 MOSFET.

3. Timer 2 Update 50kHz


void TIM2_Init_SPWM_Update(void) {
// Fréquence 50kHz = 20kHz × 400 points
// Interruption précise pour mise à jour SPWM
}

Explication : Identique à la version 12V, crée une interruption à 50kHz.

4. ADC en Continu
void ADC1_Init(void) {
// Conversion continue batterie 24V + feedback
// Callback pour traitement des valeurs
}

Explication : Configure l'ADC pour mesurer en continu la tension batterie 24V et la tension
de sortie.

5. Régulation PID
void Update_PID_Controller(void) {
// Calcul erreur = consigne - réel
// Intégrale et dérivée pour stabilité
// Limitation sortie pour protection
}

Explication : Identique à la version 12V, mais maintient 24V au lieu de 12V.

Implémentations IOC - Identiques pour les deux versions

1. Project Manager
o MCU: STM32F103C8Tx
o Clock: 72MHz from HSE
o Code Generator: Generate peripheral initialization as a pair of '.c/.h' files
2. Pinout & Configuration
o PA8: TIM1_CH1 (GPIO_Output)
o PA9: TIM1_CH2 (GPIO_Output)
o PB13: TIM1_CH1N (GPIO_Output)
o PB14: TIM1_CH2N (GPIO_Output)
o PA0: ADC1_IN0 (Analog)
o PA1: ADC1_IN1 (Analog)
o PC13: GPIO_Output

3. Configuration Timers
o TIM1: PWM Generation CH1, CH2, CH1N, CH2N
o TIM2: Time Base, Interrupt

4. Configuration ADC
o ADC1: Continuous Mode, Scan Mode
o Channels: PA0, PA1

5. NVIC Settings
o TIM2 global interrupt: Priority 2
o SysTick: Default priority

Pins Utilisés - Identiques pour les deux versions


Pin Fonction Type

PA8 M1 (High-side) AF Output

PA9 M3 (High-side) AF Output

PB13 M2 (Low-side) AF Output

PB14 M4 (Low-side) AF Output

PA0 Batterie Analog Input

PA1 Feedback Analog Input

PC13 LED Digital Output

Avantages - Version 12V

1. Tension d'entrée standard : Compatible avec batteries 12V plomb/acide


2. Courant plus élevé : Plus de puissance disponible
3. Composants moins chers : Condensateurs et diodes 16V suffisent
4. Simplicité : Circuit de protection plus simple
5. Efficacité : Moins de pertes en conduction

Avantages - Version 24V

1. Tension d'entrée élevée : Compatible avec batteries Li-ion, 2x12V


2. Courant réduit : Même puissance avec moins de courant
3. Câbles plus fins : Moins de section nécessaire
4. Perte Joule réduite : I²R plus faible
5. Flexibilité : Peut accepter 2 batteries 12V en série

Rappel Global pour Technicien

Version 12V :

 Alimentation : 10-14V batterie 12V


 Sortie : 12V régulée par PID
 Diviseur batterie : 100kΩ + 10kΩ (rapport 11:1)
 Diviseur feedback : 22kΩ + 2.2kΩ (rapport 11:1)
 Protection : Low battery (10V), High battery (14V)

Version 24V :

 Alimentation : 20-30V batterie 24V


 Sortie : 24V régulée par PID
 Diviseur batterie : 100kΩ + 10kΩ (rapport 11:1)
 Diviseur feedback : 22kΩ + 2.2kΩ (rapport 11:1)
 Protection : Low battery (20V), High battery (30V)

Points communs :

 Microcontrôleur : STM32F103C8T6 @ 72MHz


 PWM : 20kHz avec 400 points de résolution
 Contrôle : 4 MOSFET IRF en pont complet
 Régulation : PID avec intégrale et dérivée
 Protection : Deadtime 500ns, low/high battery cut-off
 LED : PC13 pour statut

Pour implémentation physique :

 Condensateurs électrolytiques 35V sur l'entrée


 Condensateurs céramiques 50V sur la sortie
 Self 100µH 5A pour filtrage
 Diodes Schottky 30BQ100 sur chaque MOSFET
 Régulateur 7805 pour 5V STM32
 Zener 3.3V sur entrée ADC pour protection

Les deux codes sont indépendants et ne présentent aucun conflit technique. Chaque version
est optimisée pour sa tension d'entrée spécifique avec les paramètres de protection et de
régulation adaptés.

Vous aimerez peut-être aussi