// 6B ukázka použití Compare kanálů k časování pomocí přerušení // každou vteřinu udělá krátký "dvojblik" s LED na PC9 #include "stm32f0xx.h" #include "stm32f0xx_ll_bus.h" #include "stm32f0xx_ll_rcc.h" #include "stm32f0xx_ll_gpio.h" #include "stm32f0xx_ll_utils.h" #include "stm32f0xx_ll_tim.h" void init_clock(void); void init_gpio(void); void init_tim3(void); int main(void){ init_clock(); // 48MHz (HSE bypass) init_gpio(); // LED na PC9 init_tim3(); while (1){ // není co dělat... } } void TIM3_IRQHandler(void){ // teď musíme rozpoznat která ze čtyř událostí vyvolala rutinu přerušení if(LL_TIM_IsActiveFlag_CC1(TIM3)){ // je to compare událost prvního kanálu ? LL_TIM_ClearFlag_CC1(TIM3); // událost jsme obsloužili, mažeme její vlajku LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_9); // rozsviť LED } if(LL_TIM_IsActiveFlag_CC2(TIM3)){ // je to compare událost druhého kanálu ? LL_TIM_ClearFlag_CC2(TIM3); // událost jsme obsloužili, mažeme její vlajku LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_9); // zhasni LED } if(LL_TIM_IsActiveFlag_CC3(TIM3)){ // je to compare událost třetího kanálu ? LL_TIM_ClearFlag_CC3(TIM3); // událost jsme obsloužili, mažeme její vlajku LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_9); // zase rozsviť LED } if(LL_TIM_IsActiveFlag_UPDATE(TIM3)){ // je to přetečení timeru ? LL_TIM_ClearFlag_UPDATE(TIM3); // událost jsme obsloužili, mažeme její vlajku LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_9); // a zase zhasni LED } } void init_tim3(void){ LL_TIM_InitTypeDef tim; LL_TIM_OC_InitTypeDef oc; // inicializujeme struktury (abychom je nemuseli vyplňovat celé) LL_TIM_StructInit(&tim); LL_TIM_OC_StructInit(&oc); // povolíme clock pro TIM3 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3); tim.Prescaler = 47999; // 1kHz do timeru tim.Autoreload = 999; // přetečení každou sekundu LL_TIM_Init(TIM3,&tim); // nastavíme komparační hladiny kanálů CH1 až CH3 oc.CompareValue = 800; // 0.8s - rozsvítit oc.OCMode = LL_TIM_OCMODE_FROZEN; // žádná akce s výstupy LL_TIM_OC_Init(TIM3,LL_TIM_CHANNEL_CH1,&oc); oc.CompareValue = 820; // 0.82s - zhasnout LL_TIM_OC_Init(TIM3,LL_TIM_CHANNEL_CH2,&oc); oc.CompareValue = 980; // 0.98s - rozsvítit (a s updatem zhasnout) LL_TIM_OC_Init(TIM3,LL_TIM_CHANNEL_CH3,&oc); // povolíme přerušení od přetečení + od všech tří compare kanálů LL_TIM_EnableIT_UPDATE(TIM3); LL_TIM_EnableIT_CC1(TIM3); LL_TIM_EnableIT_CC2(TIM3); LL_TIM_EnableIT_CC3(TIM3); // což mimochodem šlo klidně zapsat jedním úspornějším příkazem v CMSIS // TIM3->DIER |= TIM_DIER_UIE | TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE; // v NVIC povolíme přerušení od TIM3 NVIC_SetPriority(TIM3_IRQn,3); // nízká priorita NVIC_EnableIRQ(TIM3_IRQn); // a čítač spustíme LL_TIM_EnableCounter(TIM3); } // LED na PC9 void init_gpio(void){ LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC); LL_GPIO_SetPinMode(GPIOC,LL_GPIO_PIN_9,LL_GPIO_MODE_OUTPUT); } // 48MHz z externího 8MHz signálu void init_clock(void){ LL_UTILS_PLLInitTypeDef pll; LL_UTILS_ClkInitTypeDef clk; pll.Prediv = LL_RCC_PREDIV_DIV_2; // 8MHz / 2 = 4MHz pll.PLLMul = LL_RCC_PLL_MUL_12; // 4MHz * 12 = 48MHz clk.AHBCLKDivider = LL_RCC_SYSCLK_DIV_1; // APB i AHB bez předděličky clk.APB1CLKDivider = LL_RCC_APB1_DIV_1; // voláme konfiguraci clocku LL_PLL_ConfigSystemClock_HSE(8000000,LL_UTILS_HSEBYPASS_ON,&pll,&clk); // aktualizuj proměnnou SystemCoreClock SystemCoreClockUpdate(); }