Magistrala CAN (Controller Area Network) to jeden z kluczowych interfejsów komunikacyjnych w nowoczesnych systemach embedded, szczególnie w motoryzacji i przemyśle. Mikrokontrolery STM32 mają wbudowane kontrolery CAN, co czyni je idealnym wyborem do projektów wymagających niezawodnej i deterministycznej komunikacji. Ten przewodnik omawia konfigurację i działanie interfejsu CAN w STM32 – od warstwy fizycznej po praktyczną implementację.

Architektura magistrali CAN

Budowa fizyczna

Magistrala CAN składa się z dwóch przewodów: CANH i CANL. Informacja kodowana jest sygnałem różnicowym, czyli w różnicy napięć między liniami.

Na obu końcach magistrali muszą znaleźć się rezystory terminujące – najczęściej 120 Ω – które tłumią odbicia sygnału i stabilizują transmisję. Popularnym złączem magistrali CAN jest DB9M.

Stany logiczne

Dla poprawnego działania zdefiniowano dwa stany: logiczne 1 (recesywny) – w idealnym przypadku różnica napięć to 0 V; logiczne 0 (dominujący) – różnica napięć wynosi co najmniej 0,9 V.

Taka definicja stanów umożliwia bezkolizyjny arbitraż – urządzenia wykrywają dominację na magistrali i w razie konfliktu wycofują się z nadawania.

Topologia i protokół sieci

Architektura multimaster

CAN działa w architekturze multimaster – każdy węzeł ma te same uprawnienia, a transmisja ma charakter rozgłoszeniowy (broadcast). W danej chwili tylko jedno urządzenie może nadawać, pozostałe nasłuchują.

Arbitraż i CSMA/CA

Dostęp do medium kontroluje CSMA/CA (Carrier Sense Multiple Access/Collision Avoidance). Wszystkie węzły muszą pracować z tą samą prędkością bitową, aby zapewnić poprawny arbitraż i detekcję kolizji.

Standardy CAN

Pierwotny standard CAN 2.0A definiuje ramkę z 11‑bitowym identyfikatorem. W odpowiedzi na rosnące potrzeby adresacji powstał CAN 2.0B z 29‑bitowym identyfikatorem. Większość współczesnych kontrolerów (w tym STM32) obsługuje oba warianty.

Dla szybkiego porównania kluczowych różnic między wariantami warto przejrzeć zestawienie:

Wersja Długość identyfikatora Liczba identyfikatorów Typowe zastosowanie Obsługa w STM32
CAN 2.0A 11 bitów 2 048 mniejsze/średnie sieci, prostsza filtracja powszechna
CAN 2.0B 29 bitów 536 870 912 rozbudowane sieci, precyzyjna adresacja powszechna

Architektura węzła CAN w STM32

Komponenty węzła

Przypadek podstawowy – mikrokontroler, kontroler CAN (np. MCP2515) oraz transceiver warstwy fizycznej.

Przypadek optymalizowany – w mikrokontrolerach STM32 z wbudowanym kontrolerem CAN wystarczy dodać zewnętrzny transceiver fizyczny. Część układów STM32 oferuje nawet dwa niezależne kontrolery CAN.

Rola transceivera

Transceiver konwertuje różnicowe sygnały CANH/CANL na pojedynczy poziom logiczny akceptowany przez linie I/O mikrokontrolera, zapewniając zgodność z warstwą fizyczną magistrali.

Peryferium CAN w STM32 – poziomy logiczne

Peryferium CAN/FDCAN w STM32 oczekuje jednokanałowego poziomu logicznego (niski – dominujący, wysoki – recesywny). To transceiver mapuje sygnał różnicowy na logikę pojedynczej linii, którą dalej przetwarza kontroler.

Konfiguracja STM32 – praktyczne podejście

Pinowanie i funkcje alternatywne

CAN1 Tx / CAN2 Tx należy skonfigurować jako wyjścia push‑pull z odpowiednimi zabezpieczeniami (np. diody ochronne).

CAN1 Rx / CAN2 Rx ustawiamy jako wejścia AF (Alternate Function) bez pull‑up i bez pull‑down.

Transmisja i odbiór danych

Aby nadać ramkę, przygotuj nagłówek transmisji (TxHeader) z kluczowymi polami:

  • typ ramki – ramka danych (nie zdalna);
  • długość danych – w bajtach, np. 2–8 bajtów;
  • stan błędu – wskaźnik stanu błędu w trybie normalnym;
  • format – klasyczny CAN (bez CAN FD).

Odbiór realizowany jest przez callback wywoływany po pojawieniu się wiadomości w FIFO. Kontroler przekaże do aplikacji tylko te ramki, które przechodzą przez skonfigurowane filtry.

Filtry programowe CAN

Koncepcja filtrów

CAN to komunikacja rozgłoszeniowa – wszystkie węzły widzą każdą ramkę. Aby ograniczyć obciążenie aplikacji, filtry sprzętowo‑programowe dopuszczają tylko pożądane identyfikatory, dzięki czemu nieistotne wiadomości są odrzucane jeszcze przed etapem przetwarzania w kodzie.

Praktyczna implementacja – komunikacja CAN1↔CAN2 bez transceivera

Schemat pomysłu

W ramach jednego mikrokontrolera można zestawić wirtualną magistralę między CAN1 i CAN2 bez zewnętrznego transceivera, wykorzystując topologię otwartego drenu (open‑drain).

Zasada działania

W klasycznym CAN stany różnicowe tworzy transceiver. W układzie uproszczonym wspólny węzeł z rezystorem podciągającym (pull‑up) odwzorowuje logikę: poziom podciągnięty = 1 (recesywny), a poziom ściągnięty do masy = 0 (dominujący). Wejścia Rx obu kontrolerów widzą poprawne stany i są w stanie dekodować ramki.

Przykład kodu

Callback odbierający dane z FDCAN (FIFO0) może wyglądać następująco:

void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {
if (RxFifo0ITs && FDCAN_IT_RX_FIFO0_NEW_MESSAGE != RESET) {
if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1) != HAL_OK) {
Error_Handler();
}
if (HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0)) {
Error_Handler();
}
}
}

Konfiguracja nagłówka transmisji dla klasycznego CAN bez BRS:

TxHeader2.TxFrameType = FDCAN_DATA_FRAME;
TxHeader2.DataLength = FDCAN_DLC_BYTES_2;
TxHeader2.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader2.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader2.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader2.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
TxHeader2.MessageMarker = 0;

Wysyłanie wiadomości w pętli głównej oraz reakcja na odebrane dane:

while (1) {
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET) {
TxData1 = 200;
TxData1 = 20;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, TxData1) != HAL_OK) {
Error_Handler();
}
HAL_Delay(1000);
}
if (datacheck == 1) {
for (int i = 0; i < RxData2; i++) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(RxData2);
}
datacheck = 0;
}
}

Praktyczne zastosowanie – sterowanie diodą LED

Przykład aplikacyjny: po naciśnięciu przycisku CAN1 wysyła częstotliwość i liczbę mignięć, a CAN2 odbiera parametry i steruje LED zgodnie z odebranymi danymi. To zamyka pełny łańcuch: nadawanie → filtracja → odbiór → wykonanie akcji.