/* * config.c * * Created on: 28 mai 2026 * Author: innotex */ #include #include uint32_t index_time = 0; uint32_t nbr_un = 0; uint32_t nbr_un_final = 0; volatile uint8_t finReception = 0; volatile uint32_t it_count = 0; void motor_init(void) { // Init des clks sur portB et A RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN); GPIOA->MODER &= ~INIT_MODDER_MOTOR_PBA_MSK; GPIOA->MODER |= INIT_MODDER_MOTOR_PBA; GPIOB->MODER &= ~INIT_MODDER_MOTOR_PBB_MSK; GPIOB->MODER |= INIT_MODDER_MOTOR_PBB; GPIOA->OSPEEDR &= ~INIT_OSPEEDR_MOTOR_PBA_MSK; GPIOA->OSPEEDR |= INIT_OSPEEDR_MOTOR_PBA; GPIOB->OSPEEDR &= ~INIT_OSPEEDR_MOTOR_PBB_MSK; GPIOB->OSPEEDR |= INIT_OSPEEDR_MOTOR_PBB; GPIOA->PUPDR &= ~INIT_PUPDR_MOTOR_PBA_MSK; GPIOA->PUPDR &= ~INIT_PUPDR_MOTOR_PBB_MSK; GPIOA->ODR &= ~(GPIO_ODR_ODR_10); GPIOB->ODR &= ~(GPIO_ODR_ODR_10 | GPIO_ODR_ODR_5 | GPIO_ODR_ODR_4); } void init_Timer_RoueDroit(char sens, uint8_t vitesse) { RCC->APB1ENR |= (RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN); GPIOB->MODER &= ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER10); GPIOB->MODER |= (GPIO_MODER_MODER5_1 | GPIO_MODER_MODER10_1); // PB5 et PB10 configuré en alterned function // Configuration du TIM3 CH2 sur PB5 sur AF02. GPIOB->AFR[0] &= ~GPIO_AFRL_AFSEL5; // Nettoyage des 4 bits GPIOB->AFR[0] |= (2 << GPIO_AFRL_AFSEL5_Pos); // Application de AF2 // PB10 -> AF01 (TIM2). En binaire AF01 s'écrit "0001". On active donc le bit 0. GPIOB->AFR[1] &= ~GPIO_AFRH_AFSEL10; // Nettoyage des 4 bits GPIOB->AFR[1] |= (1 << GPIO_AFRH_AFSEL10_Pos); // Application de AF1 TIM2->PSC = 35; //PSC = f_horloge/f_tick - 1 TIM2->ARR = 99; // résolution - 1 TIM3->PSC = 35; //PSC = f_horloge/f_tick - 1 TIM3->ARR = 99; // résolution - 1 TIM2->CR1 &= ~TIM_CR1_CMS; // Edge-aligned mode compteur compte de à -> 99 puis retourne à 0 TIM2->CR1 &= ~TIM_CR1_DIR; // Counter used as upcounter TIM3->CR1 &= ~TIM_CR1_CMS; // Edge-aligned mode compteur compte de à -> 99 puis retourne à 0 TIM3->CR1 &= ~TIM_CR1_DIR; // Counter used as upcounter TIM2->CR1 |= TIM_CR1_ARPE; TIM3->CR1 |= TIM_CR1_ARPE; TIM2->CCMR2 &= ~TIM_CCMR2_CC3S; TIM3->CCMR1 &= ~TIM_CCMR1_CC1S; TIM2->CCMR2 &= ~TIM_CCMR2_OC3M; TIM2->CCMR2 |= (6 << TIM_CCMR2_OC3M_Pos); TIM3->CCMR1 &= ~TIM_CCMR1_OC2M; TIM3->CCMR1 |= (6 << TIM_CCMR1_OC2M_Pos); // Activation du Preload pour le Canal 2 du Timer 3 TIM3->CCMR1 |= TIM_CCMR1_OC2PE; // Activation du Preload pour le Canal 3 du Timer 2 TIM2->CCMR2 |= TIM_CCMR2_OC3PE; TIM2->CCER |= TIM_CCER_CC3E; // Activer la sortie du Canal 3 TIM2->CCR3 = vitesse; // Vitesse initiale à 0 TIM2->CR1 |= TIM_CR1_CEN; // Démarrer le Timer 2 TIM3->CCER |= TIM_CCER_CC2E; // Activer la sortie du Canal 2 (Capture/Compare 2 Enable) TIM3->CCR2 = 0; // Vitesse initiale à 0 TIM3->CR1 |= TIM_CR1_CEN; // Démarrer le Timer 3 (Counter ENable) } void init_Timer_RoueGauche(char sens, uint8_t vitesse) { // Activation des horloges RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN); RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // Configuration des MODER GPIOB->MODER &= ~GPIO_MODER_MODER4; GPIOB->MODER |= GPIO_MODER_MODER4_1; // PB4 en AF GPIOA->MODER &= ~GPIO_MODER_MODER10; GPIOA->MODER |= GPIO_MODER_MODER10_1; // PA10 en AF // Configuration des AFR // PB4 -> TIM3 CH1 (AF02) GPIOB->AFR[0] &= ~GPIO_AFRL_AFSEL4; GPIOB->AFR[0] |= (2 << GPIO_AFRL_AFSEL4_Pos); // PA10 -> TIM1 CH3 (AF01) GPIOA->AFR[1] &= ~GPIO_AFRH_AFSEL10; GPIOA->AFR[1] |= (1 << GPIO_AFRH_AFSEL10_Pos); // Paramétrage Timers TIM3->PSC = 35; TIM3->ARR = 99; TIM3->CR1 |= TIM_CR1_ARPE; TIM1->PSC = 35; TIM1->ARR = 99; TIM1->CR1 |= TIM_CR1_ARPE; // --- TIM3 CH1 (PB4) --- TIM3->CCMR1 &= ~TIM_CCMR1_OC1M; TIM3->CCMR1 |= (6 << TIM_CCMR1_OC1M_Pos) | TIM_CCMR1_OC1PE; TIM3->CCER |= TIM_CCER_CC1E; // Activer le Canal 1 // --- TIM1 CH3 (PA10) --- TIM1->CCMR2 &= ~TIM_CCMR2_OC3M; TIM1->CCMR2 |= (6 << TIM_CCMR2_OC3M_Pos) | TIM_CCMR2_OC3PE; TIM1->CCER |= TIM_CCER_CC3E; // Activer le Canal 3 TIM1->BDTR |= TIM_BDTR_MOE; // OBLIGATOIRE POUR TIM1 // Initialisation vitesses TIM3->CCR1 = 0; // Utilise CCR1 pour canal 1 TIM1->CCR3 = vitesse; // Utilise CCR3 pour canal 3 // Démarrage TIM3->CR1 |= TIM_CR1_CEN; TIM1->CR1 |= TIM_CR1_CEN; } /* * INIT US : * PA1 : TIM2_CH2 : AF01 * PA5 : TIM2_CH1 / ETR : AF01 * PA8 : TIM1_CH1 : AF01 * PA12 : TIM1_ETR AF01 */ void InitGPIOUS(void) { // 1. Activer l'horloge GPIOA RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // 2. Configuration des MODER // Nettoyage complet des bits pour PA1, PA5, PA8, PA12 GPIOA->MODER &= ~(GPIO_MODER_MODER1 | GPIO_MODER_MODER5 | GPIO_MODER_MODER8 | GPIO_MODER_MODER12); // PA1 en AF (0b10), PA5 en Output (0b01), PA12 en Output (0b01), PA8 en Input (0b00) GPIOA->MODER |= (2 << GPIO_MODER_MODER1_Pos) | (1 << GPIO_MODER_MODER5_Pos) | (1 << GPIO_MODER_MODER12_Pos); GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED1_Msk |GPIO_OSPEEDR_OSPEED5_Msk | GPIO_OSPEEDR_OSPEED12_Msk); GPIOA->OSPEEDR |= (2 << GPIO_OSPEEDR_OSPEED1_Pos | 2 << GPIO_OSPEEDR_OSPEED5_Pos | 2 << GPIO_OSPEEDR_OSPEED12_Pos); GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD8_Msk); GPIOA->PUPDR |= (2 << GPIO_PUPDR_PUPD8_Pos); // 3. Configuration AF pour PA1 (TIM2_CH2 est AF01) GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL1; GPIOA->AFR[0] |= (1 << GPIO_AFRL_AFSEL1_Pos); } void InitTimerUS(void) { // 1. Horloge TIM2 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 2. Base de temps : Te = 100 µs @ 180 MHz TIM2->PSC = 179; // 180 MHz / 180 = 1 MHz TIM2->ARR = 99; // 1 MHz / 100 = 10 kHz TIM2->CR1 |= TIM_CR1_ARPE; // preload ARR // 3. Canal 2 (PA1) en PWM mode 1 -> validation étape 1 TIM2->CCMR1 &= ~TIM_CCMR1_CC2S; // CC2 en sortie TIM2->CCMR1 &= ~TIM_CCMR1_OC2M; TIM2->CCMR1 |= (6 << TIM_CCMR1_OC2M_Pos); // PWM mode 1 TIM2->CCMR1 |= TIM_CCMR1_OC2PE; // preload CCR2 TIM2->CCER |= TIM_CCER_CC2E; // activer sortie OC2 TIM2->CCR2 = 50; // 50 % de 100 // 4. Interruption de débordement TIM2->DIER |= TIM_DIER_UIE; NVIC_EnableIRQ(TIM2_IRQn); // 6. Démarrage TIM2->CR1 |= TIM_CR1_CEN; } void UltraSoundMgt(void) { if (index_time < 500) { // 100*10⁽-6) * 500 = 0.05 soit 50ms (période de l'US) if (index_time == 0) { GPIOA->ODR |= GPIO_ODR_ODR_12; // Trig = 1 nbr_un = 0; } else if (index_time == 1) { GPIOA->ODR &= ~GPIO_ODR_ODR_12; // Trig = 0 } else { if (GPIOA->IDR & GPIO_IDR_IDR_8) // lecture Echo nbr_un++; } index_time++; } else { nbr_un_final = nbr_un; finReception = 1; index_time = 0; } } void TIM2_IRQHandler(void) { // On vérifie si c'est bien l'interruption de mise à jour (Update) du Timer 2 if (TIM2->SR & TIM_SR_UIF) { // 1. Reset au niveau du périphérique (Timer 2) TIM2->SR &= ~TIM_SR_UIF; // 2. Reset au niveau du processeur (NVIC) NVIC_ClearPendingIRQ(TIM2_IRQn); // Exécution de ta machine d'état UltraSoundMgt(); } } /** * Pilote le sens et la vitesse du moteur gauche * @param sens : 'A' pour AVANT (PB4 actif), 'R' pour RECULER (PA10 actif) * @param vitesse : valeur de 0 à 99 */ void set_RoueGauche_Sens(int sens, uint8_t vitesse) { if (sens == AVANCE) // Marche avant { TIM3->CCR1 = vitesse; // PWM sur PB4 TIM1->CCR3 = 0; // PA10 à 0 } else if (sens == RECUL) // Marche arrière { TIM3->CCR1 = 0; // PB4 à 0 TIM1->CCR3 = vitesse; // PWM sur PA10 } else // Arrêt { TIM3->CCR1 = 0; TIM1->CCR3 = 0; } } uint32_t ComputeDistance(uint32_t nbrUnFinal) { return (nbrUnFinal * 100u) / 59u; // ≈ /58.8235 }