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 - Jak odczytać sygnał na PINC0, 1, 2 w złożonym programie?

beniamin82 21 Kwi 2009 07:07 2333 12
REKLAMA
  • #1 6439167
    beniamin82
    Poziom 10  
    Posty: 19
    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ś.
    Załączniki:
    • [C] AVR ATmega8 - Jak odczytać sygnał na PINC0, 1, 2 w złożonym programie? zaplon1.jpg (37.9 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #2 6439208
    _Robak_
    Poziom 33  
    Posty: 2209
    Pomógł: 231
    Ocena: 29
    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  
    Posty: 19
    Zdaje się że nie mam AVCC podłączonego
  • #4 6439434
    _Robak_
    Poziom 33  
    Posty: 2209
    Pomógł: 231
    Ocena: 29
    To podlacz :> PortC jest zasilany wlasnie z AVCC :>
  • #5 6439453
    beniamin82
    Poziom 10  
    Posty: 19
    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  
    Posty: 1439
    Pomógł: 229
    Ocena: 6
    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  
    Posty: 19
    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  
    Posty: 1439
    Pomógł: 229
    Ocena: 6
    Ok 10kΩ.
  • Pomocny post
    #9 6440115
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    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  
    Posty: 2209
    Pomógł: 231
    Ocena: 29
    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  
    Posty: 19
    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??
  • REKLAMA
  • #12 6441754
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    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  
    Posty: 19
    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]

Podsumowanie tematu

LABEL_AI_GENERATED
Użytkownik buduje elektroniczny układ wyprzedzenia zapłonu oparty na mikrokontrolerze ATmega8. Początkowo napotkał problem z odczytem stanu wysokiego na pinach wejściowych PINC0, PINC1, PINC2 w złożonym programie, mimo że prosta operacja kopiowania portu (PORTD=~PINC) działała. Wskazano, że mikrokontrolery AVR nie mają wewnętrznych rezystorów pull-down i zalecono zastosowanie zewnętrznych rezystorów (ok. 10kΩ) zwierających piny wejściowe do masy. Zasugerowano również podłączenie pinu AVCC, z którego zasilany jest port C, choć wyjaśniono, że w ATmega8 jest on wewnętrznie połączony przez rezystancję. Kluczowym problemem okazał się błąd w kodzie polegający na nieprawidłowym sprawdzaniu stanu pinów - zamiast `(PINC & _BV(PINCx))`, użyto samych symboli `PINCx`, które reprezentują numery bitów. Po korekcie sposobu odczytu pinów program zaczął działać, aczkolwiek pojawiły się problemy z obliczeniami wyprzedzenia zapłonu. Użytkownik planuje zastąpienie obliczeń tablicą danych przechowywaną w pamięci FLASH (PROGMEM) i dopytuje o prawidłowość obliczeń częstotliwości Timer1. Zwrócono uwagę na potencjalne problemy z dostępem do wielobajtowych zmiennych globalnych w procedurach przerwania.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA