Atmega328p in merjenje frekvence

programski jeziki in programiranje

Moderator: tilz0R

Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 08 Feb 2017, 19:50

Zdravo,
želim izmeriti frekvenco na pinu PD4 (T0), na katerega pripeljem iz frekvenčnega izvora. Zato uporavbljam Timer0, ki je 8 bitni.
Nastavil sem po spodnjih nastavitvah toda sedaj ne dobivam željenih vrednosti. V bistvu je ideja, da čakam 1s in v tej sekundi štejem
impulze rising edge, število dobljenih je v bistvu dobljena frekvenca.

Koda zgleda tako:
Koda: Izberi vse
unsigned int i = 0;
ISR(TIMER0_OVF_vect){
   i++;
}
void Timer_Init(){   
   TCCR0A=0x00;
   TCCR0B=0x00;   
   OCR0A=0x00;
   OCR0B=0x00;   
   TIMSK0 = 0x04;
   sei();
}
char Timer_Get(){
   
   DDRD = (0 << PIND4);
   char tcnt;
   TIMSK0 = 0x04;
   TCCR0B = 0x07;
   _delay_ms(1000);
   TCCR0B=0x00;   
   TIMSK0 = 0x00;
   tcnt = TCNT0;
   TCNT0 = 0x00;      
   return tcnt;
}
unsigned long int Frequency_GET(){
   unsigned long int freq = 0;
   freq = (int)Timer_Get() + (i * 256);      
   i = 0;
   return freq;
}


Izpisujem si na UART ven dobim kar nekaj vrednosti:
Dobiti bi moral 530kHz dobim pa enkrat 68, drugič 220, tretjič 180, skratka nikoli enako vedno različno, opazil pa sem da so vrednosti vedno do 256.
To da dobim vedno različno je zato ker mi ISR interupt zadrži UART pošiljanje in mi ne pošlje po tisti sekundi ko je izmerilo frekvenco ampak nekje vmes.
Torej vprašanje, kako bi naredil, da bi mi kljub ISR, ki meri owerflow registra, poslalo na UART, vrednost po merjenju?
Ter da bi bila točna.
Uart pošiljanje ter merjenje teče v main while zanki:

Koda: Izberi vse
    while (1)
    {   
      freq = Frequency_GET();
      ltoa(freq, (char *)s_Freq, 10);      
      UARTTransmitS(s_Freq);
      UARTTransmitS("\r\n");
    }

Hvala za nasvete.
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 08 Feb 2017, 20:40

Odgovarjam sam sebi, bil sem nepreviden in sem spregledal ter sem registru TIMSK0 nastavil 3. bit moral pa bi mu 1. Se pozna ko scroolaš gor pa dol med registru, hitro zamenjaš bite.
Nekaj dela. :D
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 09 Feb 2017, 10:35

Še vedno pa dobivam vrednosti reda:
43368
medtem ko imam frekvenco na pinu 530kHz, ima kdo kakšno idejo ?
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a VolkD » 09 Feb 2017, 10:54

Najprej se poskusi rešiti vsakršnega delaya v programu. Potem preveri kaj ti napiše, ke pripelješ frekvenco nižjo od recimo 30kHz. Nato poskusi s tako, ki je nad 32Khz in med 64KHz. Mogoče boš s tem odkril napako.

Potem bi ti pa dal novo idejo kako to narediti. Čakanje 1 s na nov rezultat je malo nerodno. Predlagam, da narediš sledeče :

Counter v katerega šteješ vhodno frekvenco. Ob overflovu sprožiš interupt. V interuptu povečaš nek int za 1.

Timer, ki se proži na 0,1s. Ob vsakem proženju naredi sledeče:
- napolni naslednjo long int spremenljivko iz grupe desetih, ki so v krožnem bufferju. Napolno jo tako, da vzame vrednost za spodnji del vrednopst iz Counter-ja, za zgornji del pa iz zgoraj omenjenega int.
Tako dobiš vsake 0,1 s vedno 10 vrednosti, ki jih sešteješ in pretvoriš v frekvenco. To je delo za main.
Na ta način imaš dobro odzivnost, ki pa jo v prvih 10-tih ciklih plačaš z natančnostjo.
Upam, da sem bil razumljiv.
Dokler bodo ljudje mislili, da živali ne čutijo bolečine, bodo živali čutile, da ljudje ne mislijowww.S5tech.net
Uporabniški avatar
VolkD
Administratorji strani
 
Prispevkov: 22422
Pridružen: 29 Dec 2014, 19:49
Kraj: Kačiče (Divača)
Zahvalil se je: 4111 krat
Prejel zahvalo: 3103 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 09 Feb 2017, 11:22

Hvala za odgovor,
Problem je, da nimam nekega frekvenc generatorja imam le en komparator, ki mi daje ven takšno frekvenco. Bom poskusil mal spremeniti parametre.

Torej če te prav razumem TIM_OVF bi štel overflove in hkrati prožil TCR0B, in če prav razumem je en overflow dolg 0.1s, ne razumem?
Torej zdaj v bistvu ne dobim nič drugega kot 10x manjšo vrednost od frekvence, ki jo merim.

Zdaj sem naredil tako, da Timer1 ki je 16-bitn proži na vsako 0.1 sekundo, nastavim ga tako:
Koda: Izberi vse
void Timer1_Init(){
       ICR1 = 0x5A9;         //set OCRn on 1449 (OCRn = ((F_CPU / Prescaller) * Zeljeni_cas) - 1))      
      // Mode 4, CTC on OCR1A
       TCCR1B |= (1 << WGM12);      
      //Set interrupt on compare match
       TIMSK1 |= (1 << ICIE1);      
      // set prescaler to 256 and starts the timer
       TCCR1B |= (1 << CS12);      
      // enable interrupts
       //sei();          
}


Prožim pa s tem Timer0, ki meri frekvenco:
Koda: Izberi vse
ISR (TIMER1_COMPA_vect)
{   
   // action every 100ms
   if(j < 10){
      TIMSK0 = 0x01;
      TCCR0B = 0x07;
      TCCR0B=0x00;
      TIMSK0 = 0x00;
      j++;
   }else{
      j = 0;    
   }
}


Rezultat na izhodu je 0.

Frekvenco pa dobim s tem:
Koda: Izberi vse
unsigned int Timer_Get(){   
   DDRD = (0 << PIND4);
   int tcnt;
   tcnt = TCNT0;
   TCNT0 = 0x00;      
   return tcnt;
}
unsigned long int Frequency_GET(){
   unsigned long int freq = 0;
   freq = (j * Timer_Get()) + (i * 256);      
   i = 0;
   j = 0;
   return freq;
}
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 09 Feb 2017, 12:17

Ko prožim Timer0 je zgoraj napačna koda sem imel v doložišču in ko sem skopiral nisem bil dovolj pozoren:
Prava je takšna:
Koda: Izberi vse
ISR (TIMER1_COMPA_vect)
{   
   // action every 100ms
   if(j < 10){
      TIMSK0 ^= 0x01;
      TCCR0B ^= 0x07;
      j++;
   }else{
      j = 0;    
   }
}
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 09 Feb 2017, 18:53

Zdaj sem naredil tako da mi timer1 proži na 100ms timer0 ki meri frekvenco na pinu T0.
Toda še vedno ne dobim željenega rezultata.
Program zgleda takole:
Koda: Izberi vse
ISR(TIMER0_OVF_vect){
   i++;
}

ISR (TIMER1_COMPA_vect)
{
   // action every 100ms   
   TIMSK0 ^= 0x01;
   TCCR0B ^= 0x07;
   j++;   
}
void Timer_Init(){   
   TCCR0A=0x00;
   TCCR0B=0x00;   
   OCR0A=0x00;
   OCR0B=0x00;   
   TIMSK0 = 0x01;   
   
}
void Timer1_Init(){
   ICR1 = 0x5A9;         //set OCRn on 1449 (OCRn = ((F_CPU / Prescaller) * Zeljeni_cas) - 1))
   // Mode 4, CTC on OCR1A
   TCCR1B |= (1 << WGM12);
   //Set interrupt on compare match
   TIMSK1 |= (1 << OCIE1A);
   // set prescaler to 256 and starts the timer
   TCCR1B |= (1 << CS12);
   // enable interrupts
   //sei();
   //char s_TIMSK1[16];
   //itoa(TIMSK1, s_TIMSK1, 2);
   //UARTTransmitS(s_TIMSK1);
}
unsigned long int Timer_Get(){   
   DDRD = (0 << PIND4);
   unsigned long int tcnt;
   int k = 0;
   
   vrednosti[j] = TCNT0;
   
   if(j > 10){
      j = 0;      
   }
   
   if(j == 10){      
      for(k = 0; k < 10; k++){
         tcnt += vrednosti[k];      
      }
      j = 0;   
      return tcnt;
   }else{
      return tcnt = 0;
   }   
}
unsigned long int Frequency_GET(){
   unsigned long int freq = 0;
   freq = (Timer_Get()) + (i * 256);      
   i = 0;
   return freq;
}


V main zanki pa:
Koda: Izberi vse
    while (1)
    {         
      ltoa(Frequency_GET(), (char *)s_Freq, 10);      
      UARTTransmitS(s_Freq);
      UARTTransmitS("\r\n");
    }


Prosim za pomoč. Hvala.
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a Kroko » 10 Feb 2017, 17:40

Zaženi timer brez interupta. Timer naj se prosto vrti. Ko dobiš signal si zapomni vrednost timerjevega števca. Ko dobiš naslednji signal odštej od števca prejšnjo vrednost. Dobil si periodo. Vrednost števca si seveda spet zapomniš.

Ko bo števec prišel naokoli bo njegova vrednost manjša od zadnje zapomnjene. To je poseben primer, ki ga ločeno obravnavaš.
http://www.planet-cnc.comKroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 3584
Pridružen: 14 Jan 2015, 11:12
Kraj: Ljubljana
Zahvalil se je: 599 krat
Prejel zahvalo: 1166 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 213

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a gumby » 10 Feb 2017, 18:27

Poglej še timer1 in input capture.
my brain hurts
Uporabniški avatar
gumby
 
Prispevkov: 1910
Pridružen: 14 Jan 2015, 18:49
Kraj: Lendava
Zahvalil se je: 87 krat
Prejel zahvalo: 415 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 49

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a ecobra » 10 Feb 2017, 18:55

Tukaj sem našel primer https://forum.arduino.cc/index.php?topic=324796.0 frekvencmetra z arduinom brez knjižnic. Mogoče si boš lahko kaj pomagal s kodo. Sposodil sem si podobno kodo tukaj: https://github.com/PaulStoffregen/FreqCount za merjenje frekvence do 200Hz.
l.p.
ecobra
 
Prispevkov: 114
Pridružen: 31 Maj 2016, 19:48
Kraj: Radeče
Zahvalil se je: 3 krat
Prejel zahvalo: 34 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 6

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a LiPo » 12 Feb 2017, 09:51

MocnikG je napisal/-a:Izpisujem si na UART ven dobim kar nekaj vrednosti:
Dobiti bi moral 530kHz dobim pa enkrat 68, drugič 220, tretjič 180, skratka nikoli enako vedno različno, opazil pa sem da so vrednosti vedno do 256.
To da dobim vedno različno je zato ker mi ISR interupt zadrži UART pošiljanje in mi ne pošlje po tisti sekundi ko je izmerilo frekvenco ampak nekje vmes.
Torej vprašanje, kako bi naredil, da bi mi kljub ISR, ki meri owerflow registra, poslalo na UART, vrednost po merjenju?
Ter da bi bila točna.
Uart pošiljanje ter merjenje teče v main while zanki:



problem je tukaj,

Imaš frekvenco 530 kHz. se pravi 530000 Hz.
Tvoj timer pa ima max freq 255 Hz.

Uporabi 16 bitni timer in časovno bazo 1 mS ali 10 mS.


LPG
Uporabniški avatar
LiPo
 
Prispevkov: 630
Pridružen: 04 Apr 2015, 16:30
Kraj: LJUBLJANA
Zahvalil se je: 21 krat
Prejel zahvalo: 75 krat
Uporabnika povabil: cimabella
Število neizkoriščenih povabil: 15

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 12 Feb 2017, 20:52

Zakaj ne bi mogel lavfati 8 bitni timer, vrednost je 256, ko to prešteje se register timerja resetira in šteje kot en overflov, v sekundi mora izračunati št. overflow * vrednost zadnjega štetja in boš dobil pravo vrednost.
Hvala za zgornje odgovore, bom preizkusil, res je da sem spregledal da se register s katerim nastavim da šteje 100ms resetira vsakič in ga je potrebno ponastaviti po vsakem štetju. Če prav razumem datasheet.
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a MocnikG » 12 Feb 2017, 20:58

Kroko je napisal/-a:Zaženi timer brez interupta. Timer naj se prosto vrti. Ko dobiš signal si zapomni vrednost timerjevega števca. Ko dobiš naslednji signal odštej od števca prejšnjo vrednost. Dobil si periodo. Vrednost števca si seveda spet zapomniš.

Ko bo števec prišel naokoli bo njegova vrednost manjša od zadnje zapomnjene. To je poseben primer, ki ga ločeno obravnavaš.


Čakaj zdaj ne razumem kateri timer naj se vrti brez interupta?
Kako misliš dobim signal in nato naslednji signal, signal je vedno prisoten na pinu (pravokoten) le frekvenca se mu spreminja.

Moja ideja je nekako bila tudi, toda je ne znam realizirati, da bi dobil interupt ko se edge spremeni, začel timer meriti ter ko pride naslednji edge timer ugasne in izračunaš vrednost periode, 1/Periodo je frekvenca.

Kaj pomeni Pin change interrupt, lahko to obravnam kot interupt, ki se mi bo prožil ob spremembi fronte na signalu?
Uporabniški avatar
MocnikG
 
Prispevkov: 253
Pridružen: 18 Maj 2015, 17:56
Kraj: Koroška - MB - CE
Zahvalil se je: 22 krat
Prejel zahvalo: 20 krat
Uporabnika povabil: s55ei
Število neizkoriščenih povabil: 2

Re: Atmega328p in merjenje frekvence

OdgovorNapisal/-a Kroko » 12 Feb 2017, 21:34

Timer ni nujno da proži interupt. Lahko se prosto vrti, podobno kot sekundni kazalec na uri. Ko se tvoj signal spremeni iz 0 na 1 pogledaš, koliko kaže sekundni kazalec. Ko se ponovno spremeni spet pogledaš in izračunaš periodo. Za to ne rabiš "štoparice" na kateri se sekunde zmeraj štejejo od nič.
http://www.planet-cnc.comKroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 3584
Pridružen: 14 Jan 2015, 11:12
Kraj: Ljubljana
Zahvalil se je: 599 krat
Prejel zahvalo: 1166 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 213


Vrni se na Software

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost

cron