niedziela, 7 sierpnia 2016

[1] STM32 M3 - Nucleo - F103RB - Rejestry - Porty GPIO

Ten post chciałbym poświęcić na przedstawienie sposobu włączenia portów GPIO oraz zegara w mikrokontrorze wymienionym w tytule. 

Opis Rejestrów


Do obsługi portów GPIO można wyróżnić następujące rejestry: CRL, CRH, IDR, BSRR, BRR, ODR, LCKR.

Poniżej krótki opis wymienionych rejestrów. Po dokładniejsze informacje należy zajrzeć do Reference manual dla wybranego mikrokontrolera.

GPIO_CRL - Pozwala on na wybranie ustawień dotyczących wyprowadzeń od Px0 do Px7.

Rys. 1. Rejestr GPIO_CRL [manual]



Dzięki niemu możliwe jest ustawianie trybów pracy wejścia, wyjścia, analogowego, z rezystor podciągającym itp.

Rys. 2. Ustawienie bitów[manual]

Na rysunku 2 przedstawiłem jakie bity muszą zostać ustawione tak aby wybrany pin pracował w odpowiednim trybie.

GPIO_CRH - działa on podobnie jak CRL, natomiast pozwala on na ustawianie innego zestawu pinów tj. od 8 do 15.

Rys. 3. Rejestr CRH

GPIO_IDR - służy tylko do odczytu, dzięki niemu możliwe jest sprawdzenia stanu jaki występuje na danym wyprowadzeniu.

Rys. 4. Rejestr IDR

GPIO_BSRR - służy wyłączenie do zapisu. Pozwala na włączenie bądź wyłączenie danego pinu.

Rys. 5. Rejestr BSRR

Młodsze 16 bitów pozwalają na włączenie, czyli podanie "1", jeśli zostanie podane "0" to będzie miało to żadnego efektu. Po ustawieniu bitu, zostaje automatycznie ustawiony bit w rejestrze ODR. Starsze 16 bitów służy to wyłączania, czyli podanie 1 nie ustawi bitu w ODR tylko go skasuje.

GPIO_BRR - podobnie jak BSRR służy tylko i wyłącznie do zapisu. Dzięki niemu możliwe jest tylko i wyłącznie kasowanie bitów w rejestrze ODR poprzez wprowadzenie "1". Wpisanie "0" nie przynosi żadnego efektu.

Rys. 6. Rejestr BRR

GPIO_ODR - jest to rejestr do którego możliwe jest wpisanie oraz wprowadzenie danych. Ustawia on odpowiedni stan na wyprowadzeniach.

Rys. 7. Rejestr ODR

Rejestry BSRR oraz BRR uzyskują dostęp do rejestru ODR. Operacje na rejestrach BSRR oraz BRR są operacjami atomowymi, czyli niepodzielnymi. Oznacza to, że jeśli będzie wykonywana operacja nietomowa np. bezpośredni zapis do rejestru ODR, to może zostać ona niewykonana poprawnie np. poprzez wywołane przerwanie, które zmieni strukturę ustawionych bitów w rejestrze, co po połowicznym wykonaniu operacji może spowodować pewien bałagan. Taka sytuacja w przypadku operacji atomowych nie będzie miała miejsca.

GPIO_LCKR - pozwala na blokowanie danego wyprowadzenia, gdy zostały do niego już wprowadzone dane.

Rys. 8. Rejestr LCKR

LCKK służy do blokowania możliwości zmiany, natomiast LCK0 do LCK15 blokuje możliwość wprowadzenia modyfikacji dla określonego wyprowadzenia.

Program


Pierwszy program będzie prezentował w jaki sposób należy wykonać zapalenie oraz zgaszenie diody podłączonej do pinu PA5. 

  1. #include "stm32f10x.h"
  2. #include "stm32f10x_gpio.h"
  3. void delay(int time)
  4. {
  5.     int i;
  6.     for (= 0; i < time * 4000; i++) {}
  7. }
  8. int main(void)
  9. {
  10.     RCC->APB2ENR = RCC_APB2ENR_IOPAEN; // uruchomienie zegara modulu GPIO
  11.     //Ustawienie pinu 5 jako wyjście pushpull z czestotliwoscia 2MHz
  12.     //Lub tak GPIO->CRL = GPIO_CRL_MODE5;
  13.     GPIOA->CRL=0x00200000;
  14.     while (1) {
  15.         GPIOA->BSRR = GPIO_BSRR_BS5;
  16.         delay(800);
  17.         GPIOA->BSRR =~GPIO_BSRR_BS5;
  18.         delay(800);
  19.     }
  20. }

Można też pętle while zapisać w nieco inny sposób, wykorzystując do tego rejestr ODR:

  1. GPIOA->ODR |=  0x00000020;
  2. delay(800);
  3. GPIOA->ODR &=0x00000020;
  4. delay(400);

Lub tak:

  1. GPIOA->BSRR = GPIO_BSRR_BS5;
  2. delay(800);
  3. GPIOA->BSRR =~GPIO_BSRR_BS5;
  4. delay(800);

Należy pamiętać także, że następujący zapis:

GPIOA->ODR = 0x00000020; lub GPIOA ->ODR = GPIO_ODR_ODR5;

Wykasuje wszystkie bity, po za tym, który w tym momencie zostanie wprowadzony, Aby temu zapobiec i po prostu ustawić dany bit to należy zamiast operatora "=" wykorzystać "|=".

Kolejnym elementem jest obsłużenie wbudowanego przycisku, jest on podłączony na stałe do pinu PC13. Należy go skonfigurować jako wejście z rezystorem podciągającym. Wobec tego, że jest on domyślnie ustawiony w odpowiednich parametrach to wystarczy tylko włączyć zegar dla portu GPIOC.

  1. #include "stm32f10x.h"
  2. #include "stm32f10x_gpio.h"
  3. int main(void)
  4. {
  5.     //Wlaczenie zegarow
  6.     RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
  7.     RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
  8.     //Ustawienie bitu dla diody, sposob 2
  9.     GPIOA->CRL = 1<<21;
  10.     while (1)
  11.     {
  12.        //Sprawdzenie stanu przycisku
  13.        if((GPIOC->IDR & 0x2000) == 0)
  14.        {
  15.           GPIOA->BSRR |= GPIO_BSRR_BS5; // zapal diode
  16.        }
  17.        else
  18.        {
  19.            GPIOA->BSRR |=~ GPIO_BSRR_BS5;
  20.        }
  21.     }
  22. }