Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

ATmega8, ADXL345, I2C/TWI zawiesza się, nie odczytuje danych.

bart_90 20 Nov 2014 10:00 1911 11
Computer Controls
  • #1
    bart_90
    Level 9  
    Witam,
    od kilku dni próbuję uporać się z problemem odczytu danych z akcelerometru ADXL345 przez standard TWI/I2C.
    W nocie katalogowej jest napisane, że jeżeli SDO podłączone jest do GND, akcelerometr przyjmuje adresy 0xA6 read i 0XA7 write. Tak też zrobiłem. Pin CS podłączony do +5V. Do ATmegi8 podłączony mam rezonator kwarcowy 16 MHz. Prędkość TWI ustawiłem na standardową prędkość 100 kHz. Wyliczyłem to za pomocą wzoru ((16 MHz/100 kHz)-16)/2= 72 => TWBR = 0x48.

    Mój problem polega na tym iż nie mogę odczytać i wyświetlić danych z akcelerometru.
    Konfiguracja ADXL345 przebiega poprawnie (przez co wnoszę, że adresy są poprawne). Kiedy program chce odczytać dane z osi X znajdujące się pod adresem 0x32, zawiesza się. W kodzie programu zaznaczyłem to miejsce dość widocznie. Gdy zaneguje tę operację program przechodzi dalej wyświetlając "odczytane dane" i wchodzi w ostatnią pętlę, migając diodą.

    Wszystko zasilane jest przy pomocy USBASP_ATB ? czy to może generować mój problemem?
    Może źle coś przeliczyłem lub podłączyłem? Bardzo proszę o pomoc!
    Schemat oraz kod programu znajduje się poniżej.

    Żeby wyprzedzić już niepotrzebne pytania. Tak, są rezystory podciągające do SCL oraz SDA, są one widoczne na schemacie.
    Jak wynika z kodu, odczytuję jeden bajt danych osi X ? być może i tu jest problem. Może powinienem od razu całą paczkę odczytywać?

    Code: c
    Log in, to see the code

    ATmega8, ADXL345, I2C/TWI zawiesza się, nie odczytuje danych. ATmega8, ADXL345, I2C/TWI zawiesza się, nie odczytuje danych.

    Żeby nie było niedomówień - na schemacie ATmegi8 piny SV1 należą do P1 na schemacie płytki ADXL345, drugi analogicznie.

    Ostatnią przyczyną błędów może byś po prostu uszkodzone urządzenie, niestety nie mam jak tego sprawdzić. Pozostaje mi jedynie zamówić kolejny...
  • Computer Controls
  • #2
    Sparrowhawk
    Level 22  
    Code: cpp
    Log in, to see the code


    Code: cpp
    Log in, to see the code


    Nie wiem, czy tylko to jest powodem, ale starasz się zapisać dane pod nieistniejący adres. Przekraczasz zakres. Jeżeli tak masz zadeklarowany bufor, to ostatnim elementem jest 15 element.

    W C/C++ indeksy tablicy n-elementowej są z zakresu 0 .. n-1.
  • Computer Controls
  • #3
    bart_90
    Level 9  
    A nie jest przypadkiem tak, tak że jeżeli tworzymy tablice [16] to jest ona 16to komórkowa lecz indeks zaczyna się od 0 do 15?

    Zrozumiałem to w ten sposób że musiałbym tworzyć tab[15] żeby mieć 16to komórkową, a to nie prawda, tak przynajmniej mi się wydaje.

    Bez zmian.
  • #4
    hexen2k
    Level 16  
    bart_90 wrote:
    while ((TWCR&(1<<TWSTO))); // tu niektórzy ludzie mają wykrzyknik, inni nie, dlaczego?


    Zobacz na stronie Radosława Kwietnia:
    http://radzio.dxp.pl/twi/

    Masz opis bitu TWSTO.

    Generalnie czekasz na zakończenie transmisji sygnału STOP w pętli whiile. Gdy transmisja się zakończy bit jest automatycznie zerowany i pętla jest przerywana.

    Wykrzyknik w innych kodach w tym miejscu wydaje się najzwyklejszym błędem.
  • #5
    dondu
    Moderator on vacation ...
    bart_90 wrote:
    A nie jest przypadkiem tak, tak że jeżeli tworzymy tablice [16] to jest ona 16to komórkowa lecz indeks zaczyna się od 0 do 15?

    No przecież kolega Sparrowhawk napisał:

    Sparrowhawk wrote:
    W C/C++ indeksy tablicy n-elementowej są z zakresu 0 .. n-1.


    Skompiluj sobie poniższy program w kompilatorze CManiak: http://mikrokontrolery.blogspot.com/p/cmaniak-kompilator-jezyka-c-online.html

    Code: c
    Log in, to see the code

    i przeanalizuj rezultat.
  • #6
    bart_90
    Level 9  
    Przeanalizowałem wszystko, dzięki za podpowiedzi. Doszedłem natomiast do tego, że nie można tak zapisywać danych do tablicy. To co ja chciałem zrobić jest błędem, ponieważ, po pierwsze chciałem zapisać daną liczbę do rzeczywiście nieistniejącej komórki tablicy, po drugie, nawet jeżeli bym chciał zrobić:
    Code: csharp
    Log in, to see the code

    to nie jest to możliwe.

    Ta linijka programu próbuje całą, 16-to bitową wartość sczytaną z ADXL345 wcisnąć w jedną ostatnią komórkę tablicy.
    Np.
    bufor[0] = 0;
    bufor[1] = 0;
    bufor[2] = 0;
    .
    .
    .
    bufor[15] = 0000111100001111; // błąd!!!
    Powinienem skorzystać ze wskaźnika i każdą cyfrę z osobna powinienem wrzucić do osobnej komórki? Nie wiem jeszcze jak tego zrobić bo nie działałem na wskaźnikach.
    Dobrze myślę?

    A może mógłbym po prostu zapisać wynik w dwóch zmiennych 8 bitowych, pierwsza by była od 0 do 7 bit druga od 8 do 15?
    Jak to zrobić programowo?
  • #7
    vonar
    Level 28  
    bart_90 wrote:
    Ta linijka programu próbuje całą, 16-to bitową wartość sczytaną z ADXL345 wcisnąć w jedną ostatnią komórkę tablicy.

    Nie. Nawet gdyby ta funkcja zwracała wartość 16-bitową (a tak nie jest, o ile wciąż wygląda tak, jak w pierwszym poście), to i tak wynik zostałby obcięty do jednego bajtu podczas zapisu do tablicy.
  • #8
    bart_90
    Level 9  
    W takim razie w jaki sposób mam przydzielić te dane do osobnych komórek?
    Może w ogóle zrezygnować z tablicowej koncepcji i tak jak napisałem wyżej, zapisać dane w dwóch zmiennych?
    Proszę o podpowiedź.
  • #9
    Sparrowhawk
    Level 22  
    No skoro funkcja ma zwracać wartość 16 bitową, to niech taką zwraca, ale nie robi się tego za pomocą tablicy.

    W tej chwili twoja funkcja odczytu zwraca 8 bitową wartość, nie oczekując na drugi bajt danych.
  • #10
    bart_90
    Level 9  
    Zrozumiałem w końcu... tak mi się wydaje.
    Trzeba z TWI/I2C odebrać dwa bajty, nie tylko jeden jak jest u mnie...
    Zaraz zabiorę się za przekształcenie kodu. Niestety nie sprawdzę tego teraz ponieważ jestem w pracy.
    Wieczorem popróbuje. Mam nadzieję, że w końcu coś się ruszy.
  • #11
    bart_90
    Level 9  
    Witam,
    dalej się męczę z tym tematem, co prawda nie mam zbyt wiele czasu na co dzień dlatego nie udzielam się zbyt często, a szkoda.

    Zmodyfikowałem kod programu wykorzystując przykłady z książki Pana Kardasia lecz dalej bez zmian, a nawet gorzej, teraz przy inicjalizacji ADXL345 program wchodzi do pętli STOP i już z niej nie wychodzi, nie mówiąc już o odbieraniu danych.
    Bardzo proszę o pomoc lub podpowiedź.

    Code: csharp
    Log in, to see the code


    Działanie programu jest bardzo podobne co do poprzedniego lecz bez wyświetlacza.
    Po udanej inicjalizacji oraz odczytaniu dwóch bajtów wchodzi w nieskończoną pętle zapalając i gasząc diodę z pewną częstotliwością, która informuje o poprawnym wykonaniu operacji.
    Jak widać zanegowałem na razie odczyt danych oraz część inicjalizacji ponieważ już podczas wysyłania pierwszego bajtu danych z konfiguracją ( adxl_init() ) program zawiesza się nie wychodząc z pętli TWI_stop(), co zaznaczyłem w kodzie programu.

    Bardzo proszę o pomoc bo już nie wiem co mam robić.
    Zamówiłem wczoraj kolejny akcelerator z tym samym czujnikiem lecz inną płytką. Może mój jest uszkodzony, może nie. Na pewno się oby dwa przydadzą o ile będą sprawne, a ja dojdę do jakiegoś konsensusu.
  • #12
    Andrzej__S
    Level 28  
    Zadeklarowałeś:
    Code: c
    Log in, to see the code

    później w pętli głównej wywołujesz funkcję adxl_init() w której wysyłasz bufor do ADXL345:
    Code: c
    Log in, to see the code

    a co jest w tym momencie w buforze, czyli co tak naprawdę wysyłasz?

    bart_90 wrote:
    ...ponieważ już podczas wysyłania pierwszego bajtu danych z konfiguracją ( adxl_init() ) program zawiesza się nie wychodząc z pętli TWI_stop(), co zaznaczyłem w kodzie programu.

    Jak sprawdzasz, że akurat ta linijka sprawia problem?

    Sam fakt wpisania odpowiednich wartości do TWDR i TWCR nie gwarantuje, że transmisja na magistrali przebiegnie prawidłowo. Rejestr TWSR zawiera ważne informacje o tym, co dzieje się na magistrali podczas transmisji, a Ty nawet nie sprawdzasz, czy układ slave odpowiedział bitem potwierdzenia.

    W datasheet na stronie 170 masz przykład, jak wykorzystać rejestr TWSR. Na stronie 173 są wartości TWSR informujące o statusie transmisji.