logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

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

beniamin82 21 Kwi 2009 07:07 2126 12
REKLAMA
  • #1 6439167
    beniamin82
    Poziom 10  
    Pracuję nad elektronicznym układem wyprzedzenia zapłonu.
    Układzik elektroniczny z programem typu:



    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:



    
    #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ś.
  • REKLAMA
  • #2 6439208
    _Robak_
    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 ?
  • REKLAMA
  • #3 6439361
    beniamin82
    Poziom 10  
    Zdaje się że nie mam AVCC podłączonego
  • #4 6439434
    _Robak_
    Poziom 33  
    To podlacz :> PortC jest zasilany wlasnie z AVCC :>
  • REKLAMA
  • #5 6439453
    beniamin82
    Poziom 10  
    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ę?
  • REKLAMA
  • #6 6439767
    dawid512
    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.
  • #7 6439935
    beniamin82
    Poziom 10  
    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.
  • #8 6440068
    dawid512
    Poziom 32  
    Ok 10kΩ.
  • Pomocny post
    #9 6440115
    BoskiDialer
    Poziom 34  
    Nigdzie nie widzę definicji PINCx, a więc zakładam domyślne pochodzące z avr/io.h (iom8.h):
    /* 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!
  • #10 6440173
    _Robak_
    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 :>
  • #11 6441652
    beniamin82
    Poziom 10  
    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??
  • #12 6441754
    BoskiDialer
    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.
  • #13 6452623
    beniamin82
    Poziom 10  
    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

    
    #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]
REKLAMA