W tym poście chciałbym opisać integrację timera oraz przerwań zewnętrznych obsługujących biblioteki LL.
[Źródło: http://www.st.com/en/evaluation-tools/stm32f4discovery.html]
Cube Mx:
Ustawienia Timera:
Konfiguracja przycisku:
Uruchomienie przerwań:
Po uruchomieniu wszystkich potrzebnych funkcji należy się upewnić, że zostały uruchomione biblioteki LL:
Przerwania od przycisku:
Inicjalizacja diod oraz przycisku podłączonego do przerwania:
- static void MX_GPIO_Init(void)
- {
- LL_EXTI_InitTypeDef EXTI_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- /* GPIO Ports Clock Enable */
- LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOH);
- LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
- LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD);
- /**/
- LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_12|LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15);
- /**/
- LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTA, LL_SYSCFG_EXTI_LINE0);
- /**/
- EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_0;
- EXTI_InitStruct.LineCommand = ENABLE;
- EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
- EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING;
- LL_EXTI_Init(&EXTI_InitStruct);
- /**/
- LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_0, LL_GPIO_PULL_NO);
- /**/
- LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_0, LL_GPIO_MODE_INPUT);
- /**/
- GPIO_InitStruct.Pin = LL_GPIO_PIN_12|LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- LL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- }
Przerwanie od przycisku wygenerowane jest na zbocze narastające jak i opadające.
Uruchomienie przerwań jeśli nie uruchomiliśmy ich w Cubex poprzez zaznaczenie opcji EXTI line0 interrupt:
- static void EnableBtnInterrupt()
- {
- NVIC_SetPriority(EXTI0_IRQn,0);
- NVIC_ClearPendingIRQ(EXTI0_IRQn);
- NVIC_EnableIRQ(EXTI0_IRQn);
- }
Jeśli zostały uruchomione przerwania to funkcja obsługująca przerwanie zostanie zdefiniowana w pliku stm32f4xx_it.h. Natomiast funkcja inicjalizująca piny będzie zawierała procedurę uruchomienia przerwań:
- static void MX_GPIO_Init(void)
- {
- LL_EXTI_InitTypeDef EXTI_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- /* GPIO Ports Clock Enable */
- LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOH);
- LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
- LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD);
- /**/
- LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_12|LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15);
- /**/
- LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTA, LL_SYSCFG_EXTI_LINE0);
- /**/
- EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_0;
- EXTI_InitStruct.LineCommand = ENABLE;
- EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
- EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING;
- LL_EXTI_Init(&EXTI_InitStruct);
- /**/
- LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_0, LL_GPIO_PULL_NO);
- /**/
- LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_0, LL_GPIO_MODE_INPUT);
- /**/
- GPIO_InitStruct.Pin = LL_GPIO_PIN_12|LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- LL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- /* EXTI interrupt init*/
- NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
- NVIC_EnableIRQ(EXTI0_IRQn);
- }
Obsługa przerwania:
- void EXTI0_IRQHandler(void)
- {
- if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0) != RESET)
- {
- LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
- GPIO_EXTI_Callback_Line0();
- }
- }
- void GPIO_EXTI_Callback_Line0(void)
- {
- LL_GPIO_TogglePin(GPIOD, LL_GPIO_PIN_12);
- LL_GPIO_TogglePin(GPIOD, LL_GPIO_PIN_13);
- LL_GPIO_TogglePin(GPIOD, LL_GPIO_PIN_14);
- LL_GPIO_TogglePin(GPIOD, LL_GPIO_PIN_15);
- }
W obsłudze przerwania czyścimy flagę informującą o wystąpieniu przerwania po czym przechodzimy do funkcji która zajmuje się obsługą diod po kliknięciu przycisku:
Timer:
Procedura uruchomienia timera wygląda następująco:
- static void MX_TIM2_Init(void)
- {
- /* USER CODE BEGIN TIM2_Init 0 */
- /* USER CODE END TIM2_Init 0 */
- LL_TIM_InitTypeDef TIM_InitStruct = {0};
- /* Peripheral clock enable */
- LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
- /* TIM2 interrupt Init */
- NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
- NVIC_EnableIRQ(TIM2_IRQn);
- /* USER CODE BEGIN TIM2_Init 1 */
- /* USER CODE END TIM2_Init 1 */
- TIM_InitStruct.Prescaler = 159;
- TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
- TIM_InitStruct.Autoreload = 25999;
- TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
- LL_TIM_Init(TIM2, &TIM_InitStruct);
- LL_TIM_DisableARRPreload(TIM2);
- LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
- LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_UPDATE);
- LL_TIM_DisableMasterSlaveMode(TIM2);
- /* USER CODE BEGIN TIM2_Init 2 */
- /* USER CODE END TIM2_Init 2 */
- }
- void TIM2_IRQHandler(void)
- {
- /* USER CODE BEGIN TIM2_IRQn 0 */
- if(LL_TIM_IsActiveFlag_UPDATE(TIM2))
- {
- LL_TIM_ClearFlag_UPDATE(TIM2);
- TIM2_Callback();
- }
- /* USER CODE END TIM2_IRQn 0 */
- }
Funkcja odpowiedzialna za obsługę przerwania od timera. Jej zadanie jest dosyć proste. Zapala poszczególne diody, gdy dojdzie do zapalenia 4 diod czeka dwa cykle, wyłącza wszystkie diody i przechodzi do ponownego zapalania.
- void TIM2_Callback(void)
- {
- if(Tim2_DisplayDiodeCounter == 0)
- {
- LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_12);
- }
- else if(Tim2_DisplayDiodeCounter == 1)
- {
- LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_13);
- }
- else if(Tim2_DisplayDiodeCounter == 2)
- {
- LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_14);
- }
- else if(Tim2_DisplayDiodeCounter == 3)
- {
- LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_15);
- }
- else if(Tim2_DisplayDiodeCounter == 6)
- {
- LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_12);
- LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_13);
- LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_14);
- LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_15);
- }
- Tim2_DisplayDiodeCounter++;
- if(Tim2_DisplayDiodeCounter>6){
- Tim2_DisplayDiodeCounter=0;
- }
- }
Cały projekt można pobrać z dysku Google pod tym linkiem.