Obsługa magistrali CAN przez mikrokontrolery PIC

Wstęp

Controller Area Network (CAN) jest szeregową magistralą danych opracowaną w latach osiemdziesiątych w firmie Robert Bosh GmbH dla przemysłu samochodowego. Jej wprowadzenie spowodowało zmniejszenie ilości okablowania łączącego moduły pojazdu oraz umożliwiło wymianę danych między sterownikami.

Zastosowanie

CAN znajduje również zastosowanie:
– w przemysłowych magistralach polowych,
– lotnictwie, CANaerospace oraz implementacja magistrali w Airbus A380 [2],
– pojazdach wojskowych (MilCAN),
– sterowaniu automatyką w budynkach.

Cechy

Najważniejszymi cechami magistrali CAN:
– do 8 bajtów  w komunikacie,
– komunikaty są rozpoznawane przez identyfikatory (trafiają do wybranych adresatów),
– automatyczna obsługa dostępu do magistrali,
– możliwość określenia priorytetu komunikatu (im wyższa wartość liczbowa tym komunikat ma niższy priorytet).

Standaryzacja

Standardy magistrali CAN w wersji 2.0 określa specyfikacja firmy BOSH:
– wersja 2.0A posiada 11 bitowy identyfikator,
– wersja 2.0B posiada 29 bitowy identyfikator.

Prędkość transmisji danych

Zgodnie ze standaryzacją Międzynarodowej Organizacji Normalizacyjnej magistrala osiąga następujące przepustowości:
– do 1Mb/s, standard  ISO 11898 (High speed CAN bus)
– do 125kb/s, standard  ISO 11519 (Low speed CAN bus).

Transmisja danych

Magistrala może pracować w dwóch poziomach logicznych:
– dominującym (ang. “dominant”), na magistralę zapisywane jest logiczne zero,
– recesywny (ang. “recessive”), na magistralę zapisywana jest logiczna jedynka.

Medium transmisyjnym w magistrali CAN jest dwużyłowy kabel typu skrętka. Urządzenia podłączone są do medium w topologii magistrali, która zakończona jest rezystorami terminującymi o wartości 120Ω.

Rys. Topologia magistrali CAN z rezystorami terminującymi.

Każde z urządzeń nazywane jest węzłem (node), którego składowymi są:
Mikrokontroler (sterujący pracą urządzenia oraz odpowiedzialny za komunikację po magistrali CAN),
Kontroler CAN, najczęściej wbudowany w mikrokontroler (np. PIC18F25K80). Jego zadaniem jest budowa ramki danych, wykrywanie kolizji itp.
Transceiver CAN, będący zwykle oddzielnym układem (np. MCP2551). Dostosowuje poziomy napięć pomiędzy magistralą a mikrokontrolerem.

węzeł CAN

Rys. Elementy węzła – urządzenia podłączonego do magistrali CAN

Układ testowy

Układ testowy został zrealizowany na płytce stykowej. Zastosowano dwa mikrokontrolery PIC18F25K80 do których podłączono transceivery MCP2551.
Układ scalony MCP2551 jest transceiverem CAN pracującym z maksymalną prędkością 1 Mb/s zgodnie ze standardem  ISO-11898. Do jednej magistrali może zostać podłączonych do 112 urządzeń wyposażonych w tego typu transceivery.

układ testowy magistrali CAN

Rys. Układ testowy

Zadaniem układu testowego jest zrealizowanie komunikacji pomiędzy dwoma urządzeniami połączonymi za pośrednictwem magistrali CAN.
Urządzenie #1 połączone jest z komputerem PC przez przejściówkę (USB-UART), otrzymuje ono znak za pośrednictwem konsoli i wysyła je na magistralę CAN. Następnie przechodzi w stan oczekiwania na odpowiedź i po otrzymaniu ramki danych (zawierającej jeden znak) wysyła go do komputera (wyświetlając go w konsoli).
Urządzenie #2 pełni funkcję “Echo”. Wszelkie adresowane do tego urządzenia dane są odsyłane do nadawcy.


Rys. Schemat ideowy układu testowego.

Program dla mikrokontrolerów

Program dla mikrokontrolerów został napisany w CCS C. Głównymi elementami programu na które należy zwrócić uwagę są:

  • Podłączenie biblioteki ca-18f4580.c
    #include
  • Definicja adresów płytek
    #define BOARD1_ID  1
    #define BOARD2_ID  2
  • Utworzenie zmiennych
    struct rx_stat rxstat; 
    int32 rx_id; 
    int32 tx_id; 
    int8 rx_len;                
    unsigned int8 buffer[8];
  • Inicjacja CAN
    can_init();
  • Wysłanie zawartości zmiennej buffer do adresata przez magistralę CAN
    can_putd(BOARD2_ID, buffer, sizeof(buffer), 1, 1, 0);
  • Wykrycie otrzymanych danych z magistrali CAN
    can_kbhit();
  • Pobranie danych do zmiennej buffer
    can_getd(rx_id, buffer, rx_len, rxstat);

Źródło dla urządzenia #1

#include  
#fuses INTRC_IO, NOPROTECT, PUT, BROWNOUT, NOWDT,NOMCLR
#use delay(clock=8000000) 
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) 

#include  

#define BOARD1_ID  1
#define BOARD2_ID  2 

struct rx_stat rxstat; 
int32 rx_id; 
int32 tx_id; 
int8 rx_len;                
unsigned int8 buffer[8]; 

void clear_buffer(){
   for(int8 x=0;x<8;x++){
      buffer[x]=0;
   }
}void main() 
{ 
can_init(); 
delay_ms(500);
printf("Uruchomiono, oczekuje na znaki\n");

while(1) 
  { 
   clear_buffer();
   buffer[0] = getc();   // oczekiwanie na znak z uart
   printf("Wysylam %d\n",buffer[0]);

   // transmisja do modulu 2. 
   can_putd(BOARD2_ID, buffer, sizeof(buffer), 1, 1, 0); 

   clear_buffer();   // wyczyszczenie bufora

   // oczekiwanie na echo z modulu 2
   while(!can_kbhit()); 

   // jesli pobrano wiadomosc
   if(can_getd(rx_id, buffer, rx_len, rxstat)) 
     { 
      if(rx_id == BOARD1_ID)  // wiadomosc dla modulu 1
        {         printf("Odebralem %d\n", buffer[0]);
        } 
      } 
  } 
}

Źródło dla urządzenia #2

#include  
#fuses INTRC_IO, NOPROTECT, PUT, BROWNOUT, NOWDT,NOMCLR
#use delay(clock=8000000) 
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS) 

#include  

#define BOARD1_ID  1 
#define BOARD2_ID  2 

struct rx_stat rxstat; 
int32 rx_id; 
int32 tx_id; 
int8 rx_len;                
unsigned int8 buffer[8]; 

void clear_buffer(){
   for(int8 x=0;x<8;x++){
      buffer[x]=0;
   }
}

void main() 
{ 
can_init(); 

while(1){
   clear_buffer();
   // Dostepna wiadomosc z CAN 
   if(can_kbhit())  
     { 
      // jesli pobrano wiadomosc
      if(can_getd(rx_id, buffer, rx_len, rxstat)) 
        { 
         if(rx_id == BOARD2_ID)  // wiadomosc dla modulu 2
           { 
            // odeslanie danych do nadawcy - echo
            can_putd(BOARD1_ID, buffer, sizeof(buffer), 1, 1, 0); 
           } 
         } 
      } 
  } 
}

 

Odnośniki

Pliki projektu:

Noty katalogowe:

  • PIC18F25K80 – mikrokontroler
  • MCP2551 – transceiver CAN

Linki: