Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Atmega8][C] Atmega8 i TWI , ale jak zacząć...

p_zag 14 Sep 2009 09:22 12468 0
  • #1
    p_zag
    Level 14  
    Witam.
    Artykuł ten pisałem z myślą o wszystkich, którzy dopiero zaczynają swoja przygodę z magistralą TWI (czyli magistralą I2C) w procesorze Atmega8. Jest to program-szkielet, w który trzeba wpisać własne funkcje i procedury i wykorzystać gotowe procedury do komunikacji w magistrali TWI.
    A na praktyczne zastosowanie magistrali TWI zapraszam na:
    https://www.elektroda.pl/rtvforum/topic1338039.html


    [Atmega8][C] Atmega8 i TWI , ale jak zacząć...

    Code:


    //---------------------------------------------------------
    /*   Fuse Bits (taktowanie wewnętrzne procesora)

     CKSEL3..0       Częstotliwość [MHz]
        0001            1.0
       0010            2.0
        0011            4,0
        0100            8,0
    */
    //---------------------------------------------------------
    /*      Watchdog

    #define wdt_reset() __asm__ __volatile__ ('wdr')
    #define wdt_disable()
    #define wdt_enable(timeout) _wdt_write(timeout)
    #define WDTO_15MS 0      // 15 milisek
    #define WDTO_30MS 1      // 30 milisek
    #define WDTO_60MS 2      // 60 milisek
    #define WDTO_120MS 3   // 1,2 sekundy
    #define WDTO_250MS 4   // 0,25 sekundy
    #define WDTO_500MS 5   // 0,5 sekundy
    #define WDTO_1S 6      // 1 sekunda
    #define WDTO_2S 7      // 2 sekundy
    #define WDTO_4S 8      // 4 sekundy
    #define WDTO_8S 9       // 8 sekundy

    Watchdog do układ elektroniczny, zabezpieczający system mikroprocesorowy przed zbyt długim
    przebywaniem w stanie zawieszenia.
    W przypadku procesorów AVR, układ ten zaimplementowany jest już w ich strukturze.
    */
    //---------------------------------------------------------



    // MODUŁY      <- deklaracja modułów używanych w programie
    #define F_CPU 8000000UL      // czestotliwosci zegara procesora Atmega8 -> taktowanie wewnetrznie 8MHz (RC=8MHz)
    #include <avr/io.h>         // modul -> podstawowy - zawsze musi być
    #include <avr/wdt.h>       // modul -> Watchdog (C:\WinAVR-20081205\avr\include\avr\wdt.h)

    // ZMIENNE      <- deklaracja stałych, zmiennych, tablic używanych w programie
      // np.   const unsigned char kropka =0x04; // stała o nazwie kropka o wartości 4
      // np.   unsigned char kreska;      // zmiennz o nazwie kreska o wartości 0
      // np.   unsigned char tab[5] ={0,}; // zerowanie wszystkich pięciu elementow tablicy o nazwie tab

    // PROTOTYPY   <- deklaracja funkcji i procedur, które znajdują się poniżej funkcji 'int main(void) {...}'
    void TWI_inicjacja(void);
    unsigned char TWI_odczyt(unsigned char, unsigned char);
    unsigned char TWI_p_odczyt(unsigned char);
    void TWI_zapis(unsigned char, unsigned char, unsigned char);
    void TWI_p_zapis(unsigned char, unsigned char);



    //   *** PROGRAM GŁÓWNY ***   //
    int main(void)
     {/* Instrukcje jednokrotnego wykonania */
      // UWAGA ! Porty:
      //             PC5(SCL)  -  wejscie TWI
      //            PC4(SDA)  -  wejscie TWI
      // Kierunek portu (kierunek poszczególnych bitów portu)
      // 1 -> wyjscie
      // 0 -> wejscie
      DDRC =0b00000000; 
      // Stany początkowych napięć portu (poszczególnych bitów portu)
      // 1 -> stan wysoki (z podciągnięciem do VCC (pull-up))
      // 0 -> stan niski (bez podciagniecia do VCC)
      PORTC =0b00110000;
      TWI_inicjacja(); // zainicjowanie magistrali TWI
    //------- tu ewentualnie jakieś instrukcje -------
    /* ustawienie poczatkowe kirunku portów, poziomów napięć portów,
       nadanie początkowych wartości zmiennym, itp */
       
       
       
    //------------------------------------------------
      wdt_reset();            // tu konieczny restart Watchdoga         
      wdt_enable(WDTO_250MS);   // Watchdog -> restart procesora co 0,25 sekundy
      /*
      */
      while(1) 
       {/* Instrukcje wielokrotnego wykonania */
    //------- tu instrukcje wykonywane w pętli--------
    /* wszystkie instrukcje, które mają sie wykonywać wielokrotnie */




    //------------------------------------------------
        wdt_reset();   // tu nalezy zresetować Watchdoga
       }
      wdt_disable();   // wylaczenie Watchdog
      return 0;         // i zakończenie programu   
     } //   *** KONIEC PROGRAMU GŁÓWNEGO ***   //




    //--------------------------------
    //--------------------------------
    //  *** FUNKCJE I PROCEDURY ***
    //--------------------------------
    //--------------------------------
    void TWI_inicjacja(void)
    {
      // Czestotliwosc TWI(i2c) = 100kHz (max 100kHz)
      // ------------------------------------------------
      /* TWSR = TWS7 TWS6 TWS5 TWS4 TWS3  -   TWPS1 TWPS0 */
      TWSR =0b00000000;    // Preskaler = 1  ->> TWPS1=0 TWPS0=0
      // ------------------------------------------------------
      /* TWBR = TWBR7 TWBR6 TWBR5 TWBR4 TWBR3 TWBR2 TWBR1 TWBR0 */
      TWBR =0b00100000;
      /* Rejestr odpowiedzialny za wybór współczynnika podziału dla generatora.
         Generator ten odpowiada za czestotliwosc która jest dzielona przez
         sygnał zegarowy SCL w trybie pracy Master.
         ->> TWBR musi byc wieksze od 10 dla stabilnej pracy TWI(i2c) 
       ->> ((częstotliwość Atmegi/częstotliwość TWI)-16)/2 =TWBR 
     Czyli ((8MHz/100kHz)-16)/2=32  => TWBR=32 lub TWBR=0x20 lub TWBR=0b00100000 */ 
    }



    unsigned char TWI_odczyt(unsigned char scalak,
                       unsigned char adres_rejestru)
     { // odczyt pamięci o wielu rejestrach
      unsigned char odczyt;     
      TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );   // Wysłanie żądania "START".
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =scalak;                  // Podanie adresu układu scalonego z którego odczytujemy
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =adres_rejestru;            // Podanie adresu rejestru do odczytu odczytywanego układu scalonego
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));    // Oczekiwanie na ustawienie flagi TWINT.
      TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );   // Wysłanie żądania "START".
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =scalak | 0x01;             // Załadowanie danych z odczytuwanego układu scalonego do rejestru TWDR.
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      odczyt =TWDR;     
      TWCR =(1 << TWINT) | (1<<TWEN) | (1<<TWSTO);   // Wysłanie żądania "STOP".
      return(odczyt);
    }

    unsigned char TWI_p_odczyt(unsigned char scalak)
     { // odczyt pamięci o jednym rejestrze
      unsigned char odczyt;     
      TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );   // Wysłanie żądania "START".
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =scalak | 0x01;            // Podanie adresu układu scalonego z którego odczytujemy
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      odczyt =TWDR;     
      TWCR =(1 << TWINT) | (1<<TWEN) | (1<<TWSTO);   // Wysłanie żądania "STOP".
      return(odczyt);
    }

    void TWI_zapis(unsigned char scalak,
                unsigned char adres_rejestru,
                unsigned char liczba)
     { // zapis pamięci o wielu rejestrach
      TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );   // Wysłanie żądania "START".
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT..
      TWDR =scalak;                  // Podanie adresu układu scalonego do którego zapisujemy
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =adres_rejestru;            // Podanie adresu rejestru do zapisu zapisywanego układu scalonego
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));    // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =liczba;                  // Załadowanie danych do zapisu i wysłania do układu scalonego.
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWCR =(1 << TWINT) | (1<<TWEN) | (1<<TWSTO);   // Wysłanie żądania "STOP".
    }

    void TWI_p_zapis(unsigned char scalak,
                     unsigned char liczba)
     { // zapis pamięci o jednym rejestrze
      TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );   // Wysłanie żądania "START".
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =scalak;                  // Podanie adresu układu scalonego do którego zapisujemy
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWDR =liczba;                  // Załadowanie danych do zapisu i wysłania do układu scalonego.
      TWCR =(1 << TWINT) | (1 << TWEN);   // Wyczyszczenie bitu TWINT w rejestrze TWCR.
      while(!(TWCR & (1 << TWINT)));   // Oczekiwanie na ustawienie flagi TWINT.
      TWCR =(1 << TWINT) | (1<<TWEN) | (1<<TWSTO);   // Wysłanie żądania "STOP".
    }





    TWI Control Register – TWCR
    Rejestr sterujący układu TWI. W rejestrze tym zawarte są następujące bity :

    Bit 7 – TWINT: TWI Interrupt Flag
    Bit ten jest ustawiany sprzętowo po zakończeniu wykonywania przez układ TWI bieżącej operacji.
    Jeśli bit I w rejestrze statusu oraz bit TWIE w rejestrze TWCR jest ustawiony,
    to nastąpi wywołanie procedury obsługi przerwania od układi TWI.
    Bit TWINT jest zerowany programowo poprzez zapis jedynki.
    Należy pamiętać, że bit nie jest zerowany automatycznie po wywołaniu procedury obsługi przerwania.
    Należy również pamiętać, że wyzerowanie tego bitu rozpoczyna wykonywanie operacji przez układ TWI,
    tak więc wszelkie operacje na zawartości rejestrów TWAR, TWSR oraz TWDR muszą zostać zakończone
    przez wyzerowaniem bitu TWINT
    Bit 6 – TWEA: TWI Enable Acknowledge Bit
    Bit steruje generowaniem sygnału ACK.
    Jeśli bit TWEA jest ustawiony to sygnał ACK jest generowany w następujących okolicznościach :
    - układ odebrał własny adres Slave
    - odebrano sygnał globalnego wywołania przy ustawionym bicie TWGCE w rejestrze TWAR
    - odebrano dane w trybie Master Receiver lub Slave Receiver
    Bit 5 – TWSTA: TWI START Condition Bit
    Bit ten jest ustawiany w celu rozpoczęcia transmisji w trybie Master.
    Układ TWI sprawdza czy magistrala jest wolna i generuje sygnał START.
    Jeśli magistrala jest zajęta, układ TWI oczekuje na sygnał STOP i wystawia sygnał START
    w celu uzyskania statusu MASTER na magistali.
    Bit TWSTA musi zostać wyzerowany programowo po wygenerowaniu sygnału START.
    Bit 4 – TWSTO: TWI STOP Condition Bit
    Ustawienie bitu TWSTO powoduje wygenerowanie w trybie Master sygnału STOP na magistrali.
    Bit ten jest automatycznie zerowany po wygenerowaniu sygnału STOP.
    Bit 3 – TWWC: TWI Write Collision Flag
    Bit jest ustawiany przy próbie zapisu do rejestru TWDR przy wyzerowanym bicie TWINT.
    Bit jest zerowany po zapisie do rejestru TWDR przy ustawionym bicie TWINT.
    Bit 2 – TWEN: TWI Enable Bit
    Bit aktywujący interfejs TWI.
    Gdy bit TWEN jest ustawiony układ TWI przejmuje kontrolę nad wyprowadzeniami mikrokontrolera
    podłączonymi do linii SDA i SCL.
    Gdy bit TWEN jest wyzerowany, układ TWI jest wyłączany oraz wszelkie trwające operacje są przerywane.
    Bit 1 – Res: Reserved Bit
    Ten bit jest zarezerwowany.
    Bit 0 – TWIE: TWI Interrupt Enable
    Jeśli bit TWIE jest ustawiony, oraz bit I w rejestrze statusowym jest ustawiony,
    to przerwanie od układu TWI będzie aktywne tak długo, jak bit TWINT będzie ustawiony.


    No i należy pamiętać o rezystorach "podciągających" (coś pomiędzy 4,7kOm a 10kOm):
    1. linia SDA przez rezystor do plusa zasilania
    2. linia SCL przez rezystor do plusa zasilania

    ------------------------------------------------------------------------------