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

[Atmega8] [TSL2561T] Błędne odczyty. Złe łączenie rejestrów

kornel_p 05 Sie 2010 21:27 2717 9
  • #1 8369011
    kornel_p
    Poziom 11  
    Witam!!

    Odczytuję z czujnika oświetlenia TSL2561 wartości z dwóch kanałów. Na wartość jednego kanału składają się dwa rejestry 8 bitowe. Po odczytaniu wszystkich czterech (CH0_Low, CH0_High; CH1_Low, CH1_High) łączę je w dwa 16 bitowe. próbowałem tak: ch0 = (ch0_high<<8)| ch0_low, ale i tak: ch0 = (ch0_high*0x100) + ch0_low.

    Przez chwilę wszystko odczytuje dobrze, ale jak zbliżę czujnik do żarówki, wartości wzrosną dość mocno, wtedy zaczynają się dziać cuda.... odczytane wartości dla kanału CH1 to: ch0_high:b2 ch0_low:4a, a po złączeniu takie cudo: b4a6 ....

    Dodam, ze od samego odczytu z TWI wszystkie funkcje i zmienne są typu uint8_t, a zmienne CH0, CH1 uint16_t... wczesniej próbowałem z unsigned int, ale było to samo.

    Program główny:
    #define F_CPU 8000000UL
    
    #include <avr/io.h>
    #include "HD44780.h"
    #include "twi.h"
    #include <math.h>
    
    int main (void)
    
    {
    	char array[5];	
    	LCD_Initalize();
    	TSL_Initalize();
    
     while (1)
     { 
    _delay_ms(1000);
    uint8_t ch0_low = TSL_CH0low_READ();
    uint8_t ch0_high = TSL_CH0high_READ();
    uint8_t ch1_low = TSL_CH1low_READ();
    uint8_t ch1_high = TSL_CH1high_READ();
    
    uint16_t ch0 = (ch0_high<<8)| ch0_low;
    uint16_t ch1 = (ch1_high<<8)| ch1_low;
    
    unsigned int lux = CalculateLux(0, 2, ch0, ch1, 0);
    
    	LCD_GoTo(0,0);
    	snprintf (array, sizeof(array), "%x", ch0);
    	LCD_WriteText(array);
    
    	LCD_GoTo(5,0);
    	snprintf (array, sizeof(array), "%x", ch1);
    	LCD_WriteText(array);
    
    	LCD_GoTo(10,0);
    	snprintf (array, sizeof(array), "%x", ch0_high);
    	LCD_WriteText(array);
    
    	LCD_GoTo(13,0);
    	snprintf (array, sizeof(array), "%x", ch0_low);
    	LCD_WriteText(array);
    
    	LCD_GoTo(0,1);
    	LCD_WriteText("Lx: ");
    	LCD_GoTo(3,1);
    	snprintf (array, sizeof(array), "%d", lux);
    	LCD_WriteText(array);
    
    	LCD_GoTo(10,1);
    	snprintf (array, sizeof(array), "%x", ch1_high);
    	LCD_WriteText(array);
    
    	LCD_GoTo(13,1);
    	snprintf (array, sizeof(array), "%x", ch1_low);
    	LCD_WriteText(array);
     }
    }


    Odczyt z czujnika:
    #include "TSL2561_read.h"
    #include <math.h>
    
    void TSL_Initalize(void)
    {
    	 /*-----Inicjalozacja czujnika-----*/
    	twistart();
    	twiwrite (SLA1_W);
    	twiwrite (0x01);
    	twiwrite (0x03);
    	twistop ();
    }
    
    uint8_t TSL_CH0low_READ(void)
    {
    /*-----Odczyt CH0low-----*/
    
    	twistart();
    	twiwrite (SLA1_W);
    	twiwrite (data0low);
    	twistart();
    	twiwrite (SLA1_R);
    	uint8_t ch0low = twiread (NOACK); //bez ACK
    	twistop ();
    	return ch0low;
    }
    uint8_t TSL_CH0high_READ(void)
    {
    /*-----Odczyt CH0high-----*/
    	twistart();
    	twiwrite (SLA1_W);
    	twiwrite (data0high);
    	twistart();
    	twiwrite (SLA1_R);
    	uint8_t ch0high = twiread (NOACK); //bez ACK
    	twistop ();
    	return ch0high;
    }
    
    uint8_t TSL_CH1low_READ(void)
    {
    /*-----Odczyt CH1low-----*/
    
    	twistart();
    	twiwrite (SLA1_W);
    	twiwrite (data1low);
    	twistart();
    	twiwrite (SLA1_R);
    	unsigned int ch1low = twiread (NOACK); //bez ACK
    	twistop ();
    	return ch1low;
    }
    uint8_t TSL_CH1high_READ(void)
    {
    /*-----Odczyt CH1high-----*/
    	twistart();
    	twiwrite (SLA1_W);
    	twiwrite (data1high);
    	twistart();
    	twiwrite (SLA1_R);
    	uint8_t ch1high = twiread (NOACK); //bez ACK
    	twistop ();
    	return ch1high;
    }
    


    I jeszcze obsługa TWI:
    #include "TWI.h"
    
    // procedura transmisji sygnału START
    void twistart(void)
    {
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    }
    
    // procedura transmisji sygnału STOP
    void twistop(void)
    {
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
    while ((TWCR & (1<<TWSTO)));
    }
    
    // procedura transmisji bajtu danych
    void twiwrite(uint8_t data)
    {
    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    }
    
    //procedura odczytu bajtu danych
    uint8_t twiread(uint8_t ack)
    {
    TWCR = ack
    ? ((1 << TWINT) | (1 << TWEN) | (1 << TWEA))
    : ((1 << TWINT) | (1 << TWEN)) ;
    while (!(TWCR & (1<<TWINT)));
    return TWDR;
    }


    Plików nagłówkowych już nie bedę wrzucał, bo chyba nie ma sensu (wydaje mi się, ze tam nie może być błędu)


    BARDZO PROSZĘ O POMOC, BO JUŻ NIE DAJĘ RADY !! ;/
  • #2 8374847
    Konto nie istnieje
    Konto nie istnieje  
  • #3 8380761
    levi_pl
    Poziom 11  
    Wydaje mi się, że operacje przesuwania bitów robisz na ośmiobitowej zmiennej. Zadeklaruj ją jako 16-bitową albo
    - podstaw wartość high pod zmienną szesnastobitową
    - przesuń o osiem bitów
    - dodaj wartość low

    Przyszło mi coś innego do głowy - skoro zawsze przesuwasz o osiem to warto by zadeklarować zmienne w tym samym miejscu pamięci tzn.

    &16bit = &high -1 = &low

    wtedy zapisujesz do high i low a czytasz z 16bit

    Myślę że nie jest to eleganckie i kompilator będzie zgłaszał ostrzeżenia
    Ma ktoś pomysł jak to ładnie zrobić ?

    Jeszcze jedna uwaga - wygląda na to, że większość wartości 16-bitowych jest przechowywana w pamięci jako little endian - bajt w komórce o niższym adresie będzie zawierał mniej znaczącą część wartości a komórka o wyższym adresie będzie przechowywała bardziej znaczącą część wartości.

    Znalazłem ciekawy wątek na AVRFreaks

    endian issue
  • #4 8380815
    Konto nie istnieje
    Konto nie istnieje  
  • #5 8381004
    levi_pl
    Poziom 11  
    _marek napisał:
    Levi_pl napisał ...

    Zmienna jest ok.
    uint16_t ch0 = (ch0_high<<8)| ch0_low; 


    zgodnie z priorytetami operatorów powinno to być równoważne zapisowi:

    uint16_t ch0 = ch0_high<<8 | ch0_low;

    Nie mam teraz możliwości sprawdzenia jak to zadziała a ciężko mi to wygooglać. Wiesz jak to zostanie rozbite na poszczególne operacje ?

    Znalazłem w FAQ do avr-libc:

    "Bitwise operations in Standard C will automatically promote their operands to an int, which is (by default) 16 bits in avr-gcc."
  • #6 8381291
    Konto nie istnieje
    Konto nie istnieje  
  • #7 8381446
    levi_pl
    Poziom 11  
    Troszkę nieprecyzyjnie się wyraziłem. Chodziło mi o to jak będą wyglądały operacje po rozbiciu tego złożonego wyrażenia i chyba sam sobie odpowiedziałem :-)

    Otóż:
    - bajt high będzie rzutowany na wartość 16 bitowa i przesunięty o osiem bitów
    - bajt low będzie rzutowany na wartość 16 bitową
    - oba operandy zostaną poddane operacji sumy logicznej
    - wynik zostanie przypisany zmiennej 16 bitowej

    Jeśli chciałbyś w ten sposób zsumować wartości 16 bitowe do 32 bitowej to nie zadziałałoby to dobrze bo przy przesunięciu bitów o 16 otrzymałbyś same zera.

    Co do tytułowego problemu. Twoja odpowiedź jest trochę enigmatyczna. Czy sugerujesz, że problemem jest tu konwersja do ASCII ?
  • #8 8383473
    Konto nie istnieje
    Konto nie istnieje  
  • #9 11779439
    Konto nie istnieje
    Poziom 1  
  • #10 12916479
    FastProject
    Poziom 28  
    Czy koledzy poradzili sobie z odczytam dużych jasności za pomocą TSL2561? Sam zastanawia m się czy go nie wykorzystać...
REKLAMA