Stránka 1 z 2

prerušenie analógového komparátoru attiny2313

Napsal: 06 úno 2011, 22:50
od iginoiii
Dobrý deň, po čase som sa rozhodol si spraviť aj digitálny otáčkomer práve s uvedeným procesorom a výstupom na LCD. Problém mám so vstupom do komparátoru procesoru, ak dám na vstup sínusovku menej ako približne 25Hz, začne ukazovať hlúposti(pri vstupe hranatého signálu je všetko OK). Je to problém strmosti hrán, pri pomalom prechode signálu v okolí vnútornej referencie komparátoru(1.1V), nastane v rýchlom slede viac prerušení za sebou. Dá sa tento problém nejak elegantne ošetriť? Alebo mám smolu, a budem musieť upravovať signál ďalším komparátorom, pred vstupom do komparátoru procesoru?

približne od 25Hz+ už tento problém úplne zmizne a po empirickom donastavovaní konštánt :D meriam s presnosťou max 1 percenta(pri vysokých frekvenciách).

ps: je mi jasné, že pri vyhodnocovaní každých prib. 500ms(4 000 000/(2*976*1024)) nemôžem namerať frekvenciu 1.7Hz, ale ozaj pri 10Hz sinus mi to lieta od 15 do 30Hz...

Kód: Vybrat vše

#define F_CPU 4000000UL // 4 MHZ rychlost uPC

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd.h"

signed int pocet_otacok;
//signed int cas_merania;
signed int otacky;


void nast_komp(void)
{
DIDR |= _BV(AIN1D)| _BV(AIN0D);
ACSR |= _BV(ACBG)| _BV(ACIE)| _BV(ACIE)| _BV(ACIS1)| _BV(ACIS0);
}

void casovac1(void)
{
TCCR1A |= _BV(WGM11)| _BV(WGM10); // 1024 prescaller
TCCR1B |= _BV(CS12)| _BV(CS10)| _BV(WGM13); // 1024 prescaller

TIMSK |= _BV(TOIE1); // 1024 prescaller
OCR1A=976;
}


void main()
{
sei();   // Enable Global Interrupts 
casovac1();
nast_komp();


InitLCD(LS_NONE);
   LCDClear();
   //Some more text

   LCDWriteString("pocet otacok:");

for(;;) // Loop Forever
   {
   LCDWriteIntXY(2,1,otacky,5);
_delay_ms(500);
   }
}

ISR(ANA_COMP_vect)
{
pocet_otacok=(pocet_otacok+1);
//_delay_us(10);
}

// otacky za urcity cas, meram pol sekundy, takze 2Hz
ISR(TIMER1_OVF_vect)
{
otacky=(2*pocet_otacok+pocet_otacok/12);
pocet_otacok=0;
}

Napsal: 06 úno 2011, 23:08
od Crifodo
když bude po prvním přerušení zakázáno přerušení na dejme tomu 5 ms, tak už za tu dobu bude fáze dostatečně daleko, ne? co to je za čidlo, že to dává sinus?
nebo aspoň použij dostatečně velké vstupní napětí a omez to diodama, aby se ta hodnota nešmrdlala okolo nuly.

Napsal: 06 úno 2011, 23:28
od iginoiii
práve to oneskorenie až tak moc nepomáha, ako som dúfal, pretože to zachytí ten sínus aj ked sa vracia smerom dolu(aj napriek tomu, že je prerušenie nastavené na interrupt on rising edge) a celé to zblbne. Ako čidlo ešte nemám nič, sínus a logický signál mu dávam z karty od national instruments(obe pri vzorkovaní 200kS/s).

Ale ako čidlo plánujem diódu a fototranzistor, a tam pri nízkych frekvenciách je ten priebeh "skoro" ako sínus. A dúfal som, že komparátor v attiny bude stačiť, ale ako vidno budem musieť na výstup snímaču dať ešte minimálne tranzistor, resp. komparátor.

Napsal: 06 úno 2011, 23:37
od Crifodo
Když budeš počítat každý průchod nulou a po každém bude dost dlouho zakázané přerušení, tak snad nebudeš muset nic vyhodnocovat.
Kdybys použil magnet na řemenici a čidlo na způsob hallových kláves ve starých XT klávesnicích, měl bys to krásně vytvarované, s hysterezí a rovnou v úrovni pro pin s interruptem a nemusel bys žádné manévry s komparátorem dělat.

Napsal: 07 úno 2011, 00:04
od iginoiii
chcem to mať ako prenosný merák(to som neuviedol), takže mi prijde najjednoduchšie na hociaký hriadeľ len nalepiť reflexnú pásku, resp. čierne čiary na bielom podklade. Každopádne s tým prechodom nulou( v mojom prípade 1.1V je naozaj oveľa inteligentnejšie ako moja nábežná hrana, nakoľko je hneď dvojnásobné vzorkovanie... moja blbosť). Takže ako to tak vyzerá, budem tam musieť dať komparátor....

pretože fakt nechápem, prečo pri tom sínuse aj pri oneskorení vzorkovania to robí blbosti..

edit: respektíve vyskúšať tú diódu-fototranzistor, nakoľko budú použiteľné

Napsal: 07 úno 2011, 00:15
od Andrea
iginoiii píše:pretože fakt nechápem, prečo pri tom sínuse aj pri oneskorení vzorkovania to robí blbosti.

A shazuješ na konci toho zpoždění příznak přerušení od komparátoru?

Napsal: 07 úno 2011, 00:50
od iginoiii
:aplause: ako vždy, máte pravdu... vďaka obom za pomoc.

a teraz moja zvedavosť, prečo tam potrebujem zhodiť ten príznak prerušenia od komparátoru? pretože mne pri debugovaní sa zhodí v avrgcc ten bit sám. ale samozrejme realita je úplne rozdielna

Napsal: 07 úno 2011, 00:53
od Andrea
Ten bit se shodí zavoláním obsluhy přerušení, pokud je ale přerušení zakázané, tak ten příznak zůstane nahozený až do okamžiku, kdy přerušení povolíš a pak se to přerušení vyvolá.

Napsal: 07 úno 2011, 12:58
od iginoiii
vďaka,
ako mám vo zvyku, prikladám hotovú vec. Je určený pre meranie frekvencie do 200Hz, ale prerobiť to na vyššie frekvencie je jednoduché, stačí prerobiť počet miest na displeji a:

Kód: Vybrat vše

_delay_ms(1);   // delay

Hodnota sa obnovuje každú polsekundu, s tým že sa ukladá aj predchádzajúca polsekunda, takže je vyhodnocovanie frekvencie každú sekundu. Pre meranie vyšších frekvencii , a rýchlo meniacich sa frekvencii treba určite skrátiť čas merania, podľa meranej frekvencie a požadovanej presnosti.

edit: a ešte by miesto interného oscilátoru zlepšil presnosť externý kryštál, ale to naozaj nepotrebujem, už táto presnosť ktorú dosahujem je viac ako postačujúca

Kód: Vybrat vše

#define F_CPU 4000000UL // 4 MHZ rychlost uPC

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd.h"


signed int pocet_otacok;
signed int pocet_otacok2;
signed int otacky;
signed int otackyC;
signed int otackyD;
signed char ii;
void nast_komp(void)
{
DIDR |= _BV(AIN1D)| _BV(AIN0D); //vypnutie digital input
/*nastavenie vnutornej referencie komparatoru, umoznenie prerusenia*/
ACSR |= _BV(ACBG)| _BV(ACIE)| _BV(ACIE);
}

void casovac1(void)
{
TCCR1A |= _BV(WGM11)| _BV(WGM10); // WGM = phase correct, update of OCR1A on top, top=OCR1A
TCCR1B |= _BV(CS12)| _BV(CS10)| _BV(WGM13); // CS1X = 1024 prescaller
TIMSK |= _BV(TOIE1); // umoznenie prerusenia
OCR1A=1007; // top phase correct PWM, f = 4000000/(2*976*1024)= 2 Hz
//ale kvoly doladeniu presnosti empiricky zistená hodnota 1007
}

void main()
{
sei();   // Enable Global Interrupts 
casovac1();
nast_komp();


InitLCD(LS_NONE); //inicializacia LCD
   LCDClear();   // clear


for(;;) // Loop Forever
   {
   if(otacky>=1)               // z dovodu pekneho cisla na displeji
   {ii=1;}                     // miesto "010.5" to cele ukazuje
   if(otacky>=10)               // "10.5" atď
   {ii=1;}                     //
   if(otacky>=100)
   {ii=2;}
   if(otacky>=1000)
   {ii=3;}

   LCDWriteStringXY(0,0,"otacky:"); // horny riadok 2*16 lcd displej
   LCDWriteStringXY(5,1,".");       // spodny riadok 2*16 lcd displej, desatinna ciarka
   LCDWriteStringXY(10,1,"o/s");    // spodny riadok 2*16 lcd displej
   otackyC=otacky/10;            // cast otacok pred desatinnou ciarkou
   otackyD=otacky%10;            // zvysok po deleni, za desatinnou ciarkou(0,5)
   LCDWriteIntXY(5-ii,1,otackyC,ii);  // spodny riadok 2*16 lcd displej
   LCDWriteIntXY(6,1,otackyD,1);  // spodny riadok 2*16 lcd displej


_delay_ms(500);
//_delay_ms(500);
LCDClear();   // clear
   }
}



ISR(ANA_COMP_vect) // prerusenie od analogoveho komparatoru
{
pocet_otacok=(pocet_otacok+1);
_delay_ms(1);   // delay
ACSR |=(1<<ACI); // zrusenie priznakoveho bitu
}

// otacky za sekundu
ISR(TIMER1_OVF_vect)
{
otacky=(pocet_otacok+pocet_otacok2)*5;
// suma aktualnych a predch. otacok *5(z dovodu desatinnej ciarky)

pocet_otacok2=pocet_otacok; // ulozenie aktuálnych otáčok do otáčok predchádzajucich
pocet_otacok=0;   // vynulovanie poctu otacok, aby nastalo pripocitavanie odznova
TIFR |=(1<<TOV1); // zrusenie priznakoveho bitu
}


edit: editovaný popis na úvod + nastavenie príznakového bitu

Napsal: 07 úno 2011, 13:05
od Andrea

Kód: Vybrat vše

ACSR |=(0<<ACI); // zrusenie priznakoveho bitu

To funguje? 8O

Mělo tam být

Kód: Vybrat vše

ACSR |=(1<<ACI); // zrusenie priznakoveho bitu

Napsal: 07 úno 2011, 13:12
od iginoiii
:D naozaj to funguje, a dosť slušne. Ale pri debugovaní mi celý ten príkaz nič nerobí, ja fakt neviem... skúsim sa s tým ešte trochu potrápiť

Napsal: 07 úno 2011, 13:28
od AB1
#define F_CPU 4000000UL // 1 MHZ rychlost uPC

Tady nesouhlasí hodnota s komentářem.
Pokud procesor běží na 1 MHz, pak má být
#define F_CPU 1000000UL

Napsal: 07 úno 2011, 13:31
od iginoiii
to je len poznamka, som tam zabudol prepisat to za lomitkom zo stareho kodu, ale aj tak dik, popis by mal korespondovat s realitou. ii

takže to editujem v tom pôvodnom, nech nemusím zase ten dlhý kód vkladať sem

každopádne opäť ste mala Andrea pravdu, ten syntax som mal zle, má byť pri odstránení bitu toto:

Kód: Vybrat vše

&=~(1<<bitnumber)

a ja navyše to nemám odstraňovať, ale naopak.. takže dvojnásobná chyba
takže aj toto editujem tam hore

Napsal: 07 úno 2011, 14:33
od piitr
Já ty atmely moc neznám, ale měl jsem dojem, že se maže zápisem jedničky, takže správně je:

Kód: Vybrat vše

reg = 1 << bitnum;

Ale nedělám do toho, neberte mě moc vážně.

Napsal: 07 úno 2011, 14:39
od Andrea
Teď mi to docvaklo. Ono to s tou nulou funguje, protože to je OR, takže se ten registr přečte a zase zpátky zapíše, takže pokud tam byla jednička, tak se zapsala zpátky a tím se shodila. Jak v tom Cčku nedělám, tak mi to nedošlo. :oops:

Ale správně by to mělo být jak píše piitr, tím se neovlivní ostatní bity.
Edit: Není to správně, viz. další příspěvek.