Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

zliczanie impulsów pic16f84

pikachu1986 25 Mar 2007 20:36 3126 19
  • #1
    pikachu1986
    Level 13  
    witam robie komputerek pokładowy do astry i nie wiem jak zliczać impulsy z dwóch żródeł (czujnik obrotów i impulsy drogi) i jednoczesnie odmierzać czas np 1s. Powiedzmy ze program ma wyświetlać obroty silnika co sekundę ( liczy impulsy w czasie 1 s zapisuje do zmiennej i wyświetla na wyświetlaczu) .W jaki sposób to napisać (programuje w C na 16f84a), czy to ma być w przerwaniach czy moze jakoś inaczej? Prosze o odpowiedzi i sugestie
  • #2
    tomixxx
    Level 10  
    Proponuje włączyć timer ustawić tak żeby przerwanie nadchodziło co sekundę(chociaż nie pamiętam w tym momencie co jaki czas maksymalnie można ustawić przerwanie od timera ) , w przerwaniu odczytać ilość jednych i drugich impulsów, wyświetlić i wyzerować. Nic lepszego nie przychodzi mi do głowy
  • #3
    pikachu1986
    Level 13  
    Troche siedziałem nad tym i nie moge sobie poradzić z napisaniem tego programu. Włączam timer na sekunde i nie wiem w jaki sposób to ma liczyc ( w przerwaniach?) a jezeli podczas wysylania danych do wyświetlacza nastąpi przerwanie? prosze o jakiś przykład w C.
  • #4
    pikachu1986
    Level 13  
    czy naprawde nikt mi nie pomoże:] w dalszym ciągu nie wiem w jaki sposb liczyć te impulsyWłączam timer na 1 sek licze impulsy z jednego pinu ,na wyświetlaczy pokazuje sie wartość i tak góra 5 razy a pózniej procesor sie zawiesza:( co robie nie tak prosze o przykład do zliczania impulsów w C
  • #5
    Bigfoot
    Level 25  
    A skad mamy wiedziec co robisz nie tak skoro nie zalaczyles nawet listingu?

    BF
  • #6
    pikachu1986
    Level 13  
    Przepraszam faktycznie powinienem załączyć kod. Robie zliczanie impulsów z czujnika halla i wyświetlanie na wyświetlaczu tid(opel). Tak na próbe napisałem program który jeżeli na porta.f0 bedzie 0 to zwiększa zmienną obr. Napisałem to tak na próbe żeby sie przekonać czy działa (w moim projekcie sie nie sprawdzi bo jeżeli cały czas bedzie 0 to program cały czas zwiększa zmienną) .Po odpaleniu pokazuje kilka razy wynik i zawiesza sie (nigdy nie działa dłużej niż 10 sek chyba ze nic nie musi liczyć ,zawiesza sie po kilku seriach impulsów). Chce żeby procek liczył impulsy z pinu w czasie 1 sek i wyświetlał na wyświetlaczu.Prosze o jakieś porady jak to napisać, wiem że rozwiązanie jest bardzo proste ale nie moge sobie poradzić. Szukałem jakiegoś gotowca na różnych stronach ale przeważnie są programy na AVR a to ma być na 16f84. Dodaje kawałek kodu ,prosze o odpowiedź
    Code:

    void interrupt() {
      cnt++;
      TMR0   = 96;
      INTCON = 0x20;
       }
    void main () {         //główny program
    trisb=0;
    trisa==255;
    porta==255;


    OPTION_REG = 0x84;
    TMR0  = 96;
      INTCON = 0xA0;           // Enable TMRO interrupt
      cnt = 0;
      obr=0;
    while(1) {
      while (wejscie==0) {
      obr++;
      }
      if (cnt == 400) {

       podziel(obr);
       start();
       startpuls();
       send(0x94);
       startpuls();
       mrq=0;
       startpuls();
       send(0x80);
       send(0x01);

       send(0x98);
       send(0x5e);
       send(0x97);   
       send(0x9b);
       send(0x40);

       z1= table[s];
       send(z1);
       z1= table[d];
       send(z1);
       z1= table[j];
       send(z1);

       stop();

          cnt = 0;
          obr=0;
            // Reset cnt
        }


    }
    }
  • #7
    piti___
    Level 23  
    W funkcji
    Code:

    void interrupt() {
      cnt++;
      TMR0   = 96;
      INTCON = 0x20;
       }

    wylaczasz przerwania GIE = 0 oraz nie kasujesz flagi przerwania timera 0.
    W obsludze przerwania powinienes sprawdzac co wywolalo przerwanie np:
    Code:

       if ( TMR1IF == 1 )
       {
          if( TMR1IE == 1 )
          {

          }
       TMR1IF = 0;
       }


    sprobuj uruchomic "RB Port Change Interrupt" i liczyc w przerwaniu ile bylo zmian na tym porcie

    pozdrawiam
  • #8
    pikachu1986
    Level 13  
    Ponieważ nie jestem jeszcze zbyt dobry w programowaniu prosze o wyrozumiałość :)
    liczenie zmian na porcie byłoby chyba najlepszym rozwiązaniem, tylko nie wiem jak to uruchomić
    Wiem że za tego rodzaju przerwanie jest odpowiedzialny 0 i 3 bit w rejestrze intcon
    -co zrobić żeby odczytywało zmiany tylko na jednym pinie np. portb.f7,
    - czy jeżeli na pinie dłuższy czas bedzie utrzymywał sie stan niski to zmienna zwiększy sie o 1 czy bedzie sie zwiększała cały czas?
    Jezeli chodzi o włączenie GIE to zamiast INTCON = 0x20; dam INTCON = 0xA0; w jaki sposób kasuje sie flage przerwania?

    Nie rozumiem tego (byłbym wdzięczny gdyby ktoś mi to wytłumaczył)
    Code:

    if ( TMR1IF == 1 )
       {
          if( TMR1IE == 1 )
          {

          }
       TMR1IF = 0;
       }
  • Helpful post
    #9
    piti___
    Level 23  
    W PICach rozne przerwania wywoluja jedna funkcje w ktorej musisz sprawdzic zrodlo wywolania przerwania czyli sprawdzic np flage czy timer sie przekrecil lub czy nastapila zmiana na porcie B.
    Powinno to wygladac tak:
    Code:

    void interrupt() {

    if ( T0IF == 1 ) // czy timer sie przekrecil ?
    {
          if( T0IE == 1 ) // czy jest wlaczone przerwanie od timera
          {

          }
       T0IF = 0; // kasuj flage timera 0
    }

    if ( RBIF == 1 ) // czy to przerwanie z portu B ?
    {
          if( RBIE == 1 ) // czy jest wlaczone przerwanie z portu B ?
          {

          }
          RBIF = 0; // kasuj flage przerwania
    }

    }


    PORTB INTERRUPT
    An input change on PORTB<7:4> sets flag bit RBIF
    (INTCON<0>). The interrupt can be enabled/disabled
    by setting/clearing enable bit RBIE (INTCON<3>)

    Jezeli RBIE jest 1 to kazda zmiana (0-1, 1-0) na pinach B<7:4> wywola przerwanie.
    Wlaczenie tego to RBIE = 1;
    Jezeli to bedzie tylko na jednym pinie zmiana to nie musisz sprawdzac w przerwaniu na ktorym tylko zwiekszyc jakis licznik.

    Mysle ze to powinno pomoc

    pozdrawiam
  • #10
    pikachu1986
    Level 13  
    dziękuje za odpowiedź już jakoś sobie poradze (albo będe pytał :))
    mam jeszcze 2 pytania :
    - w jaki sposób to napisać jeżeli bedą 2 żródła impulsów np. impuls na portb.f7 zwiększa zmienną a ,natomiast impuls na portb.f6 zwiększa zmienną b ?
    - if ( RBIF == 1 ) // czy to przerwanie z portu B ?
    {
    if( RBIE == 1 ) // czy jest wlaczone przerwanie z portu B ?
    {
    // co tu powinno być? instrukcja zwiększająca zmienną?
    }
    RBIF = 0; // kasuj flage przerwania
    }
  • #11
    piti___
    Level 23  
    Code:

    if ( RBIF == 1 ) // czy to przerwanie z portu B ?
    {
          if( RBIE == 1 ) // czy jest wlaczone przerwanie z portu B ?
          {
    // w zaleznosci czy to zmiana z 0-1 trzeba to odwrotnie zrobic

    if (pin1 == 1)
    cnt1++;


          }
          RBIF = 0; // kasuj flage przerwania
    }


    z 2 zrodel to juz musisz sie sam zastanowic czy to sie da i jak to zrobic
    jesli dodasz
    if (pin2 == 1)
    cnt2++;
    moze sie zdazyc ze policzy wiecej impulsow niz bylo w rzeczywistosci, najlepiej liczyc na przemian, raz z jednego zrodla raz z drugiego zrodla.
  • #12
    pikachu1986
    Level 13  
    napisałem kod ze sprawdzaniem jakie to przerwanie jednak nie działa
    Code:

    void interrupt() {

      TMR0   = 96;
      INTCON = 0xA0;
      if ( T0IF == 1 ) // czy timer sie przekrecil ?
    {
          if( T0IE == 1 ) // czy jest wlaczone przerwanie od timera
          {
          cnt++;
          }
          T0IF== 0; // kasuj flage timera 0
    }
    }

    natomiast to działa bez problemu
    Code:

    void interrupt() {
      cnt++;
      TMR0   = 96;
      INTCON = 0xA0;

    dlaczego tak jest?
  • #13
    piti___
    Level 23  
    Jaki kompilator ? wskazujesz kompilatorowi ktora funkcja jest przerwaniem ? np w HT
    Code:

    #pragma interrupt_level 1
    void interrupt isr(void)
    {

    }


    Nie dziala rowniez dlatego ze kasujesz flage przerwania
    INTCON = 0xA0;
    przed instrukcja
    if ( T0IF == 1 )

    INTCON = 0xA0; ta linia nie jest potrzebna
  • #14
    pikachu1986
    Level 13  
    pisze w mikroC for pic , kod zmieniłem na
    Code:

    void interrupt() {

      TMR0   = 96;
       if ( T0IF == 1 ) // czy timer sie przekrecil ?
    {
          if( T0IE == 1 ) // czy jest wlaczone przerwanie od timera
          {
          cnt++;
          }
          T0IF== 0; // kasuj flage timera 0
    }
    }


    i niestety też nie działa

    Dodano po 32 [minuty]:

    znalazłem gotowy kod
    Code:

    void interrupt() {

      if (INTCON.T0IF) {
        cnt++;
        TMR0 = 96;
        INTCON.T0IF = 0;
      }
      else if (INTCON.RBIF) {
        cnt1++;
        TMR0 = 96;
        INTCON.RBIF = 0;
      }
    }

    działa jednak często sie zawiesza, teraz walcze z przerwaniem z portb

    Dodano po 45 [minuty]:

    jak zostawie pin nie podłączony do niczego (wisi) to liczy mi przerwania z pinu (30 nawet do 500) czy to normalne?? jak podłącze +5v i zmieniam na GDN to jest ok
  • Helpful post
    #15
    Bigfoot
    Level 25  
    pikachu1986 wrote:
    jak zostawie pin nie podłączony do niczego (wisi) to liczy mi przerwania z pinu (30 nawet do 500) czy to normalne?? jak podłącze +5v i zmieniam na GDN to jest ok


    Tak, to normalne choc nie powinienes tak zostawiac pinu wiszacego w powietrzu. Powinienes podpiac go pull-upem (powiedzmy 10k) do +5V - wtedy problem zniknie.

    BF
  • #16
    pikachu1986
    Level 13  
    Witam napisałem programik który zlicza impulsy pochodzące z czujnika prędkości (chciałem sprawdzić ile impulsów przypada na 1 obr kola). Wszystko działa pokazuje 30 imp /obr wynik zmienia sie co 1 sek. Problem pojawił sie kiedy koło zaczeło sie obracać z większą prędkością, wyniki zaczeły sie zmieniać coraz wolniej, aż w końcu wyświetlacz przestał wyświetlać, myślałem że procek sie zawiesił ale kiedy koło zwolniło wszystko wróciło do normy. Co może być przyczyną tego ze przy większej częstotliwości impulsów procesor nie daje rady?
    załączam część programu
    Code:

    void interrupt() {

      if (INTCON.T0IF) {
        cnt++;
        TMR0 = 96;
        INTCON.T0IF = 0;
      }
      else if (INTCON.RBIF) {
       if (portb.f7==1) obr++;
        TMR0 = 96;
        INTCON.RBIF = 0;
      }
    }
     //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    void main () {         //główny program
    trisb=128;
    trisa==255;
    porta==255;


    OPTION_REG = 0x84;
    TMR0  = 96;
      INTCON = 0xA8;           // Enable TMRO interrupt
      cnt = 0;
      obr=0;
    while(1) {

      if (cnt == 400) {

       podziel(obr);
       start();
       startpuls();
       send(0x94);
       startpuls();
       mrq=0;
       startpuls();
       send(0x01);
       send(0x01);


       send(0x97);
       send(0x9b);    //l/km
       send(0x5e);
       send(0x91);
       send(0x40);
       z1= table[s];
       send(z1);
       z1= table[d];
       send(z1);
       z1= table[j];
       send(z1);

       stop();
       cnt = 0;

            // Reset cnt
        }


    }
    }

    Prosze o jakąś rade
  • Helpful post
    #17
    piti___
    Level 23  
    Dlaczego w przerwaniu RBIF ustawiasz licznik ?

    Zmien if (cnt == 400) na if (cnt >= 400)
    mozliwe ze ten warunek przy wielu przerwaniach "nie trafial" dokladnie w 400 ale przeskakiwal i zliczal do 64k
  • #18
    pikachu1986
    Level 13  
    Rzeczywiście po wprowadzeniu tych zmian
    Code:

    void interrupt() {

      if (INTCON.T0IF) {
        cnt++;
        TMR0 = 96;
        INTCON.T0IF = 0;
      }
      else if (INTCON.RBIF) {
       if (portb.f7==1) obr++;
        INTCON.RBIF = 0;
      }
    }

    oraz
    Code:

     if (cnt >= 400)

    wszystko działa poprawnie:) jeszcze raz dzięki za pomoc

    Dodano po 2 [godziny] 39 [minuty]:

    Mam kolejny problem ale tym razem z obliczeniami. Chciałem żeby procek obliczał prędkość i odświeżał wynik co 1 sek. A więc zmierzyłem obwód koła (175 cm), na 1 obr koła 30 impulsów czyli na 1 m ok 17 impulsów. Na początek chciałem liczyć w m/s czyli ilość impulsów które były w danej sekundzie dziele przez 17 żeby wiedzieć ile metrów przebył samochód . Wynik powiniem wyjść w m\s ale na wyświetlaczu wynik jest identyczny jak na prędkościomierzu czyli w km\h i to w całym zakresie prędkości (a przecież km\h i m\s to nie ta sama wartość ). Nie wiem dlaczego tak jest (chyba nie uważałem na fizyce :D ) Gdzie jest błąd??
  • #19
    pikachu1986
    Level 13  
    Wracam do tematu ponieważ jest jeszcze cos czego nie rozumiem , mianowicie wszystko działa bez zarzutu ,predkość wyskalowałem pokazuje rzeczywiste wartości ale jezeli procek pochodzi troche ok 20 minut to po wyłączeniu i ponownym włączeniu zaczyna pokazywać dokładnie 2 razy wieksze wyniki. Nie zawsze tak sie dzieje ale nieraz musze czekać z 5 minut i wszystko wraca do normy. Podejrzewam ze to wina czujnika prędkości (czujnik daje impulsy masy), albo procesor zaczyna reagować na oba zbocza rosnące i opadające .Jak tego uniknąć??