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

Zliczanie impulsów z czujników w PIC16F84A - jak to zrobić w C?

pikachu1986 25 Mar 2007 20:36 3312 19
REKLAMA
  • #1 3718723
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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
  • REKLAMA
  • #2 3720125
    tomixxx
    Poziom 11  
    Posty: 12
    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
  • REKLAMA
  • #3 3721385
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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 3746742
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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 3747306
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    A skad mamy wiedziec co robisz nie tak skoro nie zalaczyles nawet listingu?

    BF
  • REKLAMA
  • #6 3747759
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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ź
    
    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 3747969
    piti___
    Poziom 23  
    Posty: 623
    Pomógł: 67
    Ocena: 9
    W funkcji
    
    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:
    
    	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 3748150
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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ł)
    
    if ( TMR1IF == 1 ) 
       { 
          if( TMR1IE == 1 ) 
          { 
    
          } 
       TMR1IF = 0; 
       } 
    
  • Pomocny post
    #9 3748234
    piti___
    Poziom 23  
    Posty: 623
    Pomógł: 67
    Ocena: 9
    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:
    
    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 3748552
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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 3748587
    piti___
    Poziom 23  
    Posty: 623
    Pomógł: 67
    Ocena: 9
    
    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 3748704
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    napisałem kod ze sprawdzaniem jakie to przerwanie jednak nie działa
    
    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
    
    void interrupt() {
      cnt++;
      TMR0   = 96;
      INTCON = 0xA0;
    

    dlaczego tak jest?
  • #13 3748768
    piti___
    Poziom 23  
    Posty: 623
    Pomógł: 67
    Ocena: 9
    Jaki kompilator ? wskazujesz kompilatorowi ktora funkcja jest przerwaniem ? np w HT
    
    #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
  • REKLAMA
  • #14 3749388
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    pisze w mikroC for pic , kod zmieniłem na
    
    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
    
    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
  • Pomocny post
    #15 3750765
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    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
  • #16 3756704
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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
    
    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
  • Pomocny post
    #17 3757300
    piti___
    Poziom 23  
    Posty: 623
    Pomógł: 67
    Ocena: 9
    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 3758495
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    Rzeczywiście po wprowadzeniu tych zmian
    
    void interrupt() {
    
      if (INTCON.T0IF) {
        cnt++;
        TMR0 = 96;
        INTCON.T0IF = 0;
      }
      else if (INTCON.RBIF) {
       if (portb.f7==1) obr++;
        INTCON.RBIF = 0;
      }
    }
    

    oraz
    
     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 3781937
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    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ąć??
  • #20 3960591
    pikachu1986
    Poziom 13  
    Posty: 155
    Ocena: 36
    moze temat jest juz stary ale wkoncu udalo mi sie uruchomić moj komputerek zamieszczam kilka zdjec :D
    Załączniki:
    • MVI_0111.AVI (2.69 MB) Musisz być zalogowany, aby pobrać ten załącznik.
    • IMG_0110.JPG (563.73 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • IMG_0109.JPG (810.12 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • IMG_0106.JPG (387.05 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • IMG_0103.JPG (410.6 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • IMG_0102.JPG (554.65 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • IMG_0101.JPG (439.16 KB) Musisz być zalogowany, aby pobrać ten załącznik.

Podsumowanie tematu

✨ Dyskusja dotyczy implementacji zliczania impulsów z dwóch czujników (czujnik obrotów silnika i impulsy drogi) w mikrokontrolerze PIC16F84A programowanym w języku C. Głównym problemem jest jednoczesne zliczanie impulsów i odmierzanie czasu (np. 1 sekundy) do wyświetlania obrotów silnika. Proponowane rozwiązania obejmują wykorzystanie przerwań od timera do odmierzania czasu oraz przerwań od zmiany stanu na porcie B (RB Port Change Interrupt) do zliczania impulsów. W obsłudze przerwań należy sprawdzać źródło przerwania (flagi T0IF, RBIF) i odpowiednio je kasować, aby uniknąć zawieszania się procesora. Wskazano, że piny wejściowe nie powinny pozostawać niepodłączone (wiszące), gdyż powoduje to fałszywe przerwania; zaleca się stosowanie rezystorów podciągających (pull-up). Omówiono także problemy z liczeniem impulsów przy wysokich częstotliwościach, które mogą powodować opóźnienia i zawieszanie się wyświetlacza. Wskazano, że w przerwaniu od portu B należy rozróżniać, który pin wywołał przerwanie, aby zliczać impulsy z dwóch źródeł osobno. Podano przykładowe fragmenty kodu obsługi przerwań, podkreślając konieczność poprawnego kasowania flag przerwań i unikania nadpisywania rejestrów sterujących przerwaniami w niewłaściwym miejscu. Poruszono także kwestie skalowania wyników pomiarów prędkości i problemów z podwójnym zliczaniem impulsów na skutek reakcji na oba zbocza sygnału. Ostatecznie autorowi udało się uruchomić działający program zliczający impulsy i wyświetlający prędkość, jednak z pewnymi zastrzeżeniami dotyczącymi stabilności i poprawności pomiarów przy dłuższym działaniu.
Wygenerowane przez model językowy.
REKLAMA