logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

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

zadeqead 12 Cze 2010 12:20 2642 1
REKLAMA
  • #1 8181745
    zadeqead
    Poziom 12  
    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@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ę:
    
    #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...
  • REKLAMA
  • #2 8199888
    flapo213
    Poziom 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
REKLAMA