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.

Wyświetlacz siedmiosegmentowy i ds18b20 prosze o pomoc

Piotr Kania 11 Kwi 2009 14:34 1836 17
  • #1 11 Kwi 2009 14:34
    Piotr Kania
    Poziom 15  

    Witam oto mój program czy ktoś wie jak zrobić konwersje msb i lsb w ds18b20 żeby wyświetlić na siedmio segmentowym wyświetlaczu temperaturę ?

    Code:

    #include <avr/io.h>
    //#include <avr/iom8.h>
    #include <avr/interrupt.h>
    //#include <stdlib.h>
    //#include <string.h>
    #define F_CPU 8000000UL
    #include <util/delay.h>
    #include "ds18B20.c"

    volatile unsigned char a,b,c,d;

    #define LEDA_OUTPUT() DDRC |= _BV(0)
    #define LEDA_ON() PORTC&= ~_BV(0)
    #define LEDA_OFF() PORTC|= _BV(0)
    #define LEDB_OUTPUT() DDRC |= _BV(1)
    #define LEDB_ON() PORTC&= ~_BV(1)
    #define LEDB_OFF() PORTC|= _BV(1)
    #define LEDC_OUTPUT() DDRC |= _BV(2)
    #define LEDC_ON() PORTC&= ~_BV(2)
    #define LEDC_OFF() PORTC|= _BV(2)
    #define LEDD_OUTPUT() DDRC |= _BV(3)
    #define LEDD_ON() PORTC&= ~_BV(3)
    #define LEDD_OFF() PORTC|= _BV(3)
    //w1-w4
    #define W1_OUTPUT() DDRD |= _BV(7)
    #define W1_ON() PORTD&= ~_BV(7)
    #define W1_OFF() PORTD|= _BV(7)
    #define W2_OUTPUT() DDRD |= _BV(6)
    #define W2_ON() PORTD&= ~_BV(6)
    #define W2_OFF() PORTD|= _BV(6)
    #define W3_OUTPUT() DDRD |= _BV(5)
    #define W3_ON() PORTD&= ~_BV(5)
    #define W3_OFF() PORTD|= _BV(5)
    #define W4_OUTPUT() DDRD |= _BV(4)
    #define W4_ON() PORTD&= ~_BV(4)
    #define W4_OFF() PORTD|= _BV(4)




    void led_init(void)
    {
    LEDA_OUTPUT();
    LEDB_OUTPUT();
    LEDC_OUTPUT();
    LEDD_OUTPUT();
    LEDA_OFF();
    LEDB_OFF();
    LEDC_OFF();
    LEDD_OFF();

    W1_OUTPUT();
    W2_OUTPUT();
    W3_OUTPUT();
    W4_OUTPUT();
    W1_OFF();
    W2_OFF();
    W3_OFF();
    W4_OFF();
    }
    void wyswietl(unsigned char a)
    {
    if(a==0)
    {LEDD_ON();LEDC_ON();LEDB_ON();LEDA_ON();}
    if(a==1)
    {LEDD_ON();LEDC_ON();LEDB_ON();LEDA_OFF();}
    if(a==2)
    {LEDD_ON();LEDC_ON();LEDB_OFF();LEDA_ON();}
    if(a==3)
    {LEDD_ON();LEDC_ON();LEDB_OFF();LEDA_OFF();}
    if(a==4)
    {LEDD_ON();LEDC_OFF();LEDB_ON();LEDA_ON();}




    if(a==5)
    {LEDD_ON();LEDC_OFF();LEDB_ON();LEDA_OFF();}
    if(a==6)
    {LEDD_ON();LEDC_OFF();LEDB_OFF();LEDA_ON();}
    if(a==7)
    {LEDD_ON();LEDC_OFF();LEDB_OFF();LEDA_OFF();}
    if(a==8)
    {LEDD_OFF();LEDC_ON();LEDB_ON();LEDA_ON();}
    if(a==9)
    {LEDD_OFF();LEDC_ON();LEDB_ON();LEDA_OFF();}
    if(a==10)
    {LEDD_OFF();LEDC_OFF();LEDB_OFF();LEDA_OFF();}
    }
    SIGNAL (SIG_OVERFLOW1)
    {
    TCNT1 = 0xfec8;        // przeładuj timer 1
    W1_ON();
    wyswietl(a);
    _delay_ms(1);
    W1_OFF();
    W2_ON();
    wyswietl(b);
    _delay_ms(1);
    W2_OFF();
    W3_ON();
    wyswietl(c);
    _delay_ms(1);
    W3_OFF();
    W4_ON();
    wyswietl(d);
    _delay_ms(1);
    W4_OFF();
    }
    void pomiar(void)
    {
    float celcius;
    char msb,lsb,temp;
    char tab[6];
    ow_reset();
    ow_write_byte(0xCC);
    ow_write_byte(0x44);
    _delay_ms(750);
    ow_reset();
    ow_write_byte(0xCC);
    ow_write_byte(0xBE);
    lsb = ow_read_byte();
    msb = ow_read_byte();
    ow_reset();

    //******************************************************

    KONWERSJA i wyświetlenie na led
    próbowałem coś zrobić na itoa ale nie przyniosło to dobrego rozwiązania

    //******************************************************

    }
    int main(void)
    {
    led_init();

    TIMSK = _BV(TOIE1);        // włącz obsługę przerwań T/C1
    TCNT1 = 0xfec8;        // wartość początkowa T/C1 0bdc=2s
    TCCR1A = 0x00;        // włącz tryb czasomierza T/C1
    TCCR1B=(1<<CS12);      // preskaler 256

    a=0;
    b=0;
    c=0;
    d=0;

    sei();
    while(1)
    {
    pomiar();
    }
    }

    0 17
  • #2 11 Kwi 2009 14:54
    __Maciek__
    Poziom 19  

    Konwersja na temperaturę :

    Code:

    ow_reset() ;
    ow_write_byte(0xCC);
    ow_write_byte(0xBE);     
    lsb = ow_read_byte() ;
    msb = ow_read_byte() ;    
    Temperatura = (msb<<8 | lsb) * 10 / 16 ;   


    A jak masz podłączone wyświetlacze ?
    Np. część kontrolerów potrzebuje kodów BCD.

    Używaj opcji SZUKAJ. To co podałem było już niejednokrotnie.

    Dobra .. popatrzyłem w kod ... i jeśli procedury wyświetlające cyfry funkcjonują prawidłowo ... to teraz możesz pobawić się z itoa ( będziesz musiał dodać kopkę dziesiętną. ) W zmiennej Temperatura masz wartość temperatury np: 200 = 20,0°C itd ...

    0
  • #3 11 Kwi 2009 15:04
    Piotr Kania
    Poziom 15  

    ok to znam ale jak teraz tą temp rozdzielić na 2 wyświetlacze np na pierwszym liczba dziesiętna na na 2 jedności. Wyświetlacze działają bo zrobiłem na nich zegar, steruje przez HEF4543

    0
  • #4 11 Kwi 2009 15:18
    __Maciek__
    Poziom 19  

    Więc właśnie interesuje Cię konwersja Int na BCD.

    np z tąd : Link

    Code:
    // returns number of digits converted
    
    // result array must be large enough to hold
    // the number of digits converted.

    int itobcd(unsigned int val, char *result)
    {
      char BCD_text[6]; // max 5 digits in a 16 bit uint
      int i;

      itoa(val, BCD_text, 10);
      i=0;
      while(BCD_text[i])
      {
        result[i] = BCD_text[i]-'0';
        i++;
      }
      return i;
    }


    Można też napisać własną procedurę .. tu patrz Google -> BCD .

    0
  • #5 11 Kwi 2009 15:44
    Piotr Kania
    Poziom 15  

    próbowałem tak

    Code:

    temp = ((msb<<4)|(lsb >> 4));
    t=(itoa(temp,tab,10));
    a=(t/10);


    ale nielata

    0
  • #7 11 Kwi 2009 18:07
    Piotr Kania
    Poziom 15  

    Potrzebuje wyświetlić temperaturę na 4 wyświetlaczach led zawsze jeżeli chodziło o LCD robiłem to tak

    Code:

     celcius =  msb << 8 | lsb ;
     celcius/=16;
     write_text(dtostrf(celcius, 3, 1, tab));

    teraz chce to wyświetlić na led i np temperature 27st rozłożyć na a=2, b=7 i w przerwaniu wyswietlić

    Dodano po 1 [minuty]:

    może ktoś zna prostszy sposób?

    0
  • #8 11 Kwi 2009 19:03
    kaktus_c++
    Poziom 18  

    Code:
    float celcius=27.15;
    
    int tmp=celcius*100;
    int d=tmp%10;
    tmp=tmp/10;
    int c=tmp%10;
    tmp=tmp/10;
    int b=tmp%10;
    tmp=tmp/10;
    int a=tmp%10;


    twój kod
    Code:
    celcius =  msb << 8 | lsb ;
    
     celcius/=16;
    jest dobry ale tylko dla temperatury >=0

    0
  • #9 11 Kwi 2009 22:29
    Piotr Kania
    Poziom 15  

    zrobiłem tak

    Code:

    ow_reset();
    ow_write_byte(0xCC);
    ow_write_byte(0x44);
    _delay_ms(100);
    ow_reset();
    ow_write_byte(0xCC);
    ow_write_byte(0xBE);
    lsb = ow_read_byte();
    msb = ow_read_byte();
    temp = ((msb<<4)|(lsb >> 4));

    c=temp%10;
    temp=temp/10;
    b=temp%10;
    temp=temp/10;
    a=temp%10;



    i działa ale co jakiś czas na wyświetlaczu pojawia sie 255 wydaje mi się że to przez timer1, który wyświetla temperaturę wiecie może jak to załatwić? Wyłącznie przerwań na czas komunikacji z ds załatwia problem, czy ktoś ma jakieś inne propozycje rozwiązania tego problemu

    0
  • #10 12 Kwi 2009 00:08
    dawid512
    Poziom 32  

    Można też stosować flagę ustawianą bądź kasowaną w przerwaniu aby stwierdzić czy wystąpiło przerwanie. Na ogół jednak wyłącza się przerwania na czas komunikacji tak jak ty to zrobiłeś.

    0
  • Pomocny post
    #11 12 Kwi 2009 09:49
    kaktus_c++
    Poziom 18  

    jestem ciekaw jak tam u ciebie z odczytem ujemnych temperatur, bo wg mnie to będą źle czytane. no chyba że nie potrzebujesz ujemnych

    0
  • #12 12 Kwi 2009 13:17
    Piotr Kania
    Poziom 15  

    tak będzie źle ale musiałem sprawdzić czy to działa. Jeśli wezmę 4 bity z msb i wszystkie z lsb to dostane np temperature w postaci 12,0625 przyczym czwarty bit z msb decydował będzie o znaku. Próbowałem tak jak Kaktus mówił ale mnożyłem przez 10000, dobrego wyniku nie dostałem, dlaczego?

    0
  • Pomocny post
    #13 12 Kwi 2009 16:28
    kaktus_c++
    Poziom 18  

    jeśli chodzi o ujemne temperatury to ta funkcja sobie poradzi:

    Code:
    float zamien_temp(unsigned char MSB,unsigned char LSB)
    
    {
        if(MSB&0x80)//ujemna temp
        {
           LSB=~LSB +1;
           MSB=~MSB;
           unsigned int suma = LSB + (((unsigned int)MSB)<<8);
           return  ((float)suma) * -0.0625;
        }
        else//dodatnia temp
           return ((float)(MSB<<8|LSB))/16;
    }

    a jeśli chodzi o mnożenie przez 10000 to poki nie zobacze fragmentu kodu to nie wiem co jest grane, zresztą taka dokładność to chyba przesada.

    0
  • #14 12 Kwi 2009 20:50
    Piotr Kania
    Poziom 15  

    to prawda przesada ale ds18b20 niby z tyloma miejscami po przecinku działa. Jutro przetestuje ten kod i dam znać do czego doszedłem. Dzięki

    0
  • #15 12 Kwi 2009 21:30
    rrata
    Poziom 19  

    Nie wiem za bardzo po co używać typu float, spokojnie można zrobić to na liczbach całkowitych (kodowanie U2). Zresztą dokładność tego termometru według dokumentacji wynosi 0.5°C, wystarczy wyświetlać z rozdzielczością 0.1°C, a to i tak będzie za dużo.

    0
  • #16 12 Kwi 2009 22:00
    Piotr Kania
    Poziom 15  

    no tak zgadza się ale chodzi o poznanie zasady jak to działa, dokładność przetwornika wynosi 0.5st wiec wystarczy nawet całkowite wyświetlać

    Dodano po 25 [minuty]:

    Przetestowałem oto mój kod

    Code:

    temp = zamien_temp(msb,lsb)*10;
    d=temp%10;
    temp=temp/10;
    c=temp%10;
    temp=temp/10;
    b=temp%10;
    temp=temp/10;
    a=temp%10;
    if(a==0) a=10;//wyłącznie 1 wyświetlacza


    temp jest jako int, program działa dziękuje za pomoc

    0
  • #17 12 Kwi 2009 22:00
    rrata
    Poziom 19  

    Dobrym programistą może nie jestem, ale zrobiłem sobie to w ten sposób:
    Wydzielam sobie cztery bity odpowiadające za ułamek

    Code:
    ulamek = lsb & 0x0F;

    Później normalnie wydzielam sobie bity odpowiadające za liczbę całkowitą:
    Code:
    lsb = lsb >> 4;
    
          msb = msb << 4;
          temp = lsb | msb;

    Sprawdzam czy jest ujemna, jesli tak to zamieniam ją na liczbę przeciwną, aby dało się to wysłać na LCD:
    Code:
    if(temp & 0b10000000)//Jeśli ujemna
    
          {
             temp = (~temp) + 1;
             if(ulamek)
                ulamek = (~ulamek) + 1;
             pisz_znak('-');//Wyświetla znak "-" na LCD
          }


    Wcześniej mam utworzoną tablicę
    Code:
    const unsigned char liczbyulamk[] = {0,0,1,2,2,3,3,4,5,5,6,6,7,8,8,9};
    ponieważ liczba ułamkowa to 4 bity, czyli od 0 do 15.

    Za wartość zmiennej ułamek wpisuję wartość cyfry po przecinku jaka ma się pokazać na LCD
    Code:
    ulamek = liczbyulamk[ulamek];


    i na koniec wyświetlam to wszystko na LCD
    Code:
    kursor_na_poczatek();//ustawia kusor na początek ekranu
    
          liczba_na_lcd(temp);
          pisz_znak('.');
          liczba_na_lcd(ulamek);
          pisz_znak(0b11011111);//wypisuje znak "°"
          pisz_znak('C');


    W ten oto sposób mam wyświetlaną temperaturę z liczbami ujemnymi z rozdzielczością 0,1°C. Kod jest błedny, gdyż zamiast pokazać temperaturę -0,1°C pokazuje -0,0°C, ale nie bardzo mam czas i chęci by to zmieniać. Zapewne lepiej dałoby się to zapisać, ale zapisałem to jak umiałem.

    Myślę, że modyfikacja kodu, aby wyświetlał temperaturę na wyświetlaczu LED siedmiosegmentowym nie będzie duzym problemem.

    0
  • #18 12 Kwi 2009 22:10
    Piotr Kania
    Poziom 15  

    Sposób kaktusa jest dla mnie lepszy bo obrabia wszystko, kiedyś też zrobiłem coś takiego jak Ty rrata ale brałem pod uwagę bit odpowiadający za zmianę co 0.5 st i też działało ale wyświetlałem na lcd.

    0
  Szukaj w 5mln produktów