Elektroda.pl
Elektroda.pl
X

Search our partners

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

[C]Atmega8 - TWI - niedziałająca magistrala

zadeqead 12 Jun 2010 12:20 2555 1
e-mierniki
  • #1
    zadeqead
    Level 12  
    Witam. Mam następujący problem z niedziałającym TWI. Mam kod na atmegę w C.

    Code:
    /*
    
    Czujnik ultradzwiekowy sterowany z magistrali i2c
    C= 2010 Grzegorz Eliszewski
    grzegorz(malpa)eliszewski.pl
    esio.eu
    */
    #define F_CPU 12000000UL // czestotliwosc kwarcu 12MHz

    #include <avr/io.h>
    #include <util/delay.h> // obsluga opoznien               
    #include <compat/twi.h> // obsluga magistrali i2c
    #include <avr/wdt.h> // obsluga watchdoga
    #include <avr/interrupt.h> // przerwania

    volatile uint8_t time=124; // czas potrzebny na powrot odbitych ultradzwiekow
    volatile uint8_t value; // dane odebrane na magistrali TWI

    // deklaracje wystąpienia funcji
    void pomiar(void);
    void signal(unsigned int o);
    unsigned int distance(unsigned int time);
    void twi_init(char adres);

    // obsluga magistrali i2c
    // przerwanie od TWI

    SIGNAL (SIG_2WIRE_SERIAL)
    {
       switch(TWSR) //odczytanie bitu sterujacego
       {
          case 0x00:   // nieoczekiwany start lub stop
             TWCR = (1<<TWSTO); // ustawienie 1 na bicie TWSTO = STOP!
             TWCR = (1<<TWINT); // ustawienie 1 na bicie TWINT = START!
             // w wypadku, gdy pojawi sie nieoczekiwany start lub stop na TWI to:
             // 1. transmisja jest zatrzymywana
             // 2. transmisja startuje ponownie
          break;
       // TWI w trybie MASTER - RECIVER
          case 0x60:   
             // TWSR = 0b11000000
             // wlasny SLA+W odebrany ACK nadane
          break;

          case 0x68: 
             // utrata kontroli nad magistrala, master odlaczony
             // wlasny SLA+W odebrany ACK nadane
          break;      
          case 0x80:
             // transmisja - odbior!
             // 1. odebrano SLA+W (adres + W jak write, czyli zapis do slave :))
             // 2. odebrano dane
             // 3. nadano ACK = bit potwierdzenia, oczekuje dalszej transmisji
             // value = TWDR; // TWDR = rejestr z danymi TWI
             if (TWDR == 0x01) // jezeli TWDR = 0b00000001
             {
                //pomiar(); // wykonanie pomiaru
                PORTD = 0xFF;
             }
          break;
          case 0x88:
             // transmisja - odbior!
             // 1. odebrano SLA+W
             // 2. odebrano dane
             // 3. nie nadano ACK (nadano NACK), potwierdzenie i koniec transmisji
             value = TWDR; // TWDR = rejestr z danymi TWI
             if (value == 0x01) // jezeli TWDR = 0b00000001
             {
                PORTD = 0xFF;
             //   pomiar(); // wykonanie pomiaru
             }
          break;
       // TWI w trybie MASTER - TRANSMITER
          case 0xA8:
             // transmisja - nadawanie!
             // 1. odebrano SLA+R (adres + odczyt ze slave)
             // 2. nadano ACK
             TWDR = time;    // zapisanie zmiennej czasu do TWDR
             TWCR = (1<<TWINT) | (1<<TWEN);    // wyczyszczenie TWINT
                         // wlaczenie TWI poprzez 1 na TWEN
                         // przygotowanie do wyslania danych
             while(!(TWCR & (1<<TWINT)));    // transmisja danych <- patrz dataszit
             // sprawdzanie statusu TWI
             if ((TW_STATUS) & (0xF8 != TW_MT_DATA_ACK))
             {
                // blad nadawania
             }
          break;
          
       }
    }


    // funkcja generujaca sygnal, o = ilosc okresow
    // generowanie sygnalu zblizonego do 40kHz, zmiana stanu co 12us zamiast co 12.5us
    void signal(unsigned int o)
    {
       int i;
       DDRB = 0xFF; // ustawienie portu B jako wyjscie
       // sbi(DDRB,6);
       // sbi(DDRB,2);
       for(i=0;i<o;i++)
       {
          // ustaw 1 na PB2 i 0 na PB1
          PORTB = 0x04;
          _delay_us(12); // czekaj 12us
             PORTB = 0x02;
          _delay_us(12);
       }
       // ustawienie stanu niskiego na porcie nadajnika
       // tlumienie nadajnika
       PORTB = 0x00;
       _delay_ms(1); // odczekanie 1ms = tlumienie nadajnika
    }

    // pomiar odleglosci, o = ilosc okresow
    // wyslanie sygnalu i odbior odbitego od przeszkody
    void pomiar(void)
    {
       TCNT1 = 0x0000; // zerowanie licznika T1
       signal(5); // emitowanie 5 okresow sygnalu sterujacego
       // _delay_ms(10); // odczekanie 10ms przed pomiarem
       TCCR1B = 0x05;    // start T1 jako licznik z prescalerem /1024 0b00000010
             // zliczanie co 12Mhz/1024
             // czestotliwosc 11.71875kHz
             // czas jednego impulsu to okolo 85us

       while(TCNT1 < 0x0FA0) // dopoki licznik nie doliczy do 0x0FA
       {
          while(bit_is_clear(ADCSRA,ADIF)); // koniec pomiaru na ADC
          {
          // jezeli wartosc na ADC jest mniejsze niz !czulosc! to przerwij odliczanie czasu
             if(ADCH > 100)
             {
                time = TCNT1; // przepisanie wartosci licznika do zmiennej
                TCNT1 = 0xFFFF; // przepelnienie licznika == wyjscie z petli
             }
          }   
       }
       TCCR1B = 0x00; // wylaczenie licznika
    //   wdt_reset(); // resetowanie watchdoga
    /*
       for(echo=0;echo<666;echo++)  // petla obliczajaca odleglosc
       {
          if(bit_is_set(ACSR,ACO))  // jezeli odebrano sygnal powracajacy
          {
             break;  // wyjscie z petli
          }
       }*/
    //   return time;
          
    }
    // obliczanie rzeczywistej odleglosci w zaleznosci od czasu
    // sprawdzic jak to ma sie do siebie :P
    unsigned int distance(unsigned int time)
    {
       unsigned int czas_s;
       if (time < 60 )
       // 60 przebiegow zegara czyli okolo 5ms
       // mierzymy tylko w jedna strone
       // wynika z opoznienia na zwarcie czujnikow
       {
          return 0;
       }
       else
       {
          return 50 + time*1.5;
       }
       // V_dzwieku w powietrzu +/- 343 m/s
       // S = (V*t)/2 || droga [m] = predkosc [m/s] * czas [s]
       // czas [s] = time * 0.000085 | jeden cykl zegara to 85us
       // jeden cykl zegara to okolo 1.5cm
    }

    // inicjacja i konfiguracja magistrali TWI
    void twi_init(char adres)
    {

       DDRC = 0b00000000; // konfiguracja portu C jako wyjscie
       PORTC = 0b00110011; // PC5 PC4 jako wyjscie

       TWAR = adres; // przypisanie adresu
       TWSR = 0; // zerowanie statusu TWI
       TWCR = 0xC5;    // ustawienie TWCR 0b11000101
             // TWINT - oczekiwanie na odpowiedzi, uaktywnienie przerwania
             // TWEA - wlaczenie generowania ACK
             // TWEN - aktywacja obslugi TWI, aktywacja interface TWI
             // TWIE - uaktywnienie obslugi przerwan TWI
    }

    // funkcja glowna
    int main(void)
    {
       twi_init(0x02); // inicjacja TWI z adresem 0x02

       // konfiguracja ADC
       ADMUX = 0x61; // konfiguracja działania ADC 0b01100001
       ADCSRA = 0xC6; // start ADC prescaler /64, f = 187.5kHz

    //   wdt_enable(WDTO_250MS); // watchdog na 250ms
       sei(); // wlaczenie obslugi przerwan
       
       DDRD = 0xFF; // port D jako wyjscie
    }


    Problem polega na tym, że jak wysyłam do czujnika na adres 0x10 wartość 0x01 to nie zapala mi się dioda, tak samo z odczytem. Testuje za pomocą arduino. Nie mam pojęcia co robię źle, to pierwsze moje spotkanie z TWI i nie wiem, może popełniłem jakiś prosty błąd.
    Wrzuciłem program zmodyfikowany do tego, żeby testować sam interfejs.
    Kod arduino za pomocą którego testuję magistralę:
    Code:

    #include <Wire.h>
    int ledPin =  13;

    void setup()
    {
      Serial.begin(9600);
      Wire.begin(); // join i2c bus (address optional for master)
      pinMode(ledPin, OUTPUT);     
    }
    int zz = 0;
    byte x = 0x01;

    void loop()
    {
      Wire.beginTransmission(0x10); // transmit to device #4
      //Wire.send("x is ");        // sends five bytes
      Wire.send(0x01);              // sends one byte 
      Wire.endTransmission();    // stop transmitting
      digitalWrite(ledPin, HIGH);   // set the LED on
                 // wait for a second
     Wire.requestFrom(0x10, 8);
     if (Wire.available()) {
        zz = Wire.receive();
      }
      else zz = 15;
      //x++;
     Serial.print(zz);
       digitalWrite(ledPin, LOW);
        delay(500);
    }


    Serial pokazuje, że magistrala nie jest gotowa, czyli wywala liczbe 15... zamiast odczytu z czujnika.
    Przewaliłem tony dokumentacji i nadal nie wiem co jest...
    Do you have a problem with Arduino? Ask question. Visit our forum Arduino.
  • e-mierniki
  • #2
    flapo213
    Level 21  
    Witaj,

    Przypomnij się na email to podrzucę na forum obsługę TWI do Atmeg napisaną w C działającą na 100%. TWI nie jest trudne ale z tego co pamiętam to jest tam jakiś myczek z zapisem do rejestrów.

    Pozdrawiam

    Dodano po 3 [godziny] 34 [minuty]:

    Witam, autor tematu otrzymał już obsługę I2C w C, ale tak sobie pomyślałem że od czasu do czasu pojawia się takiż problem dlatego postanowiłem zamieścić procedury obsługi I2C dla Atmeg w trybie mastera. Pobranie wolne od opłat punktowych. Naturalnie niektóre algorytmy można by zoptymalizować ale zrobi to równie dobrze optymalizator. W razie pytań pytać.

    Pozdrawiam