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.

[c][atmega8] Błąd przy wyświetlaniu na LCD,instrukcja switch

peterrrm 02 Gru 2009 20:01 1812 5
  • #1 02 Gru 2009 20:01
    peterrrm
    Poziom 14  

    Witam ,
    Mam pewien problem nie rozumie dlaczego poniższy kod nie działa prawidłowo:

    Code:
                while(!esc)   //jesli nacisniete ESC to wychodzi
    
                   {
                   LCD_Clear();
                   LCD_WriteText("ok-zamknij");
                   LCD_GoTo(0,1);
                   LCD_WriteText("v-otworz");
                   _delay_ms(100);
                   while(ok)
                      {
                      _delay_ms(400);
                      zamykanie_on;
                      LCD_Clear();
                      LCD_WriteText("zamykanie");
                      }
                   
                   while(v)
                      {
                      otwieranie_on;
                      LCD_Clear();
                      LCD_WriteText("otwieranie");
                      _delay_ms(100);
                      }
                      
                   zamykanie_off;
                   otwieranie_off;
                   }
                break;
                }

    Gdy w while(V) znajduje się obsługa LCD to nie działa przetwarzanie ADC w całym programie. Jeśli natomiast usunę :
    LCD_Clear() oraz LCD_WriteText("otwieranie");
    ADC działa normalnie w całym programie. Co Ciekawe w tym kawałku kodu nie wywołuje przetwarzania ani nic z nim związanego.
    Dobrze jest również wtedy jeśli bym usunął:
    LCD_Clear() oraz LCD_WriteText("zamykanie");
    po prostu nie może być jednocześnie w while(v) i while(ok) , obsługa LCD. Ale nie rozumie dlaczego i jak w takim razie wyświetlać w danym momencie to co chcę?


    Przycisk "Pisownia" został użyty.

    Post był raportowany.
    Popraw błędy i interpunkcję. Użyj przycisku PISOWNIA -->REGULAMIN pkt 15.
    Początek zdania? Zaczynamy wielką literą.
    Następnym razem będzie UPOMNIENIE. [hefid]

    0 5
  • #2 02 Gru 2009 20:36
    tmf
    Moderator Mikrokontrolery Projektowanie

    Jesli nie pokazesz calego kodu to potrzebna bedzie szklana kula.
    esc, ok i v jak sie domyslam modyfikujesz w jakims przerwaniu albo w tych funkcjach zamykanie_on i otwieranie_on? Jesli w przerwaniach to pamietales o volatile? ADC dziala na przerwaniach?

    0
  • #3 02 Gru 2009 21:53
    peterrrm
    Poziom 14  

    Oto cały kod:

    Code:
    #include <avr/io.h>
    
    #include <inttypes.h>
    #include <bity.h>
    #include <util/delay.h>
    #include <hd44780.c>
    #include <stdlib.h>
    #include <avr/interrupt.h>


    #define esc (!(PIND&0x08))  //sprawdzenie pinu "ESC" czy wcisniety
    #define ok (!(PIND&0x10)) //sprawdzenie pinu "OK" czy wcisniety
    #define v (!(PINC&0x20)) //sprawdzenie pinu "V" czy wcisniety
    #define pompa_on PORTD|=(1<<2)  //zalaczenie pompy
    #define pompa_off PORTD&=0xfb   //wylaczenie pompy
    #define zamykanie_on PORTD|=(1<<1) ,PORTD&=0xfe //zalaczenie zamykania zaworu
    #define zamykanie_off PORTD&=0xfd   //wylaczenie zamykania zaworu
    #define otwieranie_on PORTD|=(1<<0) ,PORTD&=0xfd //zalaczenie otwierania zaworu
    #define otwieranie_off PORTD&=0xfe   //wylaczenie otwierania zaworu



    double konwersja;      // Zmienna do przechowywania wyniku pomiaru
    char buffer_n[5];           // Bufor do przechowywania wyniku konwersji z "double" na ASCII
    double tem=0;  //zmienna dla wyniku pomiaru cisnienia   
    int a=0;  //zmienna dla petli przy wyswietlaniu napisu
    char buffer[5];

    void Inicjalizacja(void)   //funkcja inicjalizacji LCD i przetwornika ADC
    {
    // Inicjalizacja LCD 
       LCD_Initalize();      // Inicjalizacja wyswietlacza
       LCD_Clear();      
    // Wybranie wewnętrznego żródła napięcia odniesienia   
       ADMUX |= _BV(REFS0);      
       ADMUX |= _BV(REFS1);      
    // Zezwolenie na konwersję   
       ADCSRA |= _BV(ADEN);      
    // Wybranie częstotliwości dla taktowania przetwornika  (1/8 częstotliwosci zegara kontrolera)
       ADCSRA |= _BV(ADPS0);   
       //ADCSRA |= _BV(ADPS1);   //   
    }


    char pomiar(void)  //funkcja dokonująca pomiaru
    {   int i;
       tem=0;
       for(i=0;i<80;i++)                  //petla pomiarowa
          {
          ADCSRA |= _BV(ADSC);         // Rozpoczęcie przetwarzania
          
          while(bit_is_set(ADCSRA,ADSC))   // Oczekiwanie na zakończenie przetwarzania




          {};   
          konwersja=(double)ADCW;              // Zapisanie  wyniku konwersji do zmiennej "konwersja"                           
          tem=tem+(double)konwersja*1.570454-400;   
       _delay_ms(1);
          }
       tem=tem/80;    //wyliczenie sredniej wartosci   
       dtostrf(tem, 1,0,buffer_n);// Konwersja liczby double  do asci
       return buffer_n;  //funkcja zwraca buffer_n czyli wartosc cisnia w kodzie ASCI
    }



    int main(void)
    {
       DDRC|=(1<<4)|(1<<3); // ustawienie pin 3 i 4 portu C jako wyjscie
       DDRD|=(1<<0)|(1<<1)|(1<<2)|(1<<6);   // ustawienie pin 0 ,1,2 portu D jako wyjscie
       
       
       //domyslnie wszystkie wejscia
       PORTC|=(1<<5);  //podciagniecie wejscia pin 5 portu C do VCC 
       PORTD|=(1<<3)|(1<<4);  //podciagniecie wejscia pin 3 i 4 portu D do VCC
       
       Inicjalizacja();  // Inicjalizacja ADC i LCD
       

       for(a=0;a<16;a++)
       {
       LCD_GoTo(a,1);
       LCD_WriteText("Witaj");
       _delay_ms(5);
       LCD_GoTo(0,1);
       LCD_WriteText("                ");
       LCD_GoTo(0,0);
       }
       
       
       
       
       a=1; // a=1 dla prawidlowego dzialania menu
       
       while(1)
       {

          
          if(v) a=a+1;  //menu wyboru opcji
          if(a>4) a=0;
          switch(a) 
             {
                case 1 :
                {
                LCD_Clear();
                LCD_WriteText("Wybierz opcje");
                LCD_GoTo(0,1);
                LCD_WriteText("Tryb automat.");
                break;
                }
                case 2 :
                {
                LCD_Clear();
                LCD_WriteText("Wybierz opcje");
                LCD_GoTo(0,1);
                LCD_WriteText("Pomiar cis.");
                break;
                }
                case 3 :
                {
                LCD_Clear();
                LCD_WriteText("Wybierz opcje");
                LCD_GoTo(0,1);
                LCD_WriteText("Praca pompy");
                break;
                }
                case 4 :
                {
                LCD_Clear();
                LCD_WriteText("Wybierz opcje");
                LCD_GoTo(0,1);
                LCD_WriteText("Praca zaworu");
                break;
                }
             }
          _delay_ms(300);
          
          
          if(ok)  // po wcisnieciu ok wejscie do menu
          {
             switch(a) 
             {
                case 1 :
                {
                   while(a!=4)  //jesli a rozne od 4 to wykonuje petle po skonczeniu ustawia a=4
                   {
                      LCD_Clear();
                      LCD_WriteText("proba 1h");
                      _delay_ms(1000);
                      a=4;
                   }
                break;
                   
                }
                case 2 :
                {
                   while(!esc)   //jesli nacisniete ESC to wychodzi
                   {
                      LCD_Clear();
                      LCD_WriteText("Pomiar cis.");
                      LCD_GoTo(0,1);
                      LCD_WriteText("P=");
                      LCD_WriteText(pomiar());
                      LCD_WriteText("mbar");
                      _delay_ms(100);
                   }
                break;
                }
                case 3 :
                {
                while(!esc)   //jesli nacisniete ESC to wychodzi
                   {
                   LCD_Clear();
                   LCD_WriteText("Praca pompy");
                   LCD_GoTo(0,1);
                   LCD_WriteText("V-wlacz pompe");
                   _delay_ms(100);
                      while(v)
                         {
                         pompa_on;
                         LCD_WriteText("                "); //zamiast: LCD_Clear() ,zapobiega to migotaniu LCDeka
       LCD_GoTo(0,0);
                         LCD_WriteText("Praca pompy");
                         LCD_GoTo(0,1);
                         LCD_WriteText("P=");
                         LCD_WriteText(pomiar());
                         LCD_WriteText("mbar");
                         _delay_ms(100);
                         }
                   pompa_off;
                   }
                break;
                }
                case 4 :
                {
                while(!esc)   //jesli nacisniete ESC to wychodzi
                   {
                   LCD_Clear();
                   LCD_WriteText("ok-zamknij");
                   LCD_GoTo(0,1);
                   LCD_WriteText("v-otworz");
                   _delay_ms(100);
                   while(ok)
                      {
                      _delay_ms(400);
                      zamykanie_on;
                      LCD_Clear();
                      LCD_WriteText("zamykanie");
                      }
                   
                   while(v)
                      {
                      otwieranie_on;
                      LCD_Clear();
                      LCD_WriteText("otwieranie");
                      _delay_ms(100);
                      }
                      
                   zamykanie_off;
                   otwieranie_off;
                   }
                break;
                }
             }
          }
       }
       return 0;
       
    }



       













    ok,esc,v - to przyciski. Ani przyciski ani ADC nie są obsługiwane w przerwaniach. Jeśli wyrzucę pierwsze switch(a) a resztę zostawię bez zmian to wtedy też działa dobrze.

    0
  • Pomocny post
    #4 02 Gru 2009 22:39
    tmf
    Moderator Mikrokontrolery Projektowanie

    Pewnie bledow masz wiele, ale zacznijmy od poczatku:

    Code:
       dtostrf(tem, 1,0,buffer_n);// Konwersja liczby double  do asci
    
       return buffer_n;  //funkcja zwraca buffer_n czyli wartosc cisnia w kodzie ASCI


    dtostrf nie sprawdza dlugosci bufora, ktory u ciebie wynosi 5 bajtow, w tym musisz miec miejsce na znak konca strungu. Czyli 4 bajty zostaja, konwertujesz typ double, ktory moze zawierac liczby o dlugosci wiekszej niz 4 znaki (9999), wiec funkcja ta nadpisuje to co jest za buforem.
    Poza tym powinienes o ile juz musisz (bo po co skoro definiujesz bufor jako zmienna globalna) zwracac wskaznik na bufor.
    Po case klamry nie sa potrzebne, a umieszczenie w nich break nie zadziala tak jak myslisz. To tak na szybko, zapewne to ci nie zlikwiduje bledu, ale popraw kod, pomyslimy co dalej.

    0
  • #5 03 Gru 2009 22:21
    peterrrm
    Poziom 14  

    Dziękuje bardzo za pomoc!

    Po zamianach ADC działa:)

    Jeśli mogę prosić to wyjaśnij trochę więcej o co z tym chodzi:

    Cytat:
    dtostrf nie sprawdza dlugosci bufora, ktory u ciebie wynosi 5 bajtow, w tym musisz miec miejsce na znak konca strungu. Czyli 4....


    Dziękuje jeszcze raz i pozdrawiam

    0
  • #6 04 Gru 2009 09:34
    tmf
    Moderator Mikrokontrolery Projektowanie

    Funkcja ta konwertuje zmienna typu double (ten typ na AVR nie jest supportowany, jest to rownowazne z typem float) na string, do bufora, ktorego adres podajesz jako jeden z parametrow. Bufor musi byc na tyle duzy, zeby pomiescic maksymalna konwertowana liczbe + jeden bajt na znak konczacy string (0). Jesli masz bufor o dl. np. 5 bajtow a sprobujesz skonwertowac liczbe 12345 to w efekcie zmienna, ktora w pamieci jest alokowana za buforem zostanie nadpisana (do konwersji potrzebujesz 5 bajtow na kolejne cyfry + 1 na znak konca). W efekcie to co sie stanie zalezy od tego co tam dalej w pamieci jest - czasami zadziala, czasami nadpisze kolejna zmienna, czasami ta zmienna nadpisze np. znak konca tekstu w buforze i jak sprobujesz go przetworzyc to program sie albo wykrzaczy, albo wyswietli dziwne znaki.

    0