Zanim zaczniemy konfigurować swoje timery (zegary) możemy skorzystać z systemowego.

Standardowe przerwanie zegara

Każdy STM32 ma skonfigurowane przerwanie wywoływane z częstotliwością 1kHz. Nadpisując je dostajemy dostęp do licznika. W naszym przykładzie skorzystałem z funkcji prinfx() zdefiniowanej (jako makro) w poradniku o cout w STM32.
Najpierw u góry definiujemy sobie zmienną globalną – która będzie liczyła ticki. Ponieważ na 4 bajtach da się zapisać liczbę do 65535, nasz licznik co minutę by się przekręcał, użyjemy typu na 8 bajtach uint32_t. Słowo volatile oznacza „ulotność”, czyli możliwość zmiany wartości zmiennej w innym procesie (nie można jej optymalizować w kodzie, gdy wydaje się nieużywana).

1
volatile uint32_t counter1kHz;

A samo przerwanie ma postać:

1
2
3
4
5
6
7
8
9
void HAL_SYSTICK_Callback(){
//Clock system callback 1kHz
        counter1kHz++;
     // if (counter1kHz % 1000 == 0) //too complicated
        if ((counter1kHz & 1023) == 1023) // & 111111111 (co 1024)
         {
           printfx("%lu,", (unsigned long)counter1kHz);
         }
}

Jak widzicie, zamiast kosztownej operacji reszty z dzielenia przez 1000 (%) skorzystaliśmy z operatora bitowego & z liczbą 0b111111111 (1023 w systemie 10). Taka liczba pojawi się co 1024 wywołania czyli około 1x na sekundę (trochę dłużej będą trwały przerwy, ale niezauważalnie). Wywoływanie „kosztownych” operacji 1000 razy na sekundę nie doda wigoru naszej aplikacji, a operacje bitowe robione są szybko. Przy programowaniu STM32 warto umieć te operatory & , |, ^.

Nieaktywne przerwanie

Jeśli przerwanie nie działa, w pliku stm32f1xx_it.c (a w przypadku, gdy zamiast Bare Metal używamy rtthread: board.c) należy aktywować systick, dopisujemy jedną linię (reszta już jest)

1
2
3
4
5
6
7
8
9
10
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  HAL_SYSTICK_IRQHandler(); //FX turn on SYSTICK interrupt
  /* USER CODE END SysTick_IRQn 1 */
}

Mierzenie czasu wykonania, np. wciśnięcia BUTTONu

Mierzymy w oparciu o przerwanie buttona (opisane w poprzednich częściach) i zdefiniowany wyżej licznik, wynik podajemy w ms:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* USER CODE BEGIN 4 */
uint16_t HAL_GPIO_EXTI_Callback_start; //start point - time measure
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
//FX: Interrupt function. Light the greenLed when button is pressed, changing the status
        switch(GPIO_Pin){ //select which pin causes the callback.
                case B1_Pin: //Blue Button pin only
                        HAL_GPIO_WritePin(greenLed_GPIO_Port, greenLed_Pin, greenLedStatus ? GPIO_PIN_RESET : GPIO_PIN_SET);
                        greenLedStatus = !greenLedStatus; //remember the state
                        if (greenLedStatus){ //reverse
                                HAL_GPIO_EXTI_Callback_start = counter1kHz;
                        }
                        else { // {} !
                                printfx("Button pressed: %i ms", (counter1kHz-HAL_GPIO_EXTI_Callback_start));
                        }
                break;
        }

}