Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[pic16] odbiór RC5 na pic16f84a

mby 25 Maj 2010 12:20 1496 9
  • #1 25 Maj 2010 12:20
    mby
    Poziom 8  

    Witam. Napisałem prosty program który ma odcztywać wszystkie 14(w sumie to zczytuje 28 - odczyt co 889us) bitów tego kodu. Program działa w ten sposów:
    1) z tfmsa dostaje zbocze H-L
    2) czeka 200us zeby stan sie ustalil
    3) odczytuje wartość na pinie i wsadza do tablici received bits
    4) czeka 889us
    5) idzie do 3 lub konczy działanie uaktywniając przerwania zboczem w celu ponowego odczytu kodu.

    Program napisałem w C ale nie działa. Niby prosty...
    Prosze o poprawe. Diabeł jak zwykle pewnie tkwi w szczegółach.

    Code:

    #include <16f84a.h>
    #fuses NOWDT, XT, NOPROTECT
    #define wait1 200
    #define wait2 33

    int1 received_bits[28];
    int8 count;

    void config(void){
       ext_int_edge(H_TO_L); // ext interrupt config
       setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2);  // timer config
       enable_interrupts(INT_EXT); // inable ext interrupt
       enable_interrupts(GLOBAL); // enable global interrupts
    }

    #int_EXT
    void isr_EXT(){
       set_timer0(WAIT1);
       clear_interrupt(INT_TIMER0);
       enable_interrupts(INT_TIMER0);
       disable_interrupts(INT_EXT);
    }

    #int_TIMER0
    void isr_TIMER0(){
       if(count != 28){
          set_timer0(WAIT2);
          received_bits[count] = input(PIN_B0);
          ++count;
       } else {
          count = 0;
          disable_interrupts(INT_TIMER0);
          clear_interrupt(INT_EXT);
          enable_interrupts(INT_EXT);
       }
    }

    int8 convert(int1 *received_bits){
       int8 i;
       int8 temp = 0;
       for(i = 0; i < 4; i++){
          if(received_bits[16+2 * i] == (int1)1)
             temp |= 1 << i;
       }
       return temp;
    }


    void main(void){

    label:
       output_a(convert(received_bits));
       goto label;
       goto label;
    }

    0 9
  • #2 25 Maj 2010 12:34
    utak3r
    Poziom 25  

    mby napisał:
    Program napisałem w C

    [ciach]

    Code:

    void main(void){

    label:
       output_a(convert(received_bits));
       goto label;
       goto label;
    }


    Matko jedyna... co to jest?? :!:

    mby napisał:
    ale nie działa.


    A jak się objawia owo niedziałanie?

    0
  • #3 25 Maj 2010 12:54
    mby
    Poziom 8  

    Mial na czterech pinach poru a wyświetlać kolejne wartości received_bits[16], received_bits[18], received_bits[20], received_bits[22]. Nie wiem czy błąd jest w odbiorze, czy w 'wyświetlaniu wyników'. a ten cytat... to służy temu, żeby przypadkiem gdy przerwanie nadejdzie w nieodpowiednim momencie, program nie doszedł do końca i nie zaczął od początku wszystkiego. Nie wiedzialem jak to zrobić wiec zrobiłem tak. Aha, i w main jest tez wywolane config(). też nie działa. program wygląda tak:

    Code:

    #include <16f84a.h>
    #fuses NOWDT, XT, NOPROTECT
    #define wait1 200
    #define wait2 33
    #use standard_io (a)
    #use standard_io (b)



    int1 received_bits[28];
    int8 count;

    void convert(void){
       output_bit(PIN_A0, (int8)received_bits[16]);
       output_bit(PIN_A1, (int8)received_bits[18]);
       output_bit(PIN_A2, (int8)received_bits[20]);
       output_bit(PIN_A3, (int8)received_bits[22]);
    }


    void config(void){
       ext_int_edge(H_TO_L); // ext interrupt config
       setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2);  // timer config
       enable_interrupts(INT_EXT); // inable ext interrupt
       enable_interrupts(GLOBAL); // enable global interrupts
    }

    #int_EXT
    void isr_EXT(){
       set_timer0(WAIT1);
       clear_interrupt(INT_TIMER0);
       enable_interrupts(INT_TIMER0);
       disable_interrupts(INT_EXT);
    }

    #int_TIMER0
    void isr_TIMER0(){
       if(count != 28){
          set_timer0(WAIT2);
          received_bits[count] = input(PIN_B0);
          ++count;
       } else {
          //count = 0;
          disable_interrupts(INT_TIMER0);
          convert();
          //clear_interrupt(INT_EXT);
          //enable_interrupts(INT_EXT);
       }
    }

    void main(void){
    config();

    label:
       //convert();
       goto label;
       goto label;
    }

    0
  • #4 25 Maj 2010 13:35
    utak3r
    Poziom 25  

    Nie znam tego kompilatora, w którym to pracujesz (używam mikroC, który jest znacznie bardziej przejrzysty), więc trudno mi stwierdzić poprawność konfiguracji przerwań - a zapewne tam tkwi błąd...
    A co do tych labeli... zrób tak:

    Code:

    while (1)
    {
        convert();
    }

    0
  • #5 25 Maj 2010 14:05
    mby
    Poziom 8  

    Ja pisze w kompilatorze firmy CSS. Te kod powyżej działa już mniej wiecej. Problem jest taki, że jak wyświetlam sobie na ledach kolejne bity, np. 20, 21, 22... to wszystkie są na 1. To jest przecież niemozliwe bo mamy kod Manchaster. Błąd jest więc w zczytywaniu. Nie mam pojecia jaki, bo program jest bardzo prosty. Sprawdzałem przerwania zewnetrzne i timera, przy takich właśnie konfiguracjach. Przerwania zewnetrzne, timer i przerwania od niego śmigaja... W dalszym ciagu prosze o pomoc, bo nie mam juz pomysłów.

    0
  • #6 25 Maj 2010 14:18
    utak3r
    Poziom 25  

    A ustawiłeś piny na wejście?
    I - nie pamiętam, czy 16f84 ma komparator - przełączyłeś je na digital? Nigdzie nie widzę konfiguracji portów...

    0
  • #7 25 Maj 2010 14:21
    mby
    Poziom 8  

    W tym kompilatorze jest tak, że gdy użyje sie funkcji input() piny sa automatycznie ustawiane na wejście. Ten model nie ma komparatora.

    0
  • #8 26 Maj 2010 13:42
    sambo123
    Poziom 13  

    void config(void){
    ext_int_edge(H_TO_L); // ext interrupt config
    setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2); // timer config
    enable_interrupts(INT_EXT); // inable ext interrupt
    enable_interrupts(GLOBAL); // enable global interrupts
    }

    brak

    enable_interrupts(int_TIMER0);

    0
  • #9 26 Maj 2010 18:33
    mby
    Poziom 8  

    to przerwanie napewno powinno zostać w tym miejscu właczone? Zrobiłem to w obsłudze przerwania zewnętrzego. Popatrz na algorytm według którego postępuje.

    0
  • #10 01 Cze 2010 00:36
    sambo123
    Poziom 13  

    Code:

    #include <16f877.h>
    #fuses XT,NOWDT,NOPROTECT

    #use delay(clock=4000000)
    #use rs232(baud=2400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

    #use fast_io(a)                           
    #zero_ram

    #define one_min 1450               //no of counts to safely detect bit1
    #define one_max 2200               //optimal @4 MHz is 1800
    #define zero_min 600               //no of counts to safely detect bit0
    #define zero_max 1440               //optimal @4 MHz is 1200


    int16 irframes[14];                  //holds incoming IR data
    int8 ircount =0;                  //counts no if bits received
    int1 irdone=false;                  //flag bit

    #int_timer1                        //(is this isr necessary? I dont really know)
    void timer1_isr()
    {
       disable_interrupts(int_timer1);
    }


    #int_ext                        //IR bits detected by edge triggering
    void ext_isr()
    {
       if(irdone) return;
       irframes[ircount++]=get_timer1();
       if(ircount>=13)                  //if 13 triggers(ie 12 bits+start) found
          irdone=true;               //set "done" flag
       set_timer1(0);                  //restart timer for new bit
       enable_interrupts(int_timer1);      //(is this necessary? I dont really know)
    }


    int1 decode_ir(int8 &addr,int8 &cmd)   //IR decoding function
    {
       int8 i;
       int8 mask;
       int1 bits[12];
       
       addr=0;
       cmd=0;
       
       irframes[13]=1200;               //last bit is always zero
       
       for(i=2;i<=13;i++)
       {
          if((one_min<=irframes[i])&&(irframes[i]<=one_max))
             bits[i-2]=0x01;            //if the sampled signal lies within limits




          else                     //set to 1
          if((zero_min<=irframes[i])&&(irframes[i]<=zero_max))
             bits[i-2]=0x00;            //if the sampled signal lies within limits
          else                     //set to 0
          return false;               //otherwise clear flag
       }
       
       mask=0x01;                     //format command
       for (i=0;i<=6;i++)
       {
          if (bits[i])
          cmd=cmd|mask;
          mask<<=1;
       }
       
       mask=0x01;                     //format address
       for (i=7;i<=11;i++)
       {
          if(bits[i])
          addr=addr|mask;
          mask<<=1;
       }
       
       return true;                  //set flag
    }


    void start_ir()
    {
       ircount=0;
    //   memset(irframes,0x00,sizeof(irframes));
       irdone=false;
    }

    void main()
    {
       int8 addr, cmd;
       int1 ok;
       
       delay_ms(100);                  //setting up PIC
       setup_adc_ports(no_analogs);
       setup_adc(adc_off);
       set_tris_a(0b00000100);
       
       delay_ms(100);
                                  //timer prescaler dependent on oscillator speed
       setup_timer_1(t1_internal|t1_div_by_1);
       ext_int_edge(0,h_to_l);
       enable_interrupts(int_ext);
       enable_interrupts(global);
       
       start_ir();
       while(1)
       {
          if (irdone)
          {
             ok= decode_ir(addr,cmd);
             if(!ok)                  //if bad bits or out of synch, reset processor
                reset_cpu();         //(can I avoid this?)
             else
             {
             printf ("adr:%u kod:%u \n",addr,cmd);

                   switch (cmd)
                      {             
                         case (21)://Remote button "8"
                             {
                               
                               output_toggle(pin_a0);
                               delay_ms(500);
                               break;
                            }
                         case (0x04)://Remote button "5"
                             {

                               break;
                            }
                         case (0x01)://Remote button "2"
                             {

                               break;
                            }
                         default:   //any other button
                            {
                               
                               break;
                            }
                      }
                   
             }
             start_ir();
          }
       }
    }


    Co prawda to jest protokół SONY, ale po pewnych zmianach powinien działać i z RC5.

    0