#include #include #include //Il faut trouver le signal //On est à Timer 2 static void (*TIM2_Appel)(void) = 0; void Timer_Init(TIM_TypeDef *Timer, unsigned short Autoreload, unsigned short Prescaler){ if (Timer == TIM1) { RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; //L'horloge est enabléd } else if (Timer == TIM2) { TIM2->CR1 |= TIM_CR1_CEN; //On enable l'horloge interne RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; } else if (Timer == TIM3) { RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; } else if (Timer == TIM4) { RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; } Timer->ARR |= Autoreload; Timer->PSC |= Prescaler; } //La fonction TIM2_IRQHandler s'utilise dans le processeur, on l'a juste redifint, tel qu'à chaque overflow on met un bit 1 dans GPIOA_ODR void TIM2_IRQHandler(void) { //On redefinit le IRQHandler qui est déjà ecrit dans le code source if (TIM2->SR & TIM_SR_UIF) { //On met le bit de overflow à un dès qu'on a overflow TIM2->SR &= ~TIM_SR_UIF; //Remise à zero if (TIM2_Appel){TIM2_Appel();} } } void MyTimer_ActiveIT(TIM_TypeDef * Timer, char Prio, void(*Interrupt_fonc)(void)){ //On veut créer une fonction qui envoie un signal au cas où il y a debordement, avec une prioritaire, 0 plus importante 15 moins importante if (Timer == TIM2){ TIM2_Appel = Interrupt_fonc; NVIC_EnableIRQ(TIM2_IRQn); NVIC_SetPriority(TIM2_IRQn, Prio); TIM2->DIER |= TIM_DIER_UIE; //Le registre DIER(Interrupt Enable Register) est mis au bit Update Interrupt, qui se commute lors d'un overflow TIM2->CR1 |= TIM_CR1_CEN; //Clock Enable } } //Fonction qui permet de clignoter le DEL à un pulse volue (Sinusoïdale) //Si le sinus est haut(haute tension) le Duty Cicle est proche de 100%, //si le sinus est bas (vers la tension la plus basse) le Duty Cycle est vers 0% //On s'applique sur un plage de [0V; 3.3V] void MyTimer_PWM(TIM_TypeDef * Timer , int Channel){ int pwrmd; #if POWERMODE //Powermode 1 pwrmd = 0b110; #else pwrmd = 0b111; //Powermode 2 #endif if (Channel == 1){ Timer->CCMR1 &= ~(0b111<<4); //On clear les trois bits qui sont de pwm Timer->CCMR1 |= (pwrmd<<4); //On affecte le powermode au bits de lecture pour le µ-controlleur Timer->CCMR1 |= TIM_CCMR1_OC1PE; //Update preload, il n'affecte pas le valeur avant que la prochaine cycle Timer->CCER = TIM_CCER_CC1E; //Enable le pin voulu basculer } else if (Channel == 2){ Timer->CCMR1 &= ~(0b111<<12); //Le TIMx_CCMR1 configure deux channels, de bit [6:4] CH1, [14:12] CH2 (OC2M = Output Channel 2 ) Timer->CCMR1 |= (pwrmd<<12); Timer->CCMR1 |= TIM_CCMR1_OC2PE; Timer->CCER |= TIM_CCER_CC2E; } else if (Channel == 3){ Timer->CCMR1 &= ~(0b111<<4); Timer->CCMR2 |= (pwrmd<<4); Timer->CCMR2 |= TIM_CCMR2_OC3PE; Timer->CCER |= TIM_CCER_CC3E; } else if (Channel == 4){ Timer->CCMR1 &= ~(0b111<<12); Timer->CCMR2 |= (pwrmd<<12); Timer->CCMR2 |= TIM_CCMR2_OC4PE; Timer->CCER |= TIM_CCER_CC4E; } //En dessous d'ici, on a l'aide du plus gentil chat que je connais // Enable auto-reload preload -- //Ensures that your initial configuration — PWM mode, duty cycle, period — actually takes effect before the timer starts counting. Timer->CR1 |= TIM_CR1_ARPE; // Force update event to load ARR and CCR values immediately Timer->EGR |= TIM_EGR_UG; // Start the timer Timer->CR1 |= TIM_CR1_CEN; switch (Channel) { case 1: if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<0*4); GPIOA->CRH |= (0xA<<0*4); TIM1->BDTR |= 1<<15; } if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<0*4); GPIOA->CRL |= (0xA<<0*4);} if (Timer == TIM3){GPIOA->CRL &= ~(0xF<<6*4); GPIOA->CRL |= (0xA<<6*4);} if (Timer == TIM4){GPIOB->CRL &= ~(0xF<<5*4); GPIOB->CRL |= (0xA<<5*4);} break; case 2: if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<1*4); GPIOA->CRL |= (0xA<<1*4); TIM1->BDTR |= 1<<15;} if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<1*4); GPIOA->CRL |= (0xA<<1*4);} if (Timer == TIM3){GPIOA->CRL &= ~(0xF<<7*4); GPIOA->CRL |= (0xA<<7*4);} if (Timer == TIM4){GPIOB->CRL &= ~(0xF<<7*4); GPIOB->CRL |= (0xA<<7*4);} break; case 3: if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<2*4); GPIOA->CRH |= (0xA<<2*4); TIM1->BDTR |= 1<<15;} if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<2*4); GPIOA->CRL |= (0xA<<2*4);} if (Timer == TIM3){GPIOB->CRL &= ~(0xF<<0*4); GPIOB->CRL |= (0xA<<0*4);} if (Timer == TIM4){GPIOB->CRH &= ~(0xF<<0*4); GPIOB->CRH |= (0xA<<0*4);} break; case 4: if (Timer == TIM1){GPIOA->CRH &= ~(0xF<<3*4); GPIOA->CRH |= (0xA<<3*4); TIM1->BDTR |= 1<<15;} if (Timer == TIM2){GPIOA->CRL &= ~(0xF<<3*4); GPIOA->CRL |= (0xA<<3*4);} if (Timer == TIM3){GPIOB->CRL &= ~(0xF<<1*4); GPIOB->CRL |= (0xA<<1*4);} if (Timer == TIM4){GPIOB->CRH &= ~(0xF<<1*4); GPIOB->CRH |= (0xA<<1*4);} } } //Une fonction qui met le bon PWM volue int Set_DutyCycle_PWM(TIM_TypeDef *Timer, int Channel, int DutyC){ int CCR_VAL = (ARR_VAL + 1) * DutyC / 100; //ARR_VAL déjà definie switch (Channel){ case 1: Timer->CCR1 = CCR_VAL; case 2: Timer->CCR2 = CCR_VAL; case 3: Timer->CCR3 = CCR_VAL; case 4: Timer->CCR4 = CCR_VAL; default: break; } return 0; Timer->EGR |= TIM_EGR_UG; }