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.

zliczanie impulsów pic16f84

pikachu1986 25 Mar 2007 20:36 2943 19
  • #1 25 Mar 2007 20:36
    pikachu1986
    Poziom 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

    0 19
  • #2 26 Mar 2007 10:44
    tomixxx
    Poziom 9  

    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

    0
  • #3 26 Mar 2007 18:18
    pikachu1986
    Poziom 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.

    0
  • #4 03 Kwi 2007 01:00
    pikachu1986
    Poziom 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

    0
  • #5 03 Kwi 2007 10:50
    Bigfoot
    Poziom 25  

    A skad mamy wiedziec co robisz nie tak skoro nie zalaczyles nawet listingu?

    BF

    0
  • #6 03 Kwi 2007 13:31
    pikachu1986
    Poziom 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
        }


    }
    }

    0
  • #7 03 Kwi 2007 14:40
    piti___
    Poziom 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

    0
  • #8 03 Kwi 2007 15:38
    pikachu1986
    Poziom 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;
       }

    0
  • Pomocny post
    #9 03 Kwi 2007 16:00
    piti___
    Poziom 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

    0
  • #10 03 Kwi 2007 17:34
    pikachu1986
    Poziom 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
    }

    0
  • #11 03 Kwi 2007 17:45
    piti___
    Poziom 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.

    0
  • #12 03 Kwi 2007 18:27
    pikachu1986
    Poziom 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?

    0
  • #13 03 Kwi 2007 19:06
    piti___
    Poziom 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

    0
  • #14 03 Kwi 2007 22:49
    pikachu1986
    Poziom 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

    0
  • Pomocny post
    #15 04 Kwi 2007 10:29
    Bigfoot
    Poziom 25  

    pikachu1986 napisał:
    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

    0
  • #16 05 Kwi 2007 20:49
    pikachu1986
    Poziom 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

    0
  • Pomocny post
    #17 05 Kwi 2007 22:50
    piti___
    Poziom 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

    0
  • #18 06 Kwi 2007 13:38
    pikachu1986
    Poziom 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??

    0
  • #19 12 Kwi 2007 22:17
    pikachu1986
    Poziom 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ąć??

    0
  Szukaj w 5mln produktów