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.

[C]AVR atmega8- problem z odczytaniem portu...

21 Kwi 2009 07:07 1958 12
  • Poziom 9  
    Pracuję nad elektronicznym układem wyprzedzenia zapłonu.
    Układzik elektroniczny z programem typu:

    Code:
    PORTD=~PINC 


    działa bez problemu, ale jak już "skomplikowałem program to ni hu hu"

    Zachowuje się tak jakby nigdy nie występowała jedynka na PINC0, 1, 2.
    Jak najlepiej wyłapać to zdarzenie

    W załączniku układ elektroniczny.

    A teraz kod:



    Code:

    #define F_CPU 12800000L
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <avr/delay.h>

    volatile unsigned int wej_z_przer, wyj_na_cylindry, Temp_przepT2,przepT2,zawT2,faza,cylinder,
    przyspieszenie ;

    int oblicz_T1 (int przep, int zaw)

    {
    int wynik;


    if (przep>3) {faza=4;}

    if (przep<3) {zaw=(przep*255)+zaw;}

    if (zaw>624)
       {
        faza=4;
       }

    if (zaw<624 && zaw>=312)
        {
       
       wynik=(int)((65535-(((zaw-312)*(5.5))+1525))+0.5);

       }

    if (zaw<312 && zaw>=174)
       {
       
        wynik=(int)((65535-(((zaw-174)*(5.17))+812))+0.5);
       
       }

    if (zaw<174)
       {
       
       wynik=(int)((65535-(zaw*(4.66))+0.5));

       }



    return wynik;
    }
             

    SIGNAL (SIG_OVERFLOW1)
    {

    PORTD=~_BV(cylinder);

    }
     
     
    SIGNAL (SIG_OVERFLOW2)
    {
    Temp_przepT2++;

    }





    int main(void)
    {
    faza=1;

    DDRD=0xFF; //PORT D jako wyjście
    DDRC=0x00; //PORT C jako wejście
    PORTC=0x00; //podciągnij do zera sygnal z przerywacza "1"


    TIMSK=_BV(TOIE1)|_BV(TOIE2); //opcja przerwania T1 i T2
    TCCR1A=0x00;
    TCCR1B=_BV(CS10)|_BV(CS11); //prescaler ck/128

    TCCR2=_BV(CS22)|_BV(CS21)|_BV(CS20); //prescaler ck/1024


    sei();   //uruchomienie przerwań



    while(1)    //pętla nieskończona
           {

    PORTD=_BV(5);

    if ((PINC0) && faza==1)  // Jeśli pierwszy cylinder
             
            {
               TCNT2=0x01;   //Uruchom T2 wpisujac wartosc poczatkowa 1
             faza=2; 
             asm("nop"); //uniknecie wachan napiecia na styku
             asm("nop"); //uniknecie wachan napiecia na styku
               asm("nop"); //uniknecie wachan napiecia na styku
               PORTD=_BV(6);
                    
            }

    if ((PINC1) && faza==2)  // Jeśli drugi cylinder
             
            {
               faza=3;  //faza oczekiwania na pierwszy czas T2
             asm("nop"); //uniknecie wachan napiecia na styku
             asm("nop"); //uniknecie wachan napiecia na styku
               asm("nop"); //uniknecie wachan napiecia na styku
               PORTD=_BV(7);
                          
            }



    if ((PINC0) && faza==3)  // Jeśli pierwszy cylinder
             
            {
               przepT2=Temp_przepT2;
             zawT2=TCNT2;
             TCNT2=0x01;
               Temp_przepT2=0x00;
               
             przyspieszenie=oblicz_T1(przepT2,zawT2);
             TCNT1=przyspieszenie;
             cylinder=0x05;
                
               }


    if ((PINC1) && faza==3)  // Jeśli drugi cylinder
             
            {
             cylinder=0x03;
             asm("nop"); //uniknecie wachan napiecia na styku
             asm("nop"); //uniknecie wachan napiecia na styku
               asm("nop"); //uniknecie wachan napiecia na styku
              TCNT1=przyspieszenie;
               }



    if ((PINC2) && faza==3)  // Jeśli trzeci cylinder
             
            {
             cylinder=0x04;
             asm("nop"); //uniknecie wachan napiecia na styku
             asm("nop"); //uniknecie wachan napiecia na styku
               asm("nop"); //uniknecie wachan napiecia na styku
              TCNT1=przyspieszenie;
               }


    if (faza==4)   //przy prędkości oborotowej do 1198 lub awarii nie przyspieszaj zaplonu.
        {

        PORTD=~PINC;
     
        }




            }




    }
     


    Na wejścia In1-In2 są podłączone bezpośrednio przerywacze zapłonu (bez kondensatorów). Przerywacz cały czas jest " w powietrzu" daje zero w momencie kiedy powienien nastąpić zapłon.

    Licznik T1 jest używany przeze mnie do przyspieszenia zapłonu.
    Licznik T2 do określenia prędkości obrotowej silnika.

    Wejścia z Kanapki(wymienna płytka, na rysunku z NANDami teraz z uP) mam podpięte pod PC0-PC2 wyjścia analogicznie PD0-PD2.

    Pod ostatnie trzy piny portu D mam podpięte diody do testów, zawsze mogę sobie półapkę wpisać czy coś.



    [/code]
  • Poziom 33  
    Cytat:
    PORTC=0x00; //podciągnij do zera sygnal z przerywacza "1"

    Po pierwsze to atmegi nie maja pulldownow
    Po drugie, masz podlaczone AVCC ?
  • Poziom 9  
    Zdaje się że nie mam AVCC podłączonego
  • Poziom 33  
    To podlacz :> PortC jest zasilany wlasnie z AVCC :>
  • Poziom 9  
    Ok sprawdzę, ale czy wtedy nie działałby też

    PORTD=~PINC?? (bo to mi działa i silniczek śmiga)

    Dodano po 1 [minuty]:

    aha jeszcze jedno pytanko czy 3xnop spełni swoją rolę?
  • Poziom 32  
    Odnośnie AVCC w m8 jest ono na stałe zwarte przez pewną rezystancję(dość znany błąd). Odnośnie nop, jest to w swoim rodzaju opóźnienie choć bardziej polecam gotowe funkcje opóźniające z util/delay.h. Tak jak już wcześniej wspomniał kolega atmega nie posiada pull-down a więc musisz zastosować zew. rezystor zwierający daną końcówkę do masy.

    Edit: poprawiono.
  • Poziom 9  
    Czyli wszystkie trzy wejścia zewrzeć do masy opornikiem.
    Oraz zasilić AVCC.
    A jak duży rezystor mam dać, żeby prąd nie był za duży dla uP.
  • Pomocny post
    Poziom 34  
    Nigdzie nie widzę definicji PINCx, a więc zakładam domyślne pochodzące z avr/io.h (iom8.h):
    Code:
    /* PINC */
    
    #define PINC6   6
    #define PINC5   5
    #define PINC4   4
    #define PINC3   3
    #define PINC2   2
    #define PINC1   1
    #define PINC0   0

    Tak więc są to stałe zdefiniowane jeśli dany pin istnieje, zawierają numer bitu który należy sprawdzać. Nie są to marka do sprawdzania stanu pinu. Stąd warunek if ((PINC0) && faza==1) nigdy nie będzie spełniony (PINC0 == 0 a więc zawsze fałsz), w następnych pin nie będzie sprawdzany, tylko sama wartość zmiennej "faza". Musisz zmienić wyrażenia typu (PINCx) na (PINC & _BV(PINCx))

    Dodano po 4 [minuty]:

    Swoją drogą, starał bym się aby zmienne globalne były co najwyżej rozmiaru 1 bajt, oraz aby było ich jak najmniej. W przeciwnym przypadku trzeba sprawdzić, czy trzeba dać dostęp atomowy do zmiennych. W przeciwnym przypadku układ może zachowywać się momentami nieprzewidywalnie (wystąpienie przerwania pomiędzy odczytem pierwszego a drugiego bajtu). Warto sprawdzić wszystkie najgorsze przypadki!
  • Poziom 33  
    Proponuje krok po kroku sprawdzac program a nie piszesz ze taki jednolinijkowiec dziala a taki na 200 juz nie ;> Doprowadz do tego ze kod jest kmkasymalnie ograniczony i problem wystepuje, wtedy mozna analizowac :>
  • Poziom 9  
    Cytat:
    Musisz zmienić wyrażenia typu (PINCx) na (PINC & _BV(PINCx))


    I zagrało.... :)
    Co prawda pochrzaniłem coś w obliczeniach przyspieszania zapłonu i kilka razy autko strzeliło w gaźnik... ale jestem już na dobrej drodze...
    Teraz tylko muszę "zabezpieczyć" program.

    Jak autko będzie śmigało to na pewno się pochwalę i podzielę...

    Tak się zastanawiam, bo nie polutowałem jeszcze tych oporników, są konieczne czy wskazane??
  • Poziom 34  
    beniamin82 napisał:
    Co prawda pochrzaniłem coś w obliczeniach przyspieszania zapłonu i kilka razy autko strzeliło w gaźnik...

    Pewnie funkcja oblicz_T1 działa niepoprawnie dla przep=3 (żaden z pierwszych dwóch warunków nie jest spełniony), dla zaw=624(żaden z 3-6) oraz ogólnie dla zaw >= 624 (brak wartości wynik). Oczywiście nadal mogą się pojawić problemy z dostępem do zmiennych globalnych.
  • Poziom 9  
    Jutro wieczorkiem będę modyfikował program.
    Mam zamiar po prostu wpisać do programu tablicę z gotowymi danym (policzonymi przez exela)
    Będzie to i dokładniejsze i mniej pracochłonne dla procka.
    Dzisiaj "poćwiczyłem" trochę zmienne tablicowe w PROGMEM i zobaczymy co z tego jutro wyniknie.
    będę na pewno informował o postępach.

    Testuje mój pomysł z tabelą zmiennych i cos mi się nie podoba.

    Niech mi ktoś powie czy licznik T1 (16bitowy) zwiększa się co 5uS??
    Takie obliczenia założyłem w excelu obliczając czas po którym powinien komputerek dać iskrę.

    12,8Mhz / prescaler 64 =5uS


    zmienna indeks będzie docelowo pobierana z licznika T2 (zwiększającego się co 80uS (prescaler 1024) i jest wskaźnikiem prędkości obrotowej.
    Założyłem 459 punktów charakterystyki.

    np. dla wskaźnika 300 powinien program zaświecić diodę po 3,1ms i po takim samym czasie ją zgasić. natomiast podstawiając taką wartość w miejsce indeks widzę jak dioda miga około 3 razy na sek.


    Puszczając program tak jak poniżej, czyli z zwiększającym się indeksem widzę jak dioda miga coraz wolniej.

    teraz jeszcze jedno pytanko, jeżeli stałe z tabeli są 16bitowe to indeks pokazuje początek każdej stałej, czy początek kolejnego bajtu?

    No i oczywiście koronne pytanie: Ile trwa odczyt z pamięci PROGMEM.

    Tutaj programik testowy

    Code:

    #define F_CPU 12800000L
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>

    static const PROGMEM int licznik[]=
    {64915,64911,64907,64903,64898,64894,64890,64886,64882,
    64878,64874,64870,64865,64861,64857,64853,64849,64845,

    ....cała tabela ma 459 stałych w zakresie od 64915do 62127....

    64841,64836,64832,64828,64824,64820,64816,64812,64808,
    64803,64799,64795,64791,64787,64783,64779,64774,64770,
    62292,62286,62280,62274,62268,62262,62256,62250,62244,
    62239,62233,62227,62221,62215,62209,62203,62197,62191,
    62186,62180,62174,62168,62162,62156,62150,62144,62138,
    62133,62127
    };

    volatile unsigned int  led,indeks,wys;
             

    SIGNAL (SIG_OVERFLOW1)
    {
    led=~led;
    PORTD=led;
    wys=1;

    if (indeks<450) {   indeks++;};

    }


    int main(void)
    {




    DDRD=0xFF; //PORT D jako wyjście


    TIMSK=_BV(TOIE1);
    TCCR1A=0x00;
    TCCR1B=_BV(CS10)|_BV(CS11); //prescaler ck/64


    sei();   //uruchomienie przerwań
    indeks=0;

    wys=1;


    while(1)    //pętla nieskończona
           {

         if (wys==1)
         {
             
          TCNT1=pgm_read_word(&licznik[indeks]);
           wys=0;

          }
               }


        }
     
     


    Założyłem nowy watek : tutaj

    beniamin82 napisał:
    Cytat:
    Tak się zastanawiam, bo nie polutowałem jeszcze tych oporników, są konieczne czy wskazane??


    W związku z tym że nikt nie odpowiedział na to pytanie, przylutowałem te oporniki.... i są one wymagane do prawidłowego odczytywania portu.
    Wcześniej miałem jakieś śmieci na pinach. Przynajmniej na tych nie wyzerowanych.

    Post był raportowany.
    Pisanie postu pod postem.
    Należy używać przycisku ZMIEŃ.
    Scaliłem TRZY posty. [hefid]