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.

Atmega 16 problem z opoznieniem sygnalu

09 Cze 2009 19:08 3416 27
  • Poziom 23  
    witam
    Podaje na PD2 sygnal z generatora o częstotliwosci 100Hz i nastepnie opózniam go i wysylam na nożkę PA2. Jesli robię opóżnienie o 1ms to wszystko wygląda ok, czyli zboczel narastający(PA2) jest opoznione o 1 ms w stosunku do PD2, natomoast zbocze opadające nie jest opoznione. Problem pojawia sie gdy opoźniam sygnal o 2 ms, wtedy oprocz opoznienia na zboczu narastającym otrzymuje jescze nie wiem skad opoznienie na zboczu opadającym, skad to opoźnienie? KWarc 1 Mhz. podsylam głowną pętlę programu i sceyny z oscyloskopu.


    while(1)
    {

    inpD=PIND&0x04;
    if (inpD==0x04)
    {

    sbi(PORTA,PA2);
    }
    else
    {
    _delay_ms(1);
    cbi(PORTA,PA2);
    }

    sren dla opoznienia 1 ms
    Atmega 16 problem z opoznieniem sygnalu

    screen dla 2 ms i tu jest problem
    Atmega 16 problem z opoznieniem sygnalu
  • Pomocny post
    Poziom 23  
    Opoźnienie powstaje dlatego:
    Podczas wykonania pierwszej pętli (jesli z generatora jest 1) czekasz 2ms,
    następna pętla i znowu czekasz 2ms, w czasie tych 2ms sygnał z generatora zmienił się na zero ale ty dalej czekasz...

    Pozdrawiam
  • Poziom 38  
    Wykorzystaj przerwania.
    _delay w C i wait w Bascomie to jest to samo paskudztwo.
  • Poziom 23  
    tez dopiero przed chwila na to wpadłem, ale dzieki za pomoc

    Dodano po 9 [minuty]:

    moze jakis przyklad jak wykorzystac przerwanie w tym przypadku
  • Pomocny post
    Poziom 38  
    Od INT0-narastające zbocze a od INT1 opadające.
    Potem TIMER.
    Chociaż to rozrzutne wykorzystanie zasobów sprzętowych.
    Pewnie da się taniej.

    Dodano po 29 [minuty]:

    Albo w pętli głównej (pooling):
    jeśli PD.2=1 to
    start timer
    odlicz 1ms(albo 2) (może programowo się podeprzeć-nie wiem jaki kwarc i podzielnik)
    ustaw PA.2
    koniec jeśli.
    A jak nie:
    ustaw PA.2=0
  • Poziom 23  
    Myslalem tez nad czyms takim .
    1.Narastajace zbocze na INT0, start timera ostawionego na przepelnienie po 1 ms i w przerwaniu od przepelnienia ustawiam PA2 na 1, a petli głownej sprawdzanie stanu PD2 pod katem wystapienia stanu niskiego i ustawinie PA2 na 0
    drugi sposob
    2. Bez przerwan, tak jak mialem na poczatku w programie z delay tylko ze po pierwszym wyjsciu z delay, wchodzil by w petle wait czekajac na niski stan na PD2, dzieki temu nie bylo by problemu ponownego wchodzenia do funkcji delay.

    moze jesze jakies pomysly?
  • Pomocny post
    VIP Zasłużony dla elektroda
    Zastanów się jak to ma dokładnie działać. Czy sygnał może się zmienić w czasie opóźnienia? Jeśli tak, to jak ma zareagować układ? Jeśli nie, to po prostu wykrywaj narastające zbocze:
    Code:
    #define INPUT_VALUE (PIND & _BV(2))
    
    #define TOGGLE_OUTPUT (PINA |= _BV(2))
    uint8_t old_input = INPUT_VALUE;
    for (;;) {
        uint8_t new_input = INPUT_VALUE;
        if (new_input ^ old_input) /* prawda jeśli wystąpiło zbocze */
        {
            if (new_input) /* jeśli zbocze narastające */
                _delay_ms(2);
            TOGGLE_OUTPUT;
            old_input = new_input;
        }
    }

    Pozdrawiam,
    Dr.Vee
  • Poziom 23  
    mam kolejny problem z opoznieniem, tym razem opoznienie pojawia sie w momencie gdy właczam przerwanie na INT0 (GICR=GICR |(1<<INT0);)
    zamieszczam screen bez właczonego przerwania oraz z wlaczonym przerwaniem, jak widac po właczeniu przerwania powstaje opoznienie sygnalu , skad ono sie bierze?

    bez właczonego przerwania
    Atmega 16 problem z opoznieniem sygnalu
    z właczonym przerwaiem
    Atmega 16 problem z opoznieniem sygnalu
  • Poziom 38  
    A co robisz w przerwaniu?
    Wygląda na 50us-ok. 50 instrukcji dla 1MHz.
    Gdy obsługujesz przerwanie obsługa programu głównego jest w tym czasie przerwana.
    Można:
    zwiększyć częstotliwość kwarcu.
    w przerwaniu ustawiać tylko jakąś flagę a procedury z przerwania przenieść do programu głównego.
    Albo jedno i drugie.

    Dodano po 20 [minuty]:

    Można jeszcze nie odkładać rejestrów na stos-jeśli dokładnie wiesz że przerwanie ich nie używa.
    Ale jakieś opóźnienie będzie zawsze.
  • Poziom 23  
    wlasnie chodzi o to, ze w przerwaniu ustawiam tylko flage. I nie wiem co mu pochlania tyle czasu. W sumie po wujsciu z przerwania w głownej petli jest jescze warunek if , wlaczenie timera i odczyt rejestru, ale to chyba nie pochlania 50 instrukcji
  • Pomocny post
    Poziom 38  
    Sprawdź w AVRstudio ile jest instrukcji.
  • Poziom 23  
    rzeczywiscie po analizie w avr studio, wychodzi, ze wejscie do obslugi przerwania, ustawienie flagi, pop i push r0 oraz SREG i na koncu wyjscie z obslugi przerwania zajmuje 28 cykli do tego w glównej petli programu jest if odczyt rejestru i zapis co w sumie daje kolejne 30 cykli zegara i tak w sumie uzbierało się 48 cyki czyli 48 us, pozostaje tylko użyć szybszego kwarcu.

    Napisał byś jak zrobić zeby procek nie wpychal żadnych rejesrów na stos , bo w moim przypadku jest to zbędne. Nizej to co u mnie wypycha na stos
    00000073: __vector_1
    {
    PUSH R1 Push register on stack
    +00000074: 920F PUSH R0 Push register on stack
    +00000075: B60F IN R0,0x3F In from I/O location
    +00000076: 920F PUSH R0 Push register on stack
    +00000077: 2411 CLR R1 Clear Register
    +00000078: 938F PUSH R24 Push register on stack
    ex_int=1;//ta flage ustawiam
    +00000079: E081 LDI R24,0x01 Load immediate
    +0000007A: 93800061 STS 0x0061,R24 Store direct to data space
    83:
    }

    sens ma tylko PUSH R24 po tego rejestru uzywa do zaladowania zmiennej, reszta jest razcej zbędna no moze z wyjatkiem rejestru 0x3F(SREG), chociaz dla mojego programu w tej postaci raczej tez to nie bedzie konieczne. Jak nie pominać te zbędne pushe?
  • VIP Zasłużony dla elektroda
    Code:
    #include <avr/interrupt.h>
    
    #include <avr/io.h>
    #include <stdint.h>

    register uint8_t flaga asm("r2");

    ISR(INT0_vect, ISR_NAKED)
    {
        flaga += 1;
        /* alternatywnie, dla pewności:
        __asm__ __volatile__ (
                "inc %0" :
                "=r" (flaga) : "0" (flaga));
        */
        reti();
    }

    Pozdrawiam,
    Dr.Vee
  • Poziom 38  
    Baardzo mnie przeceniasz.
    Pisać programów to ja jeszcze nie umiem.
    Ale napisać co zrobić-spróbuję.
    Jest taki sposób żeby nie zezwalać na przerwanie-ale odczytać w programie głównym że pojawiło się żądanie przerwania-flaga.
    W rejestrze odpowiednim.
    Jak jest-to ją zerujemy (wstawiając 1-a nie 0 -mimo że jest 1-nie rozumiem dlaczego-ale w większości rejestrów w AVR tak jest-zresztą sprawdź).
    Znaczy-było przerwanie-ale go nie obsługujemy.
    Wtedy nic nie jest odkładane na stos ani z niego zdejmowane.
    Potem wykonujemy naszą procedurę-if.
    28 cykli mniej.
    Zostaje if.
    Jak to obsłużyć szybko we wstawce asm-to może ktoś mądrzejszy się wypowie.

    Dodano po 8 [minuty]:

    O, już się wypowiedział.
    Pewnie ISR_NAKED to jest "nie odkładaj na stos".
    Ale jednak wchodzi w przerwanie-pewnie będzie dłużej.
    Dr.Vee-a jak szybko "załatwić" ten if?

    Dodano po 23 [minuty]:

    Ale może wstaw kwarc 16MHz.
    Może wtedy ten oscyloskop na PC tego nie wychwyci:D
    Czego oczy nie widzą-tego sercu nie żal.
    Ale zawsze zadra-opóźnienie jakieś będzie.

    Dodano po 48 [minuty]:

    Nie-zostaw 1MHz-można coś zobaczyć.
    To jest "grzebanie w bebechach"-to lubię.
    Ciekawe do jakiego opóźnienia da się zejść?
  • VIP Zasłużony dla elektroda
    W standardowej konfiguracji avr-gcc skok do przerwania zajmuje 4+2 cykle, ew. więcej gdy przerwanie nadchodzi "w środku" instrukcji trwającej więcej niż 1 cykl. Powrót z przerwania to 4 cykle.

    To prawda, możesz w pętli testować bit INT0 w rejestrze GIFR, daje to test co 3 cykle zegarowe (sbis + rjmp). Ale równie dobrze możesz testować stan na pinie zewnętrznym i wyjdzie na to samo.

    Pokaż cały kod bo tak to "strzelanie w ciemno".

    janbernat - flagi przerwanaia zeruje się wpisując jeden po to, żeby uniknąć hazardu - odczytujesz flagi, modyfikujesz, zapisujesz - w tym cyklu może zostać ustawiona inna flaga, którą przypadkowo wyzerujesz = "gubisz" przerwanie.

    Pozdrawiam,
    Dr.Vee
  • Poziom 38  
    No tak:
    Dr.Vee:
    "4+2 cykle, ew. więcej gdy przerwanie nadchodzi "w środku" instrukcji trwającej więcej niż 1 cykl. Powrót z przerwania to 4 cykle."
    10+ cykli.
    wilk125 miał 28 cykli.

    "bit INT0 w rejestrze GIFR, daje to test co 3 cykle zegarowe (sbis + rjmp). Ale równie dobrze możesz testować stan na pinie zewnętrznym i wyjdzie na to samo. "
    Fakt, też rozwiązanie-równie szybkie.
    To podejrzewałem:
    "janbernat - flagi przerwania zeruje się wpisując jeden po to, żeby uniknąć hazardu - odczytujesz flagi, modyfikujesz, zapisujesz - w tym cyklu może zostać ustawiona inna flaga, którą przypadkowo wyzerujesz = "gubisz" przerwanie."
    -ale nie znalazłem odpowiedzi.
    O hazardzie w układach uczyłem się 30 lat temu-dzięki za przypomnienie.
    "Pisać programów to ja jeszcze nie umiem. "
    -jak napisałem.
    Ale ciekawy jestem do ilu us da się zejść.

    Dodano po 3 [minuty]:

    W zasadzie po co-rozumiem.
    Ale jak-wpisać 1 do 1 ?
  • Poziom 23  
    krotki opis proramu, po wykryciu przerwania pierwszy raz na INT0 uruchamia timer i odlicza czas do drugiego przerwania, po drugim przerwaniu i kolejnych na PA2 jest wystawiany impuls trwajacy 200us, impuls jest opoznany w stosunku do sygnalu wejsciowego w zaleznosci od okresu sygnalu. Problemem okazalo sie dodatkowe opoznienie wprowadzone przez obsluge przerwania.

    /* ATmega 1MHz */

    #define F_CPU 1000000L
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>


    #define FOSC 1000000// Clock Speed
    #define BAUD 9600
    #define MYUBRR FOSC/8/BAUD-1

    #define cbi(sfr, b) (sfr &= ~(1<<b)) // bit 0 na pin portu
    #define sbi(sfr, b) (sfr |= (1<<b)) // bit 1 na pin portu

    volatile unsigned char recive=0,ex_int=0,flaga=0;


    SIGNAL (SIG_OVERFLOW1) //timer1
    {
    //PORTC = ~led++; // wyświetl na LED-ach
    //TCNT1 = 0x0000; // przeładuj timer 1
    //USART_Transmit('P');
    //flaga=0; // po pzepenieniu
    }

    SIGNAL(SIG_UART_RECV)// przerwanie od USART odebranie znaku
    {
    recive=UDR;

    }

    SIGNAL (SIG_INTERRUPT0)
    {
    ex_int=1;
    }


    int main(void)
    {


    uint16_t okres;

    /* Wszystkie linie portu C będą wyjściami */
    DDRC = 0xFF; /* 0xFF binarnie 1111 1111 */
    PORTC =0xff; // wszytskie linie portu podciagniete do vcc

    DDRD = 0xfB;
    PORTD = 0xFB; //podciagniecie do vcc

    DDRB = 0xfE; //PB0 jako wejscie
    PORTB=0xFe; //PB0 bit bez podciagniecia vcc
    //przetwornik
    DDRA = 0x1e; //PA7 PA6 PA5 i PA0(ADC) jako wejscia

    PORTA=0xFe; // PA0 bit bez podciagniecia vcc

    ADMUX|=_BV(REFS0);; //napiecie zasilania z kondensatorem

    // Wybranie sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
    ADMUX |= _BV(ADLAR);

    // Zezwolenie na konwersję
    ADCSRA |= _BV(ADEN);

    ADCSRA |= _BV(ADPS0); //przez 8 dzielenie
    ADCSRA |= _BV(ADPS1);

    //Timer1
    TIMSK = _BV(TOIE1); // włącz obsługę przerwań T/C1
    TCCR1A= 0x00; //tryb normal bez compare
    //TCCR1B= _BV(CS11)|_BV(CS10); //preskaler 64
    //OCR0 = 0x128; //wartos porownywania z licznikiem
    //exter interupt
    sbi(MCUCR,ISC00);//narastajace zbocze
    sbi(MCUCR,ISC01);// narastajace zbocze
    //MCUCR=MCUCR | (1<ISC00);
    GICR|= _BV(INT0);

    USART_Init ( MYUBRR );
    sei(); //właczenie przerwan
    //USART_Transmit(0x0D); //nastepna linia
    //USART_Transmit(0x0A);//powrót karetki
    //unsigned char tab[]={'A','B','C','D',0x0};
    //USART_Send_String("ATMEGA 16 WITA");

    /* Początek nieskończonej pętli */
    while(1)
    {



    if (ex_int)
    {



    if (flaga==1)
    {

    okres=TCNT1;
    TCNT1=0x00;
    _delay_us(okres);
    sbi(PORTA,PA2);
    _delay_us(200);
    cbi(PORTA,PA2);


    }
    else
    {
    TCNT1=0x00;
    TCCR1B= _BV(CS11);//|_BV(CS10); //start timer preskaler 8
    flaga=1;
    }

    ex_int=0;
    }


    }

    }

    mogłbym jescze odtac opis tego

    __asm__ __volatile__ (
    "inc %0" :
    "=r" (flaga) : "0" (flaga));

    wiem co to robi ale nie wiem dlaczego, co oznaczaja cudzysłowy, dwukropek ?
  • Pomocny post
    VIP Zasłużony dla elektroda
    Po 1) użyj znaczników [code]...
    Po 2) funkcje inline _delay_us i _delay_ms muszą być wywoływane z argumentami o wartości znanej w trakcie kompilacji (stałe) - było o tym wielokrotnie na forum. Dokumentacja.
    Po 3) co do inline asm to zobacz dokumentację.

    Do pomiaru okresu możesz użyć input capture Timera1, masz dzięki temu dokładny pomiar. Po drugim przerwaniu ICR zapisujesz sobie różnicę i obliczasz opóźnienie.

    Do zmiennego opóźnienia możesz skorzystać z output compare timera1. Jeśli możesz, to podłącz wyjście sygnału do pinu OC1x - dzięki temu po odmierzeniu czasu możesz ustawić/wyzerować wyjście OC1x.

    Napisz jeszcze dokładnie co chcesz zrobić (co to za sygnał wejściowy/wyjściowy).

    Pozdrawiam,
    Dr.Vee
  • Poziom 38  
    Masz jakąś starą wersję avrgcc jeśli stosujesz "SIGNAL (SIG_INTERRUPT0)"
    Dr.Vee używa "ISR(INT0_vect)".
    Kod który przesłałeś jest przed zmianami-tak sądzę.
    Teraz usuń SIGNAL (SIG_INTERRUPT0)
    {
    ex_int=1;
    }
    a zamiast:
    if (ex_int) w pętli daj:

    if (INTF0)
    {
    INTF0=1

    itd...

    Dodano po 5 [minuty]:

    Ciekawe czy będzie lepiej.
    Ale to co napisałem-sprawdź-nie znam C i nie potrafię programować.
  • Poziom 23  
    Dr.Vee napisał:

    Po 1) użyj znaczników [code]...

    Co to za znacznik i do czego mam go użyć?

    Dr.Vee napisał:

    Po 2) funkcje inline _delay_us i _delay_ms muszą być wywoływane z argumentami


    wlasnie zauwazylem, ze jak kompiluje bez podania stalej wartosci to kod programu rosnie o okolo 1KB w porownaniu z wywolaniem ze stala wartoscia.



    Dr.Vee napisał:

    Napisz jeszcze dokładnie co chcesz zrobić (co to za sygnał wejściowy/wyjściowy).


    narazie dla testów to sygnal wejsciowy pobieram z generatora sygnalu prostakatnego ale docelowo ma ty być sygnal od impulsatora w motocyklu, poprpstu chce zrobić moduł zapłonowy z mapą zapłonu, zatem czestotliwośc sygnalu wejsciowego bedzie w granicach od 15Hz do okolo 150 Hz, sygnal wyjsciowy z ta sama czestotliwościa tylko, że ze zmiennym opóźnieniem, dla niskich obrotów większe opóznienie dla wyższych oprotów mnijsze.Opóżnienie bedzie sie zawierać w zakresie mniej wiecej od 5ms do 0 z rozdzielczoscia okolo 50 us, dlatego jak dosatlem takie opoznienie w wyniku obróbki przerwania to mnie to trochę zmartwiło, chociaz przy zastosowaniu obslugi przerwania jak wyżej podałeś do obsluga skraca sie o okolo 18 us.
    Generalnie to chyba zaczne odmierczacz okres i opoznieine zgodnie z twoimi wskjazówkami, ale jeszce chcialem zapytać bo pisałeś,że "W standardowej konfiguracji avr-gcc skok do przerwania zajmuje 4+2 cykle", a jest jakas niestandardowa konfiguracja,żebyzmniejszyc ilośc cykli?

    Dodano po 8 [minuty]:

    janbernat napisał:
    Masz jakąś starą wersję avrgcc jeśli stosujesz "SIGNAL (SIG_INTERRUPT0)"
    Dr.Vee używa "ISR(INT0_vect)".



    wersje mam nowa tylko nie wiedzialem, że jest cos takiego jak ISR()
    , wrzucilem ja do siebie i dziala obsluga przerwania zajmuje mniej bo nic na stos nie popycha

    janbernat napisał:

    if (INTF0)
    {
    INTF0=1

    sprawdzanie flagi to tez niezłuy pomysl, nie trace czasu na obsluge przerwania, tylko mam pytanie czy ta flaga sie ustawi nawet jak nie ustawie bitu INTO w GICR, bo tylo wtedy nie wskoczy do obslugi przerwania. Czy moze nie wskoczy wtedy gdzy nie umieszcze funkcji do jej obslugi, a INTO w GICR musze ustawic zeby flaga INTF0 sie ustawila, a wsumie to sobie to sprawdze w AVRstudio tylko dzis juz nie mam kiedy
  • Poziom 38  
    Flaga się ustawia zawsze.
    Nawet gdy nie jest obsłużona-to sterczy na maszcie.
    Znacznik [code]...tu program... [code/] służy do wklejenia programu-żeby odróżnić go od zwykłego tekstu.
  • VIP Zasłużony dla elektroda
    wilk125 napisał:
    zatem czestotliwośc sygnalu wejsciowego bedzie w granicach od 15Hz do okolo 150 Hz, sygnal wyjsciowy z ta sama czestotliwościa tylko, że ze zmiennym opóźnieniem, dla niskich obrotów większe opóznienie dla wyższych oprotów mnijsze.Opóżnienie bedzie sie zawierać w zakresie mniej wiecej od 5ms do 0 z rozdzielczoscia okolo 50 us, dlatego jak dosatlem takie opoznienie w wyniku obróbki przerwania to mnie to trochę zmartwiło, chociaz przy zastosowaniu obslugi przerwania jak wyżej podałeś do obsluga skraca sie o okolo 18 us.

    No to wszystko jasne. Opóźnienia = 0 nie uzyskasz softwareowo. Możesz za to dać zewnętrzny multiplekser - 1 wejście od impulsatora, drugie wejście od procesora - w ten sposób masz opcję "ominięcia" procesora = 0 opóźnienia.

    Co do opóźniania sygnału to spróbuj tak:
    Code:

    /* ewentualnie dla przyspieszenia: register uint16_t poprzedni_capture asm ("r2"); */
    volatile uint16_t poprzedni_capture;

    /*
     * Założenia:
     *  - przerwanie zdąży się wykonać w połowie okresu sygnału
     *  - maksymalne opóźnienie jest mniejsze od połowy okresu sygnału
     * Konfiguracja:
     *  - sygnał wejściowy podany na pin ICP timera1
     *  - sygnał wyjściowy na pinie OC1A timera1
     *  - timer1 w trybie free running
     *  - COM1A ustawione na toggle on output compare
     *  - input capture na obu zboczach
     *  - włączone przerwanie input capture
     *  - może być noise canceller, +ew. korekta przy obliczaniu OCR1A.
     */

    ISR(TIMER1_CAPT_vect)
    {
        uint16_t capture = ICR1;
        uint16_t pol_okresu = capture - poprzedni_capture;
        OCR1A = capture + jakas_funkcja_lub_lookup_w_tablicy(pol_okresu);
        poprzedni_capture = ICR1;
    }


    wilk125 napisał:
    "W standardowej konfiguracji avr-gcc skok do przerwania zajmuje 4+2 cykle", a jest jakas niestandardowa konfiguracja,żebyzmniejszyc ilośc cykli?

    4 cykle zajmuje skok pod adres wektora obsługi przerwania i zachowanie adresu powrotu (4 cykle). Pod adresem wektora znajduje się instrukcja skoku do właściwej procedury obsługi (2 cykle). Jeśli umieścisz procedurę obsługi bezpośrednio pod adresem danego wektora, to eliminujesz 2 cykle, ale za to część przerwań (zależy od rozmiarów procedury) staje się niedostępna.

    wilk125 napisał:
    tylko mam pytanie czy ta flaga sie ustawi nawet jak nie ustawie bitu INT0 w GICR

    Tak.

    Pozdrawiam,
    Dr.Vee
  • Poziom 38  
    poza tym -jak Dr.Vee napisał-bardziej sprzętowo myśl.
    "możesz użyć input capture Timera1, masz dzięki temu dokładny pomiar. Po drugim przerwaniu ICR zapisujesz sobie różnicę i obliczasz opóźnienie."

    Dodano po 4 [minuty]:

    Jeszcze trochę i Dr.Vee nauczy mnie C.
  • Poziom 23  
    Dr.Vee napisał:
    [code]

    * - input capture na obu zboczach


    To raczej odpada, znaczy sie odpada zbocze opadajace, bo o ile teraz mam sygnal prostokontny, to w prawdziwym przypadku (sygnal z impulsatora), bede mial jedynie krótkie impulsy, których czas trwania ni jak bedzie sie mial do okresu mniej wiecej soś takiego ____|____|_____|____|_____, w sumie powinno być prosciel bo czas trwania impulsu sygnalu wyjsciowego moge ustawić na sztywno na kilka czy kilkadziesiat us, ten impuls bedzie tylko zalaczal tyrystor(BT151 potrzebuje 2us na zalaczenie).Ważny jest pomiar okresu miedzy dwoma impulsami(narastajacymi zboczami), oraz wprowadzenie zmiennego opoznienia dla takiego impulsu.
    Zastanawiam sie czy dam rade przy pomocy tylko Timer 1 zmierzyć okres i wprowadzic opoźnienie, ponieważ opoznienie nie bedzie sie zmieniac liniowo w zależnośi od okresu.


    To zmienne opoznienie chcial bym jakos stablocowac i pozniej w zaleznosi od zmierzonego okresu pobierac ta wartosć, chodzi o to zebym mogł sobie wgrywać rózne mapy zapłonu, np.
    1 Mapa zaplonu
    okres [ms] opoznienie[ms]
    10 -------------- 0,1
    12 -------------- 0,7
    15 -------------- 1
    20 -------------- 2,3
    30 -------------- 4,2

    2 Mapa zaplonu
    okres [ms] opoznienie[ms]
    10 -------------- 0,2
    12 -------------- 1,3
    15 -------------- 2,1
    20 -------------- 2,9
    30 -------------- 4,8

    podalem tylko kilka punktow, oczywiscie bylo by ich wiecj np 100

    wybor mapy wybieral bym jakis przelacznikiem
  • VIP Zasłużony dla elektroda
    Ok, w takim razie input capture na odpowiednim zboczu i pomiar okresu.
    Dodatkowo aktywne przerwanie/test bitu OCF1A i modyfikacja OCR1A o obliczoną stałą - raz dodajesz opóźnienie, raz szerokość impulsu.

    Pozdrawiam,
    Dr.Vee
  • Poziom 38  
    Tak mi przyszło do głowy że to motocykl a nie radio.
    Jak zwiększysz częstotliwość kwarcu do 16MHz to przy opóźnieniu 50us/16 w przerwaniu będziesz miał przy 6000obr/min błąd 0.1125stopnia kąta zapłonu.
    Tak wyszło mi z obliczeń-sprawdź.
    Jak zmienisz obsługę przerwania-albo program jak Dr.Vee podał-odpowiednio mniejszy błąd-nawet ok. 0.01stopnia.
  • Poziom 23  
    walcze narazie z asemblerem i mam problem przy zapisie jak poniżej przy właczonej optymalizacji nie ustawia mi r16(flaga) na wartosc 0x50, dlaczego? Jak wylacze optymalizację to wpisuje. Myslalem ze optymalizacja ma optymalizowac program a nie go zmieniać

    Code:

    register uint8_t flaga asm("r16");

    ISR(TIMER1_COMPA_vect,ISR_NAKED) //ISR_NAKED brak zapis na stos
    {
     

    flaga=0x50;
    __asm__ __volatile__("out %1, %0" : "=r" (flaga) : "I" (_SFR_IO_ADDR(PORTD)) );
        reti();
    }
  • Poziom 23  
    udało mi sie uzyskac minimalne opoznienie okolo 18us bez przerwan i 22 z przerwaniami. zmiana opoznienia o 1us lub co 8us jak zastosuje preskaler 8, mysle ze dla zapłonu spokojnie wystarczy.