Teraz przejdę tylko do opisu rejestów oraz sposobu wywołania przerwania.
W formie przypomnienia to należy pamiętać o tym iż przerwania mają współdzielone wektory np. dla PA1 oraz PC1, czy dla linii od 10 do 15. Wobec tego trzeba będzie dokonywać sprawdzenia, która z linii dokonała wyzwolenia przerwania.
Rejestry
Z rejestrów układu EXTI można wyróżnić:
EXTI_IMR - rejestr wystąpień przerwań dla układu
Każda z pinów może przyjmować jeden stan 0 lub 1 (bity od 0 do 19). Zero oznacza, że przerwanie na linii zostało maskowane, 1 że zostało niezamaskowane Pozostałe są ustawione domyślnie na 0. Bit 19 jest używany tylko dla układów z liniami connectivity, dla innych układów należy go zostawić na 0.
EXTI_EMR - rejestr wystąpień zdarzeń
Wygląda on dokładnie tak samo jak IMR. Zero oznacza, że zdarzenie na linii jest maskowane, jedynka natomiast, że jest niemaskowane.
EXTI_RTSR - wybranie zbocza rosnącego dla danego pinu:
Jedynka ustawia wyzwalanie zboczem rosnącym.
EXTI_FTSR - ustawia wyzwalanie zboczem opadającym:
Zbocze opadające włączone gdy ustawiona jedynka.
EXTI_SWIER - ustawienie przerwania systemowego na określonej linii. Budowa wewnętrzna taka jak wcześniej wymienionych rejestrów.
Gdy przerwanie jest włączone dla EXTI_IMR to zmiana stanu z 0 na 1 powoduje ustawienie bitu w rejestrze EXTI_PR. Powoduje to wygenerowanie żądanego przerwania.
EXTI_PR - pozwala na zweryfikowanie czy wystąpiło przerwanie. 0 oznacza że przerwanie nie miało miejsca, jedynka natomiast, że wystąpiło przerwanie wyzwolone wcześniej ustawionym zboczem.
W tym rejestrze jak już wspomniałem jest ustawiana jedynka po pojawieniu się przerwania. Czyszczenie natomiast następuje poprzez wpisanie jedynki do bitu.
W tym rejestrze jak już wspomniałem jest ustawiana jedynka po pojawieniu się przerwania. Czyszczenie natomiast następuje poprzez wpisanie jedynki do bitu.
Program
Komentarz umieściłem przy każdej z linii kodu. Jego działanie polega na zapaleniu oraz zgaszeniu diody dołączonej do PA5 poprzez naciskanie przycisku.
- #include "stm32f10x.h"
- volatile uint8_t zmienna = 0;
- int main(void)
- {
- RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //Zegar dla GPIOA
- RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Zegar dla GPIOC
- RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; //Zegar funkcji alternatywnych
- //Ustawienie pinu 5 jako wyjście pushpull z czestotliwoscia 2MHz
- GPIOA->CRL = 1<<21;
- //Ustawienie pinu 13 jako input_floating
- GPIOC->CRH = 1<<22;
- //wybranie portu odpowiedzialnego za przerwanie
- AFIO->EXTICR[3] = AFIO_EXTICR4_EXTI13_PC;
- //ustawienie rejestru IMR, wlaczenie 13
- EXTI->IMR = EXTI_IMR_MR13;
- //Zbocze rosnące rejestr RTSR
- //Zbocze opadajace rejestr FTSR
- EXTI->FTSR = EXTI_FTSR_TR13;
- //Wlaczenie przerwania
- NVIC_EnableIRQ(EXTI15_10_IRQn);
- while (1){}
- }
- //Obsluga przerwania
- __attribute__((interrupt)) void EXTI15_10_IRQHandler(void)
- {
- //Sprawdzenie wywolania przerwania
- if (EXTI->PR & EXTI_PR_PR13)
- {
- //Kasowanie flagi
- EXTI->PR = EXTI_PR_PR13;
- //
- if(zmienna == 0)
- {
- GPIOA->BSRR |= GPIO_BSRR_BS5;
- zmienna = 1;
- }
- else if(zmienna == 1)
- {
- GPIOA->BSRR |=~ GPIO_BSRR_BS5;
- zmienna = 0;
- }
- }
- }
Na końcu chciałbym jeszcze zaznaczyć, że kasowanie flagi przerwania powinno się odbywać jak najszybciej jak to tylko możliwe. Czyli najlepiej zaraz po jej sprawdzeniu. Spowodowane jest to tym, że z przerwanie może zostać ponownie wywołane, ponieważ flaga nie zdąży zostać skasowana. Można też pominąć jakieś przerwanie jeśli zostanie ona za szybko skasowana.