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

if() w pętli i poza pętlą

12 Sty 2008 13:48 1134 4
  • Poziom 12  
    Witam
    W próbie opanowania LCDka natrafiłem na poniższy problem:
    Kiedy zestaw instrukcji znajduje się poza pętlą, to wykonuje się bez problemów, kiedy znajdzie się w pętli - cisza.

    Code:
    int main(void)
    
    {
     // konfiguracja portów we/wy
     DDRB = 0xFF;
     DDRD = 0xFF;  //wszystko 1, czyli WY
     PORTB = 0xFF;
     PORTD = 0xFE; //do D0 podłączony DS18B20, ma być bez podciągnięcia 1111 1110
    int a;
     char bufor[3];
     // inicjalizacja LCD
     lcd_init();
     // zapisz na LCD przykładowy tekst
     write_text("Presence Dallas");
     LCDxy(0,1);
     write_text("DS");
     
       LCDxy(4,1);
       a=ow_reset();
       if (a)
       write_text("Obecny");
       else
       write_text("Brak DS-a");

     // petla nieskończona
     while(1);

     
     return 0;
    }

    Tak działa - dostaję komunikat w zależności od tego, czy DS jest podłączony, czy nie. Niestety, żeby to sprawdzić za każdym razem po odłączeniu/podłączeniu DS-a muszę zresetować układ.
    Wyjściem byłoby umieścić blok sprawdzania w pętli while, czyli:
    Code:
    int main(void)
    
    {
     // konfiguracja portów we/wy
     DDRB = 0xFF;
     DDRD = 0xFF;  //wszystko 1, czyli WY
     PORTB = 0xFF;
     PORTD = 0xFE; //do D0 podłączony DS18B20, ma być bez podciągnięcia 1111 1110
    int a;
     char bufor[3];
     // inicjalizacja LCD
     lcd_init();
     // zapisz na LCD przykładowy tekst
     write_text("Presence Dallas");
     LCDxy(0,1);
     write_text("DS");
     

     // petla nieskończona
     while(1);
     {
       LCDxy(4,1);
       a=ow_reset();
       if (a)
       write_text("Obecny");
       else
       write_text("Brak DS-a");
     }
     return 0;
    }

    Niestety, wtedy na LCD-ku za pozycją 4,1, czyli za napisem DS nie mam nic, puste miejsce. Czy ktoś wie, dlaczego??
  • Pomocny post
    Poziom 39  
    smajlas napisał:
    ... Czy ktoś wie, dlaczego??

    Wywal średnik przy
    Code:
    while(1);
    , w drugiej wersji programu :)

    Piotrek
  • Poziom 12  
    Osz, (tu powinien być taki chłopek walący się łapą w czoło)...
    Oczywiście teraz działa ślicznie :)
    Zumek, jesteś Kimś... Dzięki!
    A tak btw, to jak tam jest średnik, to kompilator siedzi spokojnie, ale czego pętla nie działa? Czyżby to znaczyło, że po while brak jest jakichkolwiek instrukcji wtedy??
  • Poziom 27  
    Kompilator nie zwraca Tobie błędu (ostrzeżenia) w stylu:

    "Unreachable code"

    ??

    while(1); oznacza wieczną pustą pętlę.....
  • Poziom 12  
    Nie, brak takiego ostrzeżenia, za to teraz mam następną nowinę:
    po zaprogramowaniu tym:

    Code:

    #include <avr/io.h>
    #include <stdlib.h>
    //Połączenie LCDka do Portów:
    //B2 - RS, B3 - E, B4 - B7 D4-D7
    //#define LCD  PORTB
    //podłączenie DS18B20 - do portu D0, podciągnięte do zasilania rezystorem 4K7
    #define E  3
    #define RS  2
    //
    #define SET_E   PORTB |= _BV(E)
    #define CLR_E   PORTB &= ~_BV(E)
    //
    #define SET_RS  PORTB |= _BV(RS)
    #define CLR_RS  PORTB &= ~_BV(RS)
    #define OSC 8


    //procedura opóźniająca o 420us, gdy p==1 i OSC=8
    void waitms(unsigned char p)
    {
    unsigned char a,b; //zmienne licznikowe
    for(;p>0;--p) //ta pętla do wykonania p razy
       for(b=10;b>0;--b) //ta 10 razy
          for(a=10*OSC;a>0;--a) //ta petla 100 razy
          __asm("nop"); //dodatkowe opóźnienie o 1 cykl
    }

    // procedura zapisu bajtu do wyświetlacza LCD
    // bez rozróżnienia instrukcja/dana
    //zeby zapisac znak do LCD trzeba ustawic RS - 1, dane na D4 do D7
    //tryb 4-bity i "zatrzasnąć" sygnalem E
    void write_to_lcd(char x)
    {
    PORTB = ((PORTB & 0x0F) | (x & 0xF0));       // dane- pierwszej połówki bajtu
    SET_E;                                 // ustaw na E stan wysoki
    waitms(1);
    CLR_E;                                  // opadające zbocze na E -> zapis do wyświetlacza
    PORTB = ((PORTB & 0x0F) | ((x & 0x0F) << 4)); // zapis drugiej połowki bajtu
    SET_E;                                 // ustaw na E stan wysoki
    waitms(1);
    CLR_E;                                  // opadające zbocze na E -> zapis do wyświetlacza
    waitms(1);                               // czekaj 1ms
    }

    // procedura zapisu instrukcji do wyświetlacza LCD
    void write_command(char x)
    {
    CLR_RS;             // niski stan na RS -> zapis instrukcji
    write_to_lcd(x);       // zapis do LCD
    }

    // procedura zapisu danej do wyświetlacza LCD
    void write_char(char x)
    {
    SET_RS;            // wysoki stan na RS -> zapis danej
    CLR_E;
    write_to_lcd(x);       // zapis do LCD
    }

    // procedura zapisu tekstu do wyświetlacza LCD
    void write_text(char *s)
    {
    while(*s)             // do napotkania 0
      {
      write_char(*s);       // zapisz znak wskazywany przez s na LCD
      s++;                // zwiększ s (przygotuj nastepny znak)
      }
    }

    //pozycjonowanie na LCD
    void LCDxy(char x,char y)
    {
       unsigned char com=0x80;//1000 0000
       com|=(x|(y<<6));
       write_command(com);
       //po write command(com) do wyświetlacza zostaje zapisana komenda 1xxx xxxx, co daje nam
       //polecenie wybrania określonego adresu w pamięci DDRAM wyświetlacza, od teraz operacja zapisu
       //będzie się odnosić do tej komórki w pamięci
    }
    //---------------inicjalizacja LCDka--------------------------------
    void lcd_init(void)
    {
    waitms(100);          // czekaj 100ms na ustabilizowanie się napięcia zasilającego
    CLR_E;                // E = 0
    CLR_RS;             // RS = 0
    char i;             // zmienna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      PORTB = 0x30;       // 30h to jest
      //7654 3210
      //0011 0000
      waitms(1);
      SET_E;             // E = 1
      waitms(1);         // sygnał E -stan wysoki ma być utrzymany co najmniej tEN>450ns
      CLR_E;             // E = 0
      waitms(5);          // czekaj 5ms
      }
    PORTB = 0x20;          //
    //7654 3210
    //0010 0000
    SET_E;                // E = 1
    waitms(1);
    CLR_E;                // E = 0
    waitms(2);             // czekaj 1ms

    write_command(0x28);    // interfejs 4-bity, 2-linie, znak 5x7  0010 1000 
    //organizacja: 0010 NFxx N- liczba linii (1-2linie, 0-1linia), F-znak (1-5x10, 0-5x7)
    write_command(0x08);    // wyłącz LCD, kursor i miganie
    //organizacja: 0000 1000 - wyłączanie LCD
    write_command(0x01);    // czyść LCD
    //organizacja: 0000 0001 - włącz LCD (czysty)
    write_command(0x06);    // bez przesuwania w prawo
    //0000 01D0   gdzie D to kierunek przesuwu kursora 1 to + zaś 0 to -
    write_command(0x0C);    // włącz LCD, bez kursora i mrugania
    //0000 1101 ???
    }
    //--------- procedura opóźniająca o (5*t)* 0,125 us dla 8MHz kwarcu, tutaj jest 600ns (mierzone oscyloskopem)
    void delay(unsigned char t)
    {
    do
       {
       asm("nop");
       }
       while(--t);
    }
    //-----------------------------------------------Inicjalizacja DS18B20----------------------
    #define DQ 0 //definicja portu który służy jako 1-wire
    #define CLR_DQ DDRD |= _BV(DQ)  //ustawienie portu D0 w stan wysoki, czyli jako WY,
                            //czyli 1-w będzie niski
                            //(nie zapomnij zdefiniować PORTD PIN0 jako bez podciągnięcia)
                            //np. PORTD &=~_BV(0);
    #define SET_DQ DDRD &= ~_BV(DQ)   //ustawienie portu D0 w stan niski, czyli jako WE,
                            //co zwalnia linię 1-w, rezystor podciąga do 1,
                            //wymagany brak podciągnięcia do 1
    #define IN_DQ PIND & _BV(DQ)
    char ow_reset(void)
    {
    char presence;
    CLR_DQ; // stan niski na linii 1wire
    delay(200);   //120us
    delay(200);   //120us
    delay(200);   //120us
    delay(250);   //140us razem ok 500us lub wiecej
    SET_DQ;// stan wysoki na linii 1wire

    delay(100); //po zwolnieniu linii czekaj 60us
    presence=~IN_DQ; //tu ma być stan niski, jak DS obecny
    delay(200);
    delay(200);   //120us
    delay(250);   //140us, razem ok 500us
    return presence;
    }
    void ow_write_bit(char b)      // procedura zapisu bitu na linię 1wire
    {
       //cli();       // zablokowanie przerwań
       CLR_DQ;    // MASTER robi stan niski na linii 1wire
       delay(2);    // opóźnienie 1.2us - inicjalizacja slotu zapisu
       if(b) SET_DQ; // jeśli parametr jest niezerowy to ustaw stan wysoki na linii
       delay(108);    // opóźnienie 64us
       SET_DQ;    // MASTER odpuszcza, więc stan wysoki na linii 1wire
       delay(2);   //recovery -co najmniej 1us, mam 1.2us
       //sei();       // odblokowanie przerwań
    }
    void ow_write_byte(char val)    //zapis całego bajta do DS18B20
    {
       unsigned char i;
       unsigned char zm;
       for (i=0; i<8; i++)      //bajt = 8xbit
       {
          zm = val >> i;
          zm &= 0x01;
          ow_write_bit(zm);
       }
       //delay(4);
    }
    char ow_read_bit(void)      //odczyt bita informacji z DS-a
    {
       char return_bit;
       //cli();
       CLR_DQ;     //1-w stan niski
       delay(2);   //nie mniej niż 1us, mamy 1.2us
       SET_DQ;      //port 1-w jest wejściem, można czytać, co DS dał na linię
                //(przy okazji mamy zwolnienie linii, więc stan wysoki po skończeniu slotu)
       delay(20);      //czekaj 12us

       //if(IN_DQ) return 1; else return 0; //odczyt
       return_bit=IN_DQ;   //przypisanie aktualnego stanu portu do zmiennej return_bit
       delay(80);   //48us, cały slot = 61us (minimum to 60)
       delay(2); //recovery
       //sei();      //odblokowanie przerwań
       return return_bit;   
    }

    unsigned char ow_read_byte(void)   //odczyt całego bajta
    {
       unsigned char i;
       unsigned char value = 0;
       for (i=0;i<8;i++)
       {
          if(ow_read_bit())   //jak zczytana jedynka
          value|=0x01<<i;      //to wpisuj jedynkę i przesuwaj w lewo całość
          // a co jak odczytane zero??
       }
       return(value);
    }


    //----------------------------program główny----------------------------------------------------------

    int main(void)
    {
    unsigned char msb, lsb;
     // konfiguracja portów we/wy
     DDRB = 0xFF;
     DDRD = 0xFF;  //wszystko 1, czyli WY
     PORTB = 0xFF;
     PORTD = 0xFE; //do D0 podłączony DS18B20, ma być bez podciągnięcia 1111 1110
    int a;
     char bufor[8];
     // inicjalizacja LCD
     lcd_init();
     // zapisz na LCD przykładowy tekst
     write_text("DS18B20-");
     // petla nieskończona
     while(1)
     {
       LCDxy(8,0);
       a=ow_reset();
       if (a)
       write_text("obecny");
       else
       write_text("brak  ");
     
    if(a)
     {

     ow_write_byte(0xCC);      //CC - przeskocz skanowanie ROM, wysyłanie seriala itd
     ow_write_byte(0x44);      //44 - konwertuj temperaturę

     waitms(250);   //105ms na konwersję potrzeba ok 750ms, kiedy max rozdzielczość
     waitms(250);
     waitms(250);
     waitms(250);
     waitms(250);
     waitms(250);
     waitms(250);
     waitms(250);
     }


    if(a)
     {
     ow_write_byte(0xCC);
     ow_write_byte(0xBE);
     }
    lsb = ow_read_byte();
    msb = ow_read_byte();
    LCDxy(0,1);
    write_text(itoa(msb,bufor,2));

    write_text(itoa(lsb,bufor,2));
     }
     return 0;
    }

    na LCD-ku pod opisem DS18B20-obecny/brak mam same jedynki... muszę coś pogrzebać, bo tak być nie może, przecież w pokoju mam około 20 st C!
    Znalazłem. Trzeba jeszcze zresetować DS-a przed konwersją i przed odczytem temp.