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

Diskuze a poradna o programátorech a programování různých obvodů

Moderátor: Moderátoři

Zpráva
Autor
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

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

#1 Příspěvek 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;
}
Uživatelský avatar
Crifodo
Příspěvky: 14779
Registrován: 11 říj 2005, 00:00

#2 Příspěvek 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.
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

#3 Příspěvek 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.
Uživatelský avatar
Crifodo
Příspěvky: 14779
Registrován: 11 říj 2005, 00:00

#4 Příspěvek 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.
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

#5 Příspěvek 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é
Andrea
Příspěvky: 9340
Registrován: 07 zář 2007, 00:00

#6 Příspěvek 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?
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

#7 Příspěvek 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
Andrea
Příspěvky: 9340
Registrován: 07 zář 2007, 00:00

#8 Příspěvek 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á.
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

#9 Příspěvek 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
Naposledy upravil(a) iginoiii dne 07 úno 2011, 13:40, celkem upraveno 2 x.
Andrea
Příspěvky: 9340
Registrován: 07 zář 2007, 00:00

#10 Příspěvek 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
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

#11 Příspěvek 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ť
Uživatelský avatar
AB1
Příspěvky: 312
Registrován: 23 lis 2009, 00:00

#12 Příspěvek 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
Uživatelský avatar
iginoiii
Příspěvky: 364
Registrován: 01 črc 2010, 00:00
Bydliště: Bratislava

#13 Příspěvek 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
Uživatelský avatar
piitr
Příspěvky: 1003
Registrován: 19 říj 2007, 00:00
Kontaktovat uživatele:

#14 Příspěvek 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ě.
Andrea
Příspěvky: 9340
Registrován: 07 zář 2007, 00:00

#15 Příspěvek 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.
Naposledy upravil(a) Andrea dne 07 úno 2011, 17:18, celkem upraveno 1 x.
Odpovědět

Zpět na „Programování PIC, ATMEL, EEPROM a dalších obvodů“