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

I2C/ATmega8/C - Pisanie własnej biblioteki do obsługi I2C w C pod ATmega8

marijuz 21 Sie 2016 19:34 2007 11
REKLAMA
  • #1 15882442
    marijuz
    Poziom 18  
    Cześć!
    Wpadł mi w ręce czujnik temperatury i ciśnienia BMP180 i postanowiłem zrobić z niego użytek. A że należy go obsługiwać przez I2C, a nie miałem z tym standardem do czynienia, to wziąłem się za pisanie własnej biblioteki obsługującej I2C. Oczywiście zadanie nie jest proste i już natknąłem się na problem, ale mam nadzieję, że z waszą pomocą się uda.

    A problem jest taki, że ATmega nie odczytuje danych. Wiem że potrafi poprawnie wysłać dane, bo czujnik reaguje na swój adres - wysyła potwierdzenie tak jak powinien. Na przypadkowy adres nie reaguje, a na swój owszem, więc myslę że wysyłanie danych jest ok ;-)

    Gorzej jeśli chodzi o odbiór. Coś jest ewidentnie nie tak. Odbiera albo wszystkie 8 bitów jako 1, albo wszystkie jako 0. Co ciekawe atmega programowana co drugi raz wyświetla inny wynik - raz 0, raz 225.

    Pewnie chodzi o jakiś głupi błąd, ale wprawne oko w moment go wyłapie. Proszę też o wyrozumiałość, bo z C bawię się dopiero kilka dni, dotychczas uzywałem bascoma, jednak demo okazało się niewystarczające do moich celów.

    Poniżej kod i opisuję przy felernej procedurze co autor miał na mysli ;-)
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Zaznaczę że podciągnąłem SDA i SCL rezystorami do Vcc,

    Proszę o pomoc i pozdrawiam.[/code]
  • REKLAMA
  • Pomocny post
    #2 15882610
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • Pomocny post
    #3 15882704
    excray
    Poziom 41  
    I2C wymaga sterowania wyjściem OD/OC a co za tym idzie używanie rejestru PORT do ustawiania stanu wysokiego to mocno nietrafiony pomysł. kolejny nietrafiony to używanie operacji XOR do sterowania stanem linii. Zdecydowanie zaciemnia kod nie przynosząc żadnych realnych korzyści.
  • #4 15882706
    marijuz
    Poziom 18  
    Szczerze mówiąc to nawet nie wiedziałem że można to zrobić sprzętowo. A poza tym dużo dowiedziałem się o protokole, więc mimo wszystko nie żałuję że zabrałem się za pisanie tej biblioteki. Tylko gdyby ktoś wskazał mi gdzie jest błąd w tym nieszczęsnym odczycie, byłbym bardzo wdzięczny.


    EDIT
    Cenna uwaga, dziękuję, poczytam o otwartym drenie/kolektorze. Faktycznie XOR okazał się trochę niewygodny, ale przekonałem się o tym w połowie kodu i uznałem że jak zacznę wszystko zmieniać, to się posypie ;-)
  • Pomocny post
    #5 15882719
    excray
    Poziom 41  
    Aha, operacje tego typu: PORTC&=(0<<5)+(0<<4); nie przynoszą efektu takiego jaki oczekujesz. 0 się nie przesuwa bitowo w C. W praktyce ta komenda zostanie zrealizowana tak: PORTC &= 0; Powinieneś napisać tak: PORTC &=~((1<<5)+(1<<4));
  • #6 15882725
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • Pomocny post
    #7 15882733
    excray
    Poziom 41  
    Dokładnie. A przede wszystkim operuj rejestrem DDR a nie PORT. Bo spalisz sobie tego BMP180.
  • REKLAMA
  • #8 15882738
    marijuz
    Poziom 18  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #9 15882739
    Konto nie istnieje
    Konto nie istnieje  
  • #10 15882916
    marijuz
    Poziom 18  
    No przyznaję się że nie mam pojęcia jak można operować rejestrem DDR. Byłem przekonany że służy do ustawiania kierunku portu.
  • Pomocny post
    #11 15882996
    Konto nie istnieje
    Konto nie istnieje  
  • #12 15883120
    excray
    Poziom 41  
    Pisałem Ci o wyjściu typu OC/OD - otwarty kolektor/dren. Takie wyjście ma to do siebie, że w stanie niskim zwiera magistralę do masy (silny niski stan - 0), a w wysokim zwalnia ją tworząc stan wysokiej impedancji (stąd zewnętrzne oporniki wymuszające). Takiego wyjścia wymaga magistrala I2C, aby unikać konfliktów gdy jedno urządzenie wystawi 0 a inne 1 na tej samej linii. Takiego wyjścia też w zasadzie nie ma atmega. Sterując rejestrem PORT masz albo silny stan niski albo silny wysoki. Dlatego wykorzystuje się pewien trik - sterowanie rejestrem DDR. Trzeba najpierw ustawić rejestr PORT na 0 dla odpowiednich linii, a następnie sterujesz bitami w DDR. Jak ustawisz wejście to linia przechodzi w stan wysokiej impedancji a zewnętrzne oporniki robią swoje. A jak jako wyjście to masz silne 0 na wyjściu, bo przecież do rejestru PORT tej linii wpisaliśmy wcześniej 0. Czyli osiągamy dokładnie to czego oczekujemy. Trzeba tylko pamiętać, że jest tutaj pewna negacja tzn. ustawienie 1 w DDR powoduje przejście linii w 0, a ustawienie 0 w DDR powoduje podciągnięcie linii przez opornik do +V czyli logiczne 1. Dlatego przykładowa definicja dla linii SCL/SDA wygląda tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
REKLAMA