Skocz do zawartości

Atmega8 - niedziałające TWI


esio

Pomocna odpowiedź

Witam. Mam następujący problem z niedziałającym TWI. Mam kod na atmegę w C.

/* 
Czujnik ultradzwiekowy sterowany z magistrali i2c 
C= 2010 Grzegorz Eliszewski 
grzegorz(małpa)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ę:

Kod:

#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...

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.