Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[AVR][C] Czujnik temperatury, prośba z znalezieniu błędu

oskar777 17 Gru 2010 00:28 3447 27
  • #1 17 Gru 2010 00:28
    oskar777

    Poziom 25  

    Witam Was. Mam taką prośbę. Otóż chciałem uruchomić czujnik temperatury, ponieważ LCD udało mi się uruchomić tak więc postanowiłem iść dalej za ciosem :>.

    Niestety układ nie działa. Przedstawię kod i opiszę co i jak.
    led.c <- tak się nazywa tymczasowo główny plik.
    Kod:

    Code:

    #define F_CPU 16000000   
    #include <avr/io.h>
    #include <util/delay.h>               
    #include <HD44780.h>         
    #include <ds18b20.h>         


    extern volatile unsigned int DS18B20_Timeout;
    extern int    Temp[8] ;
    extern int Temperatura ;


    int main(void)
    {
    LCD_Initalize();

        while (1)
        {
       LCD_Clear();
       TempDS18B20();
          _delay_ms(200);
          char buffer;
          itoa(Temp, buffer, 10);
          LCD_WriteText(buffer);
          _delay_ms(5000);
          
        }
     
       
    }



    I tak docelowo chciałem odczytać temperaturę z 3-5 czujników, podłączonych osobno do każdego pinu procesora.

    Na razie jest to jeden czujnik podłączony do PD6 (12 nóżka) atmegi 8.
    Zmodyfikowałem trochę kod pod jeden czujnik ale chyba nie udolnie.

    Code:

    /******************************************************************************
    oraz w przerwaniu co 50us :
    Kod:
    if (DS18B20_Timeout>0) DS18B20_Timeout--;

    One wire library

    ******************************************************************************/
    #define F_CPU      16000000 //częstotliwość zegara w Hz

    #include "ds18b20.h"
    #include <avr/interrupt.h>
    #include <avr/io.h>
    #include <util/delay.h>

    int Temperatura ;
    int    Temp[8] ;
    uint8_t cnt;
    char   TempError ;
    volatile int DS18B20_Timeout;

    uint8_t  OW_PIN ; // PB4
    uint8_t *OW_IN  ; // PINB
    uint8_t *OW_OUT ; // PORTB
    uint8_t *OW_DDR ; // DDRB

    #define OW_GET_IN()    bit_is_set(*OW_IN,OW_PIN)  // *OW_IN & (1 << OW_PIN)
    #define OW_DIR_IN()    *OW_DDR &= (~(1 << OW_PIN ))
    #define OW_DIR_OUT()   *OW_DDR |= (1 << OW_PIN)

    enum {A,B};
    char watek = A;





    // definicja sensorow   
    //uint8_t SENS[8][2] = {{&PORTD,5},{&PORTD,6},{&PORTD,7},{&PORTB,0},{&PORTB,1},{&PORTB,2},{&PORTB,3},{&PORTB,4}};
    // definicja sensora  (TU PRÓBOWAŁEM ZMIENIĆ NA JEDEN CZUJNIK :( )
    uint8_t SENS[0][2] = {{&PORTD,6}};

    void
    ow_setup(unsigned char sensor)
    {

       uint8_t *ptr = (uint8_t*)(SENS[sensor][0]) ;   

       OW_OUT = ptr ;
       OW_DDR = ptr-1 ;
       OW_IN  = ptr-2 ;

       OW_PIN = (SENS[sensor][1]) ;
       
    }

    unsigned char
    ow_reset(void) // 900 us
    {
       uint8_t err=1;
       cli();
       OW_DIR_OUT();   
       _delay_us(480);
       OW_DIR_IN();
       _delay_us(70);
       err = OW_GET_IN();
       _delay_us(410);
       sei();
    return err;
    }

    unsigned char
    ow_read_bit(void) // 70 us
    {   
       unsigned char b = 0;
       
       OW_DIR_OUT();
       _delay_us(6);
       OW_DIR_IN();
       _delay_us(9);
       b = OW_GET_IN();
       _delay_us(55);
       
    return b;
    }

    void
    ow_write_bit(char b) // 70 us
    {
       
       OW_DIR_OUT();
       _delay_us(6);
       if (b) OW_DIR_IN();
       _delay_us(64);
       OW_DIR_IN();
       
    }

    void
    ow_write_byte(char data)
    {
    unsigned char i, temp;
       cli();
       for(i=0;i<8;i++)
       {
       temp=data>>i;
       temp &= 0x01;
       ow_write_bit(temp);
       }
       sei();
    }

    unsigned char
    ow_read_byte (void)
    {
    unsigned char i;
    unsigned char value=0;
       cli();
       for (i=0;i<8;i++)
       {
       if(ow_read_bit()) value |= 0x01<<i;
       _delay_us(6);
       }
       sei();
    return (value);
    }

    void
    TempDS18B20 (void)
    {
       unsigned char msb, lsb = 0;

       switch (watek)
       {
       case A:   
         if (DS18B20_Timeout) { break; }
       
         cnt++;
         //if(cnt>7) cnt = 0 ;  // ORYGINALNY ZAPIS
         if(cnt>1) cnt = 0 ;   // TU ZMIENIŁEM     
         ow_setup( cnt ) ;

         if ( ow_reset() ) { Temp[cnt] = 10000 ; break ; }
       
         ow_write_byte(0xCC);
         ow_write_byte(0x44);   
         DS18B20_Timeout = 760 * 20;
         watek = B ;
         break;

       case B:
         if (DS18B20_Timeout) { break; }
       
         ow_reset() ;
          ow_write_byte(0xCC);
          ow_write_byte(0xBE);     
         lsb = ow_read_byte() ;
         msb = ow_read_byte() ;
                 
         Temp[cnt] = (msb<<8 | lsb) * 10 / 16 ;
       
         DS18B20_Timeout = 1 * 20 ;
         
         PORTD ^= _BV(4) ;
       
         watek = A ;
         break;

       default:break;
       } ;

    }


    Ponieważ, uczę się C tak więc podejrzewam, że nie wiem jak poprawnie odczytać dane. LCD pokazuje ciąg 7-miu znaków na tą chwilę 8010108 chociaż pewnie to nic nie znaczy albo pokazują się krzaki tzn połowa krzaków połowa cyfr, ale o tej samej liczbie.

    Tam jest jeszcze informacja by do timera dodać zapis ale jeszcze timerów nie poznałem, może da się to jakoś ominąć. Albo wie ktoś jak użyć timera.

    Program ogólnie się kompiluje.
    Czujnik jest podłączony nie-pasożytniczo.

    Swoją droga jak się odwołać do każdego czujnika z osobna ?, czy automatycznie w pętli nadpisuje zmienną temp


    Będę wdzięczny za pomoc, bo pół dnia nad tym spędziłem i nie wiem o co chodzi.


    Pozdrawiam
    Oskar

    0 27
  • #2 17 Gru 2010 08:10
    tmf
    Moderator Mikrokontrolery Projektowanie

    Zmienna buffer ma nie być typu char, tylko typu tablicowego, tak aby mogła pomieścić wynik konwersji. Poza tym po rozpoczeciu konwersji opóźnienie 200ms to za mało. Te układy w zależności od rozdzielczości potrzebują ponad 650ms.

    0
  • #3 17 Gru 2010 09:19
    oskar777

    Poziom 25  

    Dzięki, ale to jeszcze nie to, dałem

    Code:

    _delay_ms(700);
    char buffer;
    itoa(Temp[1], buffer, 10);
    albo
    _delay_ms(700);
    int buffer;
    itoa(Temp, buffer, 10);


    Ale wynik nadal jest ten sam.

    0
  • #4 17 Gru 2010 09:36
    tmf
    Moderator Mikrokontrolery Projektowanie

    Bo nadal nie zmieniłeś zmiennej Buffer. Pomyśl, jest o typie char, który ma 8 bitów, a wynikiem konwersji jest łańcuch o długości kilku bajtów! Jak chcesz go pomieścić w zmiennej o typie char?

    0
  • #5 17 Gru 2010 10:03
    oskar777

    Poziom 25  

    Tyle co mi się wydaje to z tego kodu

    Code:

    Temp[cnt] = (msb<<8 | lsb) * 10 / 16 ;


    to Temp[1] powinna mieć zapisaną temperaturę jako int czyli -55 do 120 chyba.

    wynik konwersji chyba, też mam dobrze. Przynajmniej tak w opisie tej funkcji znalazłem
    Cytat:
    For converting a number to a string in base 8 (octal), 10 (decimal), or 16 (hexadecimal),


    Może się źle odnoszę do pojedynczego elementu tablicy ?, albo źle typ określam ?

    Znalazłem chyba poprawny sposób odczytu danych czyli

    Code:

    char buffer[4];
          itoa(Temp[1], buffer, 10);
          LCD_WriteText(buffer);


    Nadal nie odczytuje temperatury ale przynajmniej jest chyba ok w tym miejscu

    0
  • #6 17 Gru 2010 10:59
    tmf
    Moderator Mikrokontrolery Projektowanie

    Też nie jest ok, bo wynik konwersji liczby int na string może mieć max. 7 bajtów (-32768 null).
    Jak się z tym uporasz to sprawdź same procedury OW, czy zwracają sensowne wartości.

    0
  • #7 17 Gru 2010 11:46
    oskar777

    Poziom 25  

    Zrobiłem kilka testów

    Code:

    // przed main
    char bit;
    // dalej  w pętli
    bit = ow_read_bit();      
    char buffera[7];
    itoa(bit, buffera, 10);
    LCD_WriteText(buffera);

    // wynik po pierwszym przejściu pętli 1 potem cały czas 64
    // dalej przed main
    uint8_t  rr;
    // potem w pętli
    rr=  ow_reset();
    char bufferb[7];
    itoa(rr, bufferb, 10);
    LCD_WriteText(bufferb);
    // wynik cały czas 0


    Wynik taki jest przy uruchomieniu przed wszystkim funkcji
    TempDS18B20();
    Jeżeli nie jest zainicjalizowana to mam 0 i 0 w obydwóch funkcjach.

    Jak to interpretować ?

    0
  • #8 17 Gru 2010 12:09
    tmf
    Moderator Mikrokontrolery Projektowanie

    Że otrzymujesz reset pulse. Co do pierwszego to nie da się tego zinterpretować, bo magistralę OW trzeba wprowadzić w określony stan, żeby czytać bity. Przeanalizuj kod, który wykorzystujesz, albo napisz własny - przynajmniej się nauczysz o co w tym chodzi. Notę katalogową czujnika czytałeś?

    0
  • #9 17 Gru 2010 12:13
    oskar777

    Poziom 25  

    No nie uczyłem sie jej na pamięć ale przeglądałem ją, może gdzieś znajdę działający kod na jednym czujniku w celu porównania. Na razie na forum nic kompletnego nie widziałem.

    0
  • Pomocny post
    #10 17 Gru 2010 12:21
    atom1477
    Poziom 43  

    Code:
    static uint8_t onewire_0_reset(void) ;
    
    static void onewire_0_WriteByte(uint8_t data);
    static uint8_t onewire_0_ReadByte(void);

    #define WIRE_PORT_0 PORTC
    #define WIRE_DIR_0 DDRC
    #define WIRE_PIN_0 PINC
    #define WIRE_CON_0 3

    union int16_t_LSB_MSB
        {
        struct
            {
            uint8_t LSB;
            uint8_t MSB;
            };
          
            int16_t XSB;
        };

    union int16_t_LSB_MSB Temperature;
    volatile char Text[20];

    //-------------------------------------------------------------------------
    static uint8_t onewire_0_reset(void)
    {
        WIRE_DIR_0 |= 1<<WIRE_CON_0;        //pin 1wire jako wyjscie
        WIRE_PORT_0 &= ~(1<<WIRE_CON_0);   //pin 1wire -> 0
        _delay_us(650);               //tx reset pulse
       WIRE_DIR_0 &= ~(1<<WIRE_CON_0);    //pin 1wire jako wejscie
        //WIRE_PORT_0 |= 1<<WIRE_CON_0;       //pin 1wire -> 1 (koniec reset pulse)/pullup na wejscie
        _delay_us(70);
        if (bit_is_set(WIRE_PIN_0,WIRE_CON_0))
            {
            _delay_us(500);           //tx reset pulse
            return 1;                 //zwraca jedynke jesli slave milczy
          
            }
        else
            {
            _delay_us(500);           //tx reset pulse
          
            return 0;                 //zwraca zero jesli slave odpowiedzial
            }
    }
    //-------------------------------------------------------------------------
    static void onewire_0_WriteByte(uint8_t data)
    {
        uint8_t i;
       
       WIRE_PORT_0 |= 1<<WIRE_CON_0;    //pin 1wire -> 1
        WIRE_DIR_0 |= 1<<WIRE_CON_0;     //pin 1wire jako wyjscie
        for (i=0; i<8; i++)
            {
          cli();
          
          if((data & 0b00000001) == 1)
                {
                WIRE_PORT_0 &= ~(1<<WIRE_CON_0); //pin 1wire -> 0
                _delay_us(5);
                WIRE_PORT_0 |= 1<<WIRE_CON_0;    //pin 1wire -> 1
                _delay_us(65);
                }
            else
                {
                WIRE_PORT_0 &= ~(1<<WIRE_CON_0); //pin 1wire -> 0
                _delay_us(70);
                WIRE_PORT_0 |= 1<<WIRE_CON_0;    //pin 1wire -> 1
                }
            _delay_us(5);
            data >>= 1;
          
          sei();
            }
    }
    //-------------------------------------------------------------------------
    static uint8_t onewire_0_ReadByte(void)
    {
        uint8_t data = 0;
        uint8_t i;
       
        WIRE_PORT_0 &= ~(1<<WIRE_CON_0);    //pin 1wire -> 0
        for (i=0; i<8; i++)
            {
          cli();
          
            data >>= 1;
            WIRE_DIR_0 |= 1<<WIRE_CON_0;        // in 1wire jako wyjscie
            _delay_us(3);
            WIRE_DIR_0 &= ~(1<<WIRE_CON_0);     //pin 1wire jako wejscie
           _delay_us(10);
            if(bit_is_set(WIRE_PIN_0,WIRE_CON_0))
                {
                data |= 0b10000000;
                }
            _delay_us(70);
          
          sei();
            }

        return data;
    }
    //-------------------------------------------------------------------------


    main()
    {
    ...
    ...
    ...

      onewire_0_reset();
      onewire_0_WriteByte(0xCC);
      onewire_0_WriteByte(0x44);
     
      _delay_ms(1000);
     
      onewire_0_reset();
      onewire_0_WriteByte(0xCC);
      onewire_0_WriteByte(0xBE);
      Temperature.LSB = onewire_0_ReadByte();
      Temperature.MSB = onewire_0_ReadByte();

      Temperature.XSB = (Temperature.XSB * 10) / 16;

      itoa(Temperature.XSB, Text, 10);
    ...
    ...
    ...
    return 0;
    }

    1
  • #11 18 Gru 2010 20:35
    oskar777

    Poziom 25  

    Mam teraz inne pytanie dzięki atomowi układ działa odczytuje temperaturę ale nie jestem pewien czy mam 12 bit rozdziałkę.

    Dla przykładu mam w kodzie.

    Code:

    Temperature.LSB = onewire_0_ReadByte();
    Temperature.MSB = onewire_0_ReadByte();
    itoa(Temperature.XSB, Text, 2);
    LCD_WriteText(Text);


    LCD_WriteText(Text); pokazuje mi np
    100101001 czyli 9 bitów, tyle co dokumentacje czytałem to rejestr odczytu temperatury składał się z 2 bajtów
    pierwszy 8 bitów temperatury
    drugi 3 bity reszta odczytu temperatury i 5 bitów informujących o ujemnej bądź dodatniej temperaturze.

    Samą temperaturę odczytuje tak... przykład Atoma nie ma kropki w odczycie, być może da się robić na uniach jakieś operacje, by się to dało, ale ja niestety nie wiem jak.
    temperatura:
    Code:

    float temp=0;
       temp=(float)(Temperature.LSB+(Temperature.MSB*256))/16;
      dtostrf(temp,1,2,buf);
        LCD_WriteText(buf);


    Prosiłbym o pomoc szanownych Kolegów bo nie wiem co jest nie tak, czytałem też o rejestrach sterujących rozdzielczością ale nie wiem jak ustawić ten rejestr.
    Jak odczytać czy jest ujemna czy dodatnia temperatura tzn jak warunek zapisać.

    Pozdrawiam

    0
  • #12 19 Gru 2010 10:52
    atom1477
    Poziom 43  

    Spróbuj tak.

    Code:

          float Float;

          Float = Temperature.XSB;
          Float = Float / 16;
     
          dtostrf(Float, 3, 2, Text);
          //Tutaj pasowało by dać wyrównanie textu do stałej długości
     
          LCD_GoTo(0,0);
          LCD_WriteText("T=");
          LCD_GoTo(7,0);
          LCD_WriteText("   ");

    0
  • #13 20 Gru 2010 08:55
    oskar777

    Poziom 25  

    Witam trochę analizowałem różne pomiary i dowiedziałem się, że jest tu zastosowany kod U2 z wartościami ujemnymi, dla przykładu
    0000 0000 0000 1000 daje mi 0.5 st C bo 2-² daje mi ½ co daje mi 0.5,
    tylko czemu
    1111 1111 1111 1000 daje mi - 0.5 st C i czemu dzieli wynik się przez 16 ?.
    Wcześniej mierzyłem w za małym zakresie i jak mi ucinało zera z lewej to nie wiedziałem o co chodzi.
    Szukałem w google jakiś opisów tego (u2 do dec) ale nic nie znalazłem.

    Druga sprawa, wynik jest odczytywany co 1 s, bo tyle mniej więcej potrzebuje czujnik dla 12 bitow, teraz pytanie jak zrobić odczyt poza pętlą główną ?
    W pętli będą warunki na sprawdzenie czy temperatura jest w pewnym zakresie jeżeli nie to zostanie wzbudzony alarm.
    Myślałem i timerze czy to dobry pomysł ? i jaki zastosować ?

    Pozdrawiam

    0
  • #14 20 Gru 2010 09:29
    atom1477
    Poziom 43  

    oskar777 napisał:
    tylko czemu
    1111 1111 1111 1000 daje mi - 0.5 st C

    No przecież tak ma być w kodzie U2 (i kodowaniu ułamkowym z 4 bitami na część ułamkową).
    oskar777 napisał:
    i czemu dzieli wynik się przez 16 ?

    A tego nie wiem (i nie rozumiem :D).
    oskar777 napisał:
    Druga sprawa, wynik jest odczytywany co 1 s, bo tyle mniej więcej potrzebuje czujnik dla 12 bitow, teraz pytanie jak zrobić odczyt poza pętlą główną ?
    W pętli będą warunki na sprawdzenie czy temperatura jest w pewnym zakresie jeżeli nie to zostanie wzbudzony alarm.


    oskar777 napisał:
    Myślałem i timerze czy to dobry pomysł ?

    Tak.
    oskar777 napisał:
    i jaki zastosować ?

    A masz wybór? :D Masz tam tylko 3 Timery (w większości AVRów 3) i wszystkie prawie identyczne jeżeli chodzi o ich wykorzystanie do "taktowania" pomiarów.

    0
  • #15 21 Gru 2010 11:33
    oskar777

    Poziom 25  

    Witam, po małej walce dodałem obsługę timera i przerwań, kod działa ale prosiłbym o ocenę czy jest ok, czy coś można inaczej zrobić

    Code:


    int main(void)
    {
    LCD_Initalize();
    // Potrzebna ilość cykli = (1 / częstotliwość pożądana) / (preskaler / częstotliwość zegara)
    TCCR1B |= (1 << WGM12); // Aktywacja trybu cTC
    OCR1A = 31250;
    TCCR1B |= (1 << CS12); // Ustawia timer z preskalerem Fcpu/256  datascheet str.100 table 40
    TIMSK |= (1 << OCIE1A); // zezwolenie na przerwaia
    sei(); // zezwolenie na globalne przerwania
        while (1)
        {
       
    LCD_WriteText("Temp: ");       
    LCD_WriteText(Text);       
    _delay_ms(500);
    LCD_Clear();    

        } // end while

       
       
     
       
    }
    ISR(TIMER1_COMPA_vect)
    {
    onewire_0_reset();
    onewire_0_WriteByte(0xCC);
    onewire_0_WriteByte(0x44);
     
      _delay_ms(750);
     
    onewire_0_reset();
    onewire_0_WriteByte(0xCC);
    onewire_0_WriteByte(0xBE);
    Temperature.LSB = onewire_0_ReadByte();
    Temperature.MSB = onewire_0_ReadByte();
    float Float;
    Float = Temperature.XSB;
    Float = Float / 16;
    dtostrf(Float, 3, 1, Text);    
    }



    Pozdrawiam

    0
  • #16 21 Gru 2010 11:41
    tmf
    Moderator Mikrokontrolery Projektowanie

    Nie, jest bardzo źle. Po pierwsze po co ci float? Poczytaj o arytmetyce stałopozycyjnej. Po drugie, jeśli byś odwrócił kolejność odczytu czujnika temp. i najpierw odczytywał temp. a potem rozpoczynał konwersję to nie musiałbyś mieć tego delay(750) - tylko pierwszy pomiar byłby zły, co nie jest problemem. Poza tym konwersja z float na text powinna być poza procedurą obsługi przerwania, nie ma powodu, żeby ją tam umieszczać. Prawdopodobnie też w większym programie TIMER1_COMPA powinno być zdefiniowane z ISR_NOBLOCK, żeby nie blokować innych przerwań na długi czas związany z obsługa 1-wire. W twoim kodzie ta prosta procedura obsługi przerwania zajmuje praktycznie 80-90% czasu procesora, powinna zajmować coś koło 0,1 promila.

    0
  • #17 21 Gru 2010 11:51
    oskar777

    Poziom 25  

    Float mi potrzebny by odczytać (i wyświetlić) temperaturę z przecinkiem, nie wiem jak zrobić to inaczej. Jeśli masz jakiś przykład na to, to się ucieszę jeśli nie to nic innego nie dam chyba, że ktoś ma taki przykład i się nim podzieli.

    Cytat:

    Poza tym konwersja z float na text powinna być poza procedurą obsługi przerwania, nie ma powodu, żeby ją tam umieszczać.


    Poprawię.
    ISR_NOBLOCK -> poszukam, poczytam.

    Cytat:

    Po drugie, jeśli byś odwrócił kolejność odczytu czujnika temp. i najpierw odczytywał temp. a potem rozpoczynał konwersję to nie musiałbyś mieć tego delay(750)


    Mam dać w przerwaniu



    Code:

    onewire_0_reset();
    onewire_0_WriteByte(0xCC);
    onewire_0_WriteByte(0xBE);
    Temperature.LSB = onewire_0_ReadByte();
    Temperature.MSB = onewire_0_ReadByte();

    // odwrotnie ?

    onewire_0_reset();
    onewire_0_WriteByte(0xCC);
    onewire_0_WriteByte(0x44);
     


    Czy o co innego Ci chodziło ?

    Pozdrawiam

    ...edit

    Dzięki za te rady
    Dałem tak
    Code:

     while (1)
        {
    Float = Temperature.XSB;
    Float = Float / 16;
    dtostrf(Float, 3, 1, Text);    

    LCD_GoTo(0,0);   
    LCD_WriteText("Temp: ");       
    LCD_WriteText(Text);       



    float porownanie;
    porownanie = 22.5;

    if(Float >= porownanie) {
    LCD_GoTo(0,1);
    LCD_WriteText("Alarm jakis: ");    
    LCD_WriteText(Text);          
    }

    _delay_ms(500);
    LCD_Clear();    


        } // end while
       
    }
    ISR(TIMER1_COMPA_vect, ISR_NOBLOCK)
    {
    onewire_0_reset();
    onewire_0_WriteByte(0xCC);
    onewire_0_WriteByte(0xBE);
    Temperature.LSB = onewire_0_ReadByte();
    Temperature.MSB = onewire_0_ReadByte();

    onewire_0_reset();
    onewire_0_WriteByte(0xCC);
    onewire_0_WriteByte(0x44);
     }




    Teraz działa o wiele szybciej, ten warunek jest na taki alarm temperatury, który będzie w przyszłości, da się to zrobić bez float jeśli tak to jak ?

    0
  • #18 21 Gru 2010 16:52
    tmf
    Moderator Mikrokontrolery Projektowanie

    Tak jak pisałem, użyć arytmetyki stałopozycyjnej. Małe naprowadzenie - jeśli masz np. 10,23 i pomnożysz to razy 100 to masz 1023, czyli liczbę całkowitą. Żeby to poprawnie wyświetlić wystarczy wiedzieć gdzie postawić przecinek. Dla liczb binarnych tez to działa. Możesz tez skorzystać z wbudowanych typów stałopozycyjnych _Fract i _Accum. BTW, funkcja alarmu jest wbudowana w DS1820, wystarczy wpisać wartość i potem robić Alarm Search.

    0
  • #19 22 Gru 2010 13:02
    oskar777

    Poziom 25  

    Witam,
    trochę przegrzebałem fora dyskusyjne wczoraj i dziś w szukaniu wersji non-float i znalazłem to.

    Code:

    // na początku kodu
    #define THERM_DECIMAL_STEPS_12BIT 625 //.0625
    uint8_t temperature[2];
    int8_t digit;
    uint16_t decimal;


    char buffer[14];
    digit=Temperature.LSB>>4;
    digit|=(Temperature.MSB&0x7)<<4;
    decimal=Temperature.LSB&0xf;
    decimal*=THERM_DECIMAL_STEPS_12BIT;
    sprintf(buffer, "%+d.%04u C", digit, decimal);


    I teraz pytanie, jak uzyskać ujemną temperaturę ?, jak temperatura spada poniżej 0 to mam wynik 127.625 jako pierwszy i tak dalej.

    Da się zaokrąglić wynik do 2 miejsc po przecinku ?
    Czytałem to http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/ ale nie wiem jak ustawić by zrobiło mi ujemną temperaturę
    Będę wdzięczny za pomoc.

    edit...
    Wpadłem na jeden pomysł, ponieważ 5 ostatnich bitów drugiej części ma wartość 1 przy ujemnej temperaturze to mogę zrobić kasowanie ich przy konwersji i zamianę na 0, zrobienie warunku czy wystąpił znak ujemny i wyświetlenie odpowiedniej wartości.

    Poszukam jak to zrobić i dam znać.

    0
  • #21 23 Gru 2010 00:19
    oskar777

    Poziom 25  

    Udało mi się znaleźć kod, który wyświetla temperaturę bez float i sprintf

    Code:

    //  Set TEMP_RESOLUTION to the corresponding resolution of used DS18x20 sensor:
    //  18S20: 9  (default setting; can be 9,10,11,or 12)
    //  18B20: 12

    const unsigned short TEMP_RESOLUTION = 12;


     Display_Temperature(unsigned int temp2write) {
      const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
      char temp_whole;
     
      unsigned int temp_fraction;

      // check if temperature is negative
      if (temp2write & 0x8000) {
        text_temp[0] = '-';
        temp2write = ~temp2write + 1;
      }

      // extract temp_whole
      temp_whole = temp2write >> RES_SHIFT ;

      // convert temp_whole to characters
      if (temp_whole/100)
        text_temp[0] = temp_whole/100  + 48;
       
      else
        text_temp[0] = '0';

      text_temp[1] = (temp_whole/10)%10 + 48;             // Extract tens digit
      text_temp[2] =  temp_whole%10     + 48;             // Extract ones digit
     
     
      // extract temp_fraction and convert it to unsigned int
      temp_fraction  = temp2write << (4-RES_SHIFT);
      temp_fraction &= 0x000F;
      temp_fraction *= 625;

      // convert temp_fraction to characters
      text_temp[4] =  temp_fraction/1000    + 48;         // Extract thousands digit
      text_temp[5] = (temp_fraction/100)%10 + 48;         // Extract hundreds digit
      text_temp[6] = (temp_fraction/10)%10  + 48;         // Extract tens digit
      text_temp[7] =  temp_fraction%10      + 48;         // Extract ones digit
     
     
      return text_temp;
    }


    Tylko pytanie, jak ododać przecinek ?
    Myślałem coś w stylu text_temp[3] = ".";
    Ale to nie działa, wie ktoś gdzie to wstawić by było poprawnie, próbowałem też łączyć stringi przez strcat

    Pozdrawiam

    0
  • #22 23 Gru 2010 10:23
    tmf
    Moderator Mikrokontrolery Projektowanie

    A nie prościej zmienić indeksy w text_temp? Przecież tam jawnie masz wstawiane kolejne cyfry... Zamiast szukać gotowców, kup porządną książkę o nauce programowania i od tego zacznij. Bo niebezpiecznie zbliżasz się do etapu, w którym moderator wywali cały ten wątek jako zaniżający poziom.

    0
  • #23 23 Gru 2010 16:12
    oskar777

    Poziom 25  

    Przenumerowanie indeksów nic nie daje, bo wynik jest z kosmosu wzięty, tak więc wnioskuje, że wiele z niego nie rozumiesz. (z tej funkcji).

    Co do książki to wiele z niej się nie dowiem, nawet myślałem o zakupie ale co chwile widzę wypowiedzi w stylu...."tamten przykład w książce jest do D i lepiej spróbuj z tego rozwiązania".
    Co do "etapu" na tym pod-forum znajdują się tematy w stylu jak zapalić diodę i jakoś nie są kasowane. Ja pytam o trochę bardziej skomplikowane tematy i proszę o pomoc w konkretnych tematach jak na razie atom wkleił mi coś co działa.


    Twoje niektóre wypowiedzi są pomocne nie powiem dużo mi pomogły, ale teksty w stylu poszukaj sobie co to jest U2 zupełnie nic nie wnosi do tematu. Wszedłem na wiki poczytałem nawet wiem jak się to liczy i...i nic kompletnie nic z tego nie wynika bo nawet jak bym cały dzień siedział nad tym to bym nie wpadł, że np wynik
    float trzeba przez 16 podzielić by był poprawny odczyt.
    Sam kolega Atom, który siedzi nad avr np tego nie wiedział ale takich przypadków na forum są dziesiątki.

    Tak więc mam prośbę jeżeli chcesz mi naprawdę pomóc to proszę o konkretne odpowiedzi. Jak ja odpowiadam na tym forum to nie piszę poszukaj sobie o tym chyba, że to "coś" można łatwo znaleźć i zrozumieć, tylko podaje konkretne rozwiązania.

    Na razie zostawiam wersje float, a tą zapytam się autora tego skryptu może coś poradzi.

    Pozdrawiam

    0
  • #24 23 Gru 2010 16:53
    atom1477
    Poziom 43  

    oskar777 napisał:
    że np wynik
    float trzeba przez 16 podzielić by był poprawny odczyt.
    Sam kolega Atom, który siedzi nad avr np tego nie wiedział ale takich przypadków na forum są dziesiątki.

    Dlaczego uważasz że tego nie wiedziałem?

    0
  • #25 23 Gru 2010 17:57
    oskar777

    Poziom 25  

    Cytat:

    oskar777 napisał:
    i czemu dzieli wynik się przez 16 ?

    A tego nie wiem (i nie rozumiem ).

    Tylko to nie miało mieć żadnego negatywnego wydźwięku, bo chyba tak to przyjąłeś.[/code]

    0
  • #26 23 Gru 2010 19:16
    atom1477
    Poziom 43  

    Myślałem że pytasz o coś innego. Bo bardzo dziwnie zapytałeś.
    Myślałem że pytasz o to dlaczego "dzieli wynik się" (tak jak by wynik sam się dzielił mimo że go o to nie prosisz).
    A nie o to dlaczego należy go dzielić.
    Bo dlaczego należy go dzielić to wiem :D
    Po prostu na 4-rech najmłodszych bitach masz wartości za przecinkiem. 4-ry bity czyli 16-cie wartości. Więc odczytując tą liczbę bez uwzględnienia przecinka odczytasz ją 16-cie razy większą. Więc można np. podzielić przez 16 aby odzyskać położenie przecinka.

    0
  • #27 24 Gru 2010 01:26
    oskar777

    Poziom 25  

    Witam dokonałem kilka zmian w kodzie i jestem bliski sukcesu w tym temacie.
    1. udało mi się uzyskać kropkę, inaczej zmienną zdefiniowałem tzn jest teraz tak

    Code:
    char *text_temp = "0000.0000";

    Poprawiłem warunek na minus zamiast
    Code:

    if (temp2write & 0x8000) {
        text_temp[0] = '-';
        temp2write = ~temp2write + 1;
      }

    dalem
    Code:

     if (temp2write & 0xF800) {
        text_temp[0] = '-';
        temp2write = ~temp2write + 1;
      } else {
       text_temp[0] = '+';
      }

    Przenumerowałem też indeksy.

    Problem jest taki, że temperatura jest wyświetlana w postaci

    +001.xxxx
    +01x.xxxx
    +1xx.xxxx
    i minus tak samo
    Próbuję znaleźć jakiś sposób na wywalenie tych nadmiarowych zer.
    Dałem takie coś
    Code:

      char string=text_temp;
        char searchchar = '0';
        char replacechar = ' ';
        char *ptr;   
        ptr = string;
        while (*ptr != '.') {
            if(*ptr == searchchar){
          
                 *ptr = replacechar;
              }
            ptr++;
        }


    I to praktycznie działa wywala zera.
    Niestety wywala też zera potrzebne tzn jak jest 10.xxxx stopni C to robi mi 1 .xxxx C

    Jak temu zaradzić ?, może jest prosty sposób inny ?

    warunek *ptr != '.' jest po to by szukał do kropki.

    Na razie to tyle.

    Pozdrawiam

    0
  • #28 27 Gru 2010 10:12
    oskar777

    Poziom 25  

    Witam Was.
    Poprawiłem skrypt. Poczytałem trochę o wskaźnikach, chodź nie wszystko z nich rozumiem, zrobiłem kilka poprawek i działa.
    Zmiany są takie

    Zmienna

    Code:

    char *text_temp = "0000.0000";
    zamieniona na
    char *text_temp = "0000.00";

    Dzięki temu miałem mniej liczb na końcu.

    kod:

    Code:

    char string=text_temp;
        char searchchar = '0';
        char replacechar = ' ';
        char *ptr;   
        ptr = string;
        while (*ptr != '.') {
            if(*ptr == searchchar){
         
                 *ptr = replacechar;
              }
            ptr++;
        }

    /////
    Zamieniłem na coś bardziej sensownego czyli
    /////

    int znak = 0;
        char *ptr;
        ptr = text_temp;
       int dl;
       dl = strlen(text_temp);
        while (*ptr == 0x30 || *ptr == '+' || *ptr == '-')
        {
           
           ptr++;
          
          
        }
       dl = strlen(ptr);
       if(dl == 3) {
       *--ptr = '0';
       }
       
       
       if(text_temp[0] == '+') {
       *--ptr= '+';
          } else {
          *--ptr = '-';
          }
     

    Pewnie można to jeszcze bardziej optymalnie zrobić, jednak ja już nie wiem jak.
    Zakomentowałem też dodatkowo text_temp[7], text_temp[8] I teraz wszystko działa jak należy.

    Pozdrawiam.

    0