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

PCF8583 i2c – nie działa komunikacja, jak poprawnie obsłużyć magistralę i2c?

ksz 11 Lip 2006 01:26 2292 9
REKLAMA
  • #1 2809371
    ksz
    Poziom 15  
    Posty: 113
    Pomógł: 12
    Próbuję obsługiwać układ pcf8583 przez i2c, i wydaje się że komunikacja właśnie po i2c nie chce mi działać.. Kod do i2c pobrałem z internetu, nie znam na tyle tej magistrali, żeby samemu sobie to napisać.. Oto część kodu:
    
    
    #define SCL I2C_SCL
    
    #define SDA I2C_SDA
    
    void
    i2c_wbyte (uint8_t dana) 
    
    {								//wysłanie pojedynczego bajtu do Slave'a I2C
    
    	uint8_t i;
    
    	for (i = 0; i < 8; i++)	{ //będzie 8 bitów 
    		if (dana & 0x80) 		//badaj najstarszy bit wysyłanego znaku
    
    			I2C_DDR |= _BV (SDA);	//wyslij "1"
    
    		else
    			I2C_DDR &= ~_BV (SDA);	//wyslij "0"
    		//i2c_delay(0);
    
    		I2C_DDR |= _BV (SCL);
    		i2c_delay (i2cdelay);
    		I2C_DDR &= ~_BV (SCL);
    		i2c_delay (i2cdelay);
    		dana <<= 1;			//przygotuj następny bit do wysłania
    
    	}
    	I2C_DDR |= _BV (SDA);		//zwolnij linię SDA dla Slave'a
    
    	i2c_delay (i2cdelay);
    	I2C_DDR |= _BV (SCL);
    	//while(!(I2C_PIN & _BV (SCL)));   //czekaj, aż Slave będzie gotowy do przyjęcia następnego bitu
    	while (!SDA) ;			//czekaj, aż Slave będzie gotowy do przyjęcia następnego bitu
    
    	i2c_delay (i2cdelay);
    	i = I2C_PIN & _BV (SDA);	//czytaj potwierdzenie ACK od Slave'a
    
    	I2C_DDR &= ~_BV (SCL);
    	i2c_delay (i2cdelay);
    }
    
    uint8_t
    i2c_rbyte (bool ack) 
    
    {								//przyjęcie pojedynczego bajtu od Slave'a I2C
    
    	//parametr ack=1 oznacza, że jest wysyłany ostatni bajt bloku,
    
    	//nie należy więc wysyłać potwierdzenia
    
    	uint8_t dana = 0, i;
    
    	for (i = 0; i < 8; i++)	{ //będzie 8 bitów 
    
    		I2C_DDR &= ~_BV (SCL);
    		i2c_delay (i2cdelay);
    		I2C_DDR |= _BV (SCL);
    		i2c_delay (i2cdelay);
    		dana <<= 1;			//przygotuj miejsce na kolejny odebrany bit
    
    		dana |= ((I2C_PIN & _BV (SDA)) == 1 ? 1 : 0);	//dopisz odebrany bit  
    
    	}
    	I2C_DDR &= ~_BV (SCL);
    	if (ack) 					//czy wysyłać potwierdzenie?
    
    		I2C_DDR &= ~_BV (SDA);	//wyslij ACK
    	else
    		I2C_DDR |= _BV (SDA);	//brak potwierdzenia sygnalizuje zakończenie bloku
    
    	
    	i2c_delay (i2cdelay);
    	I2C_DDR |= _BV (SCL);
    	//while(!(I2C_PIN & _BV (SCL)));               //czekaj, aż Slave będzie gotowy do przyjęcia następnego bitu
    	while (!SDA) ;			//czekaj, aż Slave będzie gotowy do przyjęcia następnego bitu
    
    	i2c_delay (i2cdelay);
    	I2C_DDR |= _BV (SDA);		//zwolnij linię SDA
    
    	I2C_DDR &= ~_BV (SCL);
    	return dana;
    }
    


    U mnie nie chce to działać, program jest zaczerpnięty z tego formum, na forum widziałem, że kilka osób tego używa, ktoś miał jakiś problem może z 'uruchomieniem' tego kodu? Może coś trzeba zmienić?

    Dzięki z góry za pomoc, pozdr.
    Krzysiek
  • REKLAMA
  • #2 2809484
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • #4 2809632
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Co konkretnie definiują I2C_DDR,I2C_PIN,I2C_SCL i I2C_SDA
    Jak dla mnie , ten kod nie jest zbyt jasny :( Jeśli np. I2C_DDR jest "odpowiednikiem" rejestru kierunku dowolnego portu (DDRx), to ten kod nie może działać.Być może jest inaczej , ale dopuki nie przedstawisz co oznaczają powyższe makra , doputy nie jestem w stanie nic pomóc :(

    Piotrek
  • #5 2810210
    ksz
    Poziom 15  
    Posty: 113
    Pomógł: 12
    Zumek: dlaczego nie może działać? Oto te makra:

    /* konfiguracja i2c */
    #define I2C_DDR DDRD
    #define I2C_PORT PORTD
    #define I2C_PIN PIND
    #define I2C_SDA PD1
    #define I2C_SCL PD0

    Nie można tak definiować?

    pawelwiniarski0: uC - do testów obecnie at90s2313, docelowo ATmega8535, C - bo avr-gcc jest legalnie za darmo, bo pod linuksem piszę, bo znam C. Co do UARTa, go jednak też trzeba oprogramować, a w/w kod, nie ukrywam, jest zassany z sieci, wierzę, że jeśli ktoś coś publikuje, to to działa.. Poza tym UART póżniej wykorzystam do innych celów (też komunikacja szeregowa, ale całkowicie inna szyna, tę już trochę znam;>)
  • #6 2810326
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • #7 2810348
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    ksz napisał:
    Zumek: dlaczego nie może działać? Oto te makra:

    /* konfiguracja i2c */
    #define I2C_DDR DDRD
    #define I2C_PORT PORTD
    #define I2C_PIN PIND
    #define I2C_SDA PD1
    #define I2C_SCL PD0

    Nie można tak definiować?

    Definicje są jak najbardziej prawidłowe , ale kod jest do ... kitu :(
    Przeanalizujmy poniższy fragment:
    
    void
    i2c_wbyte (uint8_t dana)
    
    {                        //wysłanie pojedynczego bajtu do Slave'a I2C
    
       uint8_t i;
    
       for (i = 0; i < 8; i++)   { //będzie 8 bitów
          if (dana & 0x80)       //badaj najstarszy bit wysyłanego znaku
    //*****************************
    //poniższa linia ustawia kierunek portu na wyjście i na pinie SDA pojawi
    //się stan bitu SDA jaki jest zapisany w I2C_PORT .Jeśli to jest "1" , to OK , ale jeśli "0" ... ????
    
             I2C_DDR |= _BV (SDA);   //wyslij "1"
          else
    
    //************************************************
    //ta linia ustawia ustawia kierunek portu na wejście i bez względu 
    //na stan bitu SDA w I2C_PORT,na pinie SDA zawsze będzie stan wysoki ,
    // gdyż linia SDA powinna być podciągnięta do +VCC zewnętrznym rezystorem.
    //Poniższa linia kodu, nie jest w stanie ustawić "0" na pinie SDA.
    
             I2C_DDR &= ~_BV (SDA);   //wyslij "0" 
    ...
    
    

    Reszta kodu - nie sprawdzałem ;)
    Piotrek
  • REKLAMA
  • #8 2810370
    ksz
    Poziom 15  
    Posty: 113
    Pomógł: 12
    pawelwiniarski0: rozumiem że masz na myśli UART? Problem ogólnie mam taki, że muszę podsłuchiwać szynę EIB (europejski standard w inteligentym budynku) i tu zamierzałem wykorzystać UART, bo wydaje mi się (fixme jeśli się mylę), że nie da się pogodzić I2C i EIB..? I2C jest do zegarka na PCF8583, bo muszę notować czasy zmian urządzeń zarządzanych przez EIB.. I takie zapytanie na koniec co do dokumentacji Atmela do sprzętowego i2c, miałeś na myśli datasheet procesora, czy jakiś oddzielny plik? Bo chętnie się z tym zapoznam..

    dzięki, pozdro
    Krzysiek

    Dodano po 19 [minuty]:

    zumek napisał:


    [ciach]

    Reszta kodu - nie sprawdzałem ;)
    Piotrek


    ehh te i2c ;)
    a znasz może kod z przykładów na www.mikrokontrolery.net
    (http://www.mikrokontrolery.net/avr_c_09.htm )?
    Bo jego też nie mogę przekonać do współpracy:| A zmieniłem tylko piny na 0 i 1..
    Ma to znaczenie dla uC, których pinów używam? (Prócz tego o czym pisał pawelwiniarski0, czyli sprzętowe wsparcie..)
  • #9 2831817
    ksz
    Poziom 15  
    Posty: 113
    Pomógł: 12
    SIC! Mea culpa..
    Poczytałem sobie i o i2c i datasheet uC dokładniej.. Wszystko stało się jasne.. Hehh.. Sorki za zamieszanie..

    Dzięki za próby naprowadzania mnie..

    pozdrawiam
    Krzysiek
  • #10 2831947
    greatlukas
    Poziom 14  
    Posty: 122
    Pomógł: 3
    Ocena: 7
    Witam, może ci sie przyda
    // funkcja wysyłająca informacje do TDA7439 przez TWI (I2C)
    void TWI_send(unsigned char SADDR,unsigned char DATA)
    {
    
    // send START condition
        TWCR=(1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    // Wait for TWINT Flat set. This indicates that the START condition has been transmited
       while (!(TWCR & (1<<TWINT)));
    
    // wyślij adres urządzenia
       TWDR=SLA_W;
       TWCR=(1<<TWINT) | (1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
    
    // wyślij adres rejestru w urządzeniu, który ma byc zmodyfikowany
       TWDR=SADDR;
       TWCR=(1<<TWINT) | (1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
    
    // wartość jaką należy wprowadzić do wybranego wcześniej rejestru TDA7439
       TWDR=DATA;
       TWCR=(1<<TWINT) | (1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
    
    // wyślij warunek STOP
       TWCR= (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
       while (!(TWCR & (1<<TWSTO)));
    }


    nie zapomnij tylko najpierw ustawić częstotliwości transmisji np.
    //     f=10kHz
           TWSR|=(1<<TWPS0);
           TWBR=198;

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemów z komunikacją I2C z układem PCF8583, realizowanej za pomocą własnoręcznie napisanego kodu w języku C na mikrokontrolerach AVR (AT90S2313, docelowo ATmega8535). Autor stosuje programową implementację magistrali I2C, definiując piny SDA i SCL na portach mikrokontrolera, jednak napotyka na trudności z poprawnym przesyłaniem danych. Wskazano, że lepszym rozwiązaniem jest wykorzystanie sprzętowego modułu TWI (Two Wire Interface) dostępnego w mikrokontrolerach AVR, co znacznie upraszcza obsługę i zwiększa niezawodność komunikacji. Podkreślono, że linie I2C wymagają zewnętrznych rezystorów podciągających, a manipulowanie kierunkiem portu (DDR) zamiast poziomem na linii SDA jest błędne i prowadzi do nieprawidłowego działania. Zaproponowano zapoznanie się z dokumentacją Philipsa dotyczącą protokołu I2C oraz datasheetami Atmela dla sprzętowego TWI. Przykładowy kod obsługi TWI w AVR pokazano na przykładzie wysyłania danych do innego układu przez magistralę I2C. Autor przyznał, że po lekturze dokumentacji lepiej rozumie działanie magistrali i planuje wykorzystać sprzętowe wsparcie I2C zamiast programowej implementacji.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA