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

[AVR][C] - dekoder IR Sony - wyjaśnienie

mirekk36 21 Paź 2008 10:09 1893 4
REKLAMA
  • #1 5653098
    mirekk36
    Poziom 42  
    Witam,

    Zrobiłem prosty układzik, przerobiłem prosty programik ze stronki http://www.microsyl.com/ ( i zakładka Mod Lamp ) do dekodowania sygnałów IR z pilota Sony, na swoje potrzeby. Sposób ten wykorzytuje wejście ICP procesora (u mnie Atmega8) oraz Timer1. Jak widać program przerobiłem dosyć mocno ;) i najważniejsze , że przepięknie działa. Jednak męczy mnie to, że nie mogę zrozumieć zasady działania jego jednego małego fragmentu - dotyczącego obliczania długości impulsu (zmienna PulseWidth)

    dokładniej mówiąc tego fragmentu:

      PulseWidth = ICR1 - LastCapture;
      LastCapture = ICR1;


    poniżej cały kodzik:
    (częstotliwość taktowania procka tutaj to 8MHz, preskaler = 8 dzięki czemu jedno "tiknięcie" Timera1 = 1us. W związku z tym wartość w ICR1 to już dokładna równowartość długości sygnału w us)
    // ir_decode.c
    #define IR_PORT B
    #define IR_PIN 0
    #define IR_IN (1<<IR_PIN)
    
    volatile uint16_t LatchedIrData;
    volatile uint8_t address;
    volatile uint8_t command;
    volatile uint8_t Ir_key_press_flag = 0;
    
    void ir_init()
    {
    	DDR(IR_PORT) RESET IR_IN;		// pin jako wejście
    	PORT(IR_PORT) SET IR_IN;		// podciągnięcie pinu do VCC
      	TCCR1B SET (1<<CS11);         	// Timer1 / 8
      	TCCR1B SET(1<<ICES1);         	// Zbocze narastające na ICP
      	TIMSK SET (1<<TICIE1);        	// Przerwanie od ICP
    } 
    
    
    SIGNAL(SIG_INPUT_CAPTURE1)
    {
      static uint16_t LastCapture;
      uint16_t PulseWidth;
      static uint8_t IrPulseCount;
      static uint16_t IrData;
    
      PulseWidth = ICR1 - LastCapture;
      LastCapture = ICR1;
    
    if (PulseWidth > 1984)
      {  // jeśli impuls dłuższy niż czas trwania JEDYNKI to reset wskaźników
        IrPulseCount = 0;
        IrData = 0;
      }
      else
      {
        IrData = IrData >> 1;
        if (PulseWidth > 1388) IrData = IrData | 0x8000;
        IrPulseCount++;
        if (IrPulseCount == 12)
        {
          LatchedIrData = ((IrData >> 4) & 0b0000000001111111);
    	  command = LatchedIrData;
    	  LatchedIrData = (IrData >> 11);
    	  address = LatchedIrData;
    	  Ir_key_press_flag = 1;
        }
      }
    }


    (przy okazji może się komuś przyda bo naprawdę prosty jak drut i rewelacyjnie działa bo w tle pracy programu głównego ;)

    poniżej jak coś przypomnę jak wygląda przebieg Sony IR aby lepiej było to przeanalizować:
    [AVR][C] - dekoder IR Sony - wyjaśnienie

    jak widać przerwanie jest wywoływane za każdym razem gdy następuje zbocze wzrastające sygnału. Na początku jest obliczana długość trwania każdego impulsu (zera bądź jedynki), impulsy jak widać składają się zawsze z 2 części. i tak

    JEDYNKA to: 600us + 1200us co daje nam 1800us

    ZERO to: 600us + 600us co daje nam 1200us

    gdy impuls trwa dłużej to resetowane są wartości licznika odebranych bitów itp.

    dla mnie główny problem jest taki:

    ponieważ sposób obliczania dł.impulsu jest tak jak podałem wyżej to nie rozumiem jak to się zachowuje gdy np:

    1. wystąpiło przerwanie
    2. wartość ICR1 = 1200us
    3. wartość LastCapture = 1800us

    więc PulseWidth = 1200 - 1800 co nam da chyba ;) 64936 więc poniższy warunek za każdym razem powinien być spełniony
    if (PulseWidth > 1984)
      {
        IrPulseCount = 0;
        IrData = 0;
      }

    i ciągle powinien następować reset - a tak się nie dzieje - więc zastanawiam się co naknociłem w moim powyższym wywodzie i jak to naprawdę działa:

      PulseWidth = ICR1 - LastCapture;
      LastCapture = ICR1;


    tylko to nie daje mi spać bo cała reszta jest dla mnie jasna.

    (z góry dziękuję za pomoc w rozwikładniu mojej zagadki)
  • REKLAMA
  • Pomocny post
    #2 5653242
    szelus
    Poziom 34  
    Ale wartość ICR1 nie równa się 1200us (czy 1800us, czy cokolwiek), tylko wartości licznika czasu zatrzaśniętej w momencie zbocza (a licznik liczy w kółko, od 0 do 65535 i dalej znów od 0). Dopiero różnica bieżącej wartości ICP i poprzedniej (dla poprzedniego zbocza) daje ten czas 1200/1800us pomiędzy zboczami.
  • REKLAMA
  • #3 5653756
    mirekk36
    Poziom 42  
    szelus -> ja tak w uproszczeniu napisałem, że np: ICR = 1200us, ponieważ wyjaśniałem wcześniej iż:

    częstotliwość taktowania to 8MHz
    preskaler = 8

    co powoduje, że każde zwiększenie wartości licznika o 1 odbywa się dokładnie co 1us i w związku z tym liczba jaka jest aktualnie w Timerze1 oraz ta zatrzaśnięta w ICR1 odzwierciedla od razu ile mikrosekund upłynęło od wystąpienia zbocza narastającego. (tzn odległości pomiędzy zboczami oblicza się już wg właśnie wartości ICR1, który zawiera jakby jednostki - mikrosekundy)

    ale i tak bardzo ci dziękuję bo naprowadziłeś mnie na trop, chyba, bo ja jakoś nie wiem dlaczego założyłem sobie , że gdy występuje zbocze narastające to wartość licznika Timer1 przepisywana jest do ICR1 a sam Timer1 jest zerowany. Ale przecież w tym wzykłym trybie pracy licznika Timer1 nie następuje żadne porównanie i Timer1 jak mówisz cały czas biegnie od 0 do 65535 odmierzając jakby 65535us

    przez co staje się zrozumiałe, że aby obliczyć odcinki tego odmierzanego czasu PulseWidth to trzeba wykonać takie działanie ;)
  • REKLAMA
  • Pomocny post
    #4 5654266
    szelus
    Poziom 34  
    Dokładnie o to mi chodziło. Jesteś już kolejną osobą, która sugeruje, że muszę podkręcić jasność wypowiedzi ;)
  • #5 5654383
    mirekk36
    Poziom 42  
    szelus -> nie, nie przyznaję, że to ja byłem bardziej zakręcony i naprawdę dzięki temu że napisałeś to wyjaśnienie n/t działania w tym przypadku Timera1, spowodowało, że dopiero zaskoczyłem o co w tym chodzi. ;) jeszcze raz dzięki
REKLAMA