Stránka 1 z 2

Odečítání z enkodérů rychlosti

Napsal: 04 srp 2009, 22:38
od ATMEGA
Ahoj. Bohužel už si nepamatuju přezdívky co jsem používal předtím a zdejší vyhledávání na fóru není zrovna 100procentní, takže takto navazuju na předchozí diskuze. Já jsem ten s tím prográmkem pro ovládání rychlosti motorků s hallovými senzory. Konečně mám čas a tak jsem se zas do toho pustil. Kód v příloze je sice funkční, ale ne moc přesný. Ovládání rychlosti mám pomocí PI regulátoru. Funguje to, ale pořád ještě pomalu. Soustředil jsem se tedy na prvotní problém: odečítání rychlosti. To je dost pomalé, ale asi jediné funkční, když počítám dobu mezi 12 impulsy, kterou jsme se tuhle dohodli, že musím dodržovat. Myslím, že by šlo počítat dobu i mezi méně impulsy. (Přeci jenom hallův enkodér který dává 360 pulsů za otáčku není to pravé). K těmto motorkům existuje už hotový kontrolér, který sice plně nesplňuje mé představy, ale pochybuju že odečítá pro 12. Potřeboval bych poradit, jak mám kód uskromnit, protože MCU takto nestíhá. Pokud nastavím setuptime(viz, zdroják) na aktuální čas, tak se to už po 5 minutách o 10 vteřin zpožďuje. Je to způsobené tím, že je tam ještě přerušení od sériového portu, ale nevím co s tím. ?

Napsal: 05 srp 2009, 00:38
od ATMEGA
Jen pro připomenutí. Ten enkodér dává 12 pulsů na otáčku motoru a převodovka je 30:1, proto to měření po 12, asi tam jsou nějaké brumy a nepřesnosti.

Napsal: 05 srp 2009, 08:45
od Crifodo
ten problém s vlastní identitou a s kontinuitou svých dotazů si nějak vyřeš, než z toho bude tvůj hlavní problém. :twisted:
Většinou tady k tomu slouží registrace.

Napsal: 05 srp 2009, 11:17
od vasek125
Tak jo. Po nějakém vzpomínání jsem přišel na své heslo a mohl se znova přihlásit :-) .

Napsal: 06 srp 2009, 02:57
od vasek125
Zpátky k problému: jak zjednodušit kód aby mcu stíhal, nebo spíše jak nastavit přerušení od sériového portu, aby nikdy nerušilo přerušení kde běží odečítání rychlosti?

Napsal: 06 srp 2009, 09:52
od piitr
No, tyhle věci se řešívaly tak, že řadič přerušení uměl rozlišovat priority. Nevím ale, jestli to AVR umí. Čekal bych, že ne. Co by ale možná šlo, je udělat zpracování jednoho přerušení dále přerušitelné a druhé ne. To by možná šlo a vyhovělo. Myslím jako hned na začátku toho delšího přerusení povolit další přerušení.

Taky jsem se dival na ten kód. Obecně bych řekl, že tam máš na můj vkus zbytečně moc proměnných. Např. místo pwm1counter, pwm2counter a pwm3counter stačí jen jeden pwmCounter. Dále speedLcounted1 a speedLcounted3 mají vždy právě opačné hodnoty, takže by stačila jen jedna z nich. A tak podobně. Kdyby se Ti povedlo všechny vstupy ze senzorů dát na jeden port, možná by se ta jedna časovací rutina dala trochu zjednodušit. Třeba takhle:

Kód: Vybrat vše

static int oldSenzorPin = 0;

...

ISR(TIMER2_OVF_vect) { // zavola se pri preteceni interniho 8bit citace
   int senzorPin;
   int senzorDelta;

   TCNT2=254; // 14.7456MHz/256/2=28800 preruseni/sec - pocita s nastavenim interniho oscilatoru na    
      // 14.7456MHz. Pokud tak neni, je nutne prepocitat
       // 1024 (velikost counteru) - 9 (nas delitel) = 6 (pri kazdem preteceni       
         // zaciname od 6 a ne od 0)

   longac++;
   // longac ma byt 600 pro poslani 1x/vterinu, 120 pro 5x/vterinu
   if (longac>=28800) {
      longac=0;
      longacDOit=1;
      longac3DOit=1;
      longac10++;
   }
   
   if ( pwmCounter <= PWMD1 ) bitSet(PORTC, 3); else bitClear(PORTC, 3);
   if ( pwmCounter <= PWMD2 ) bitSet(PORTC, 4); else bitClear(PORTC, 4);
   if ( pwmCounter <= PWMD3 ) bitSet(PORTC, 5); else bitClear(PORTC, 5);
   pwmCounter = (pwmCounter + 1) & 0xFF;
   
   pulsecounterL++;
   pulsecounterP++;
   
   senzorPin = SENZOR_PIN;
   senzorDelta = senzorPin ^ oldSenzorPin;
   if ( senzorDelta & (1<<LEVY_SENZOR_H | 1<<LEVY_SENZOR_Z) ) pulseL++;
   if ( senzorDelta & (1<<PRAVY_SENZOR_H | 1<<PRAVY_SENZOR_Z) ) pulseP++;
   if ( (senzorPin & (1<<LEVY_SENZOR_H & 1<<LEVY_SENZOR_Z)) == 0 ) speedLdir = senzorDelta>>LEVY_SENZOR_H & 1;
   if ( (senzorPin & (1<<PRAVY_SENZOR_H & 1<<PRAVY_SENZOR_Z)) == 0 ) speedPdir = senzorDelta>>PRAVY_SENZOR_H & 1;
   oldSenzorPin = senzorPin;
   
   if (pulseL>=12 || pulsecounterL>28800) {
      finalSpeedL = (pulseL*(28800000/pulsecounterL))/1000; // nevim, jak je rychle deleni, mozna by pomohlo, kdyby se

hodnoty pulseL a pulseCounterL jen zkopirovaly do globalnich promennych a delilo by se to mimo preruseni
      pulsecounterL = 0;
      pulseL = 0;
   }
   
   if (pulseP>=12 || pulsecounterP>28800) {
      finalSpeedP = (pulseP*(28800000/pulsecounterP))/1000;
      pulsecounterP = 0;
      pulseP = 0;
   }
}

Edit: Chyběly mi tam jedny závorky, protože & má nižší prioritu než ==. Tak jsem je tam přidal.
Edit2: Ještě jsem odstranil jednu operaci &, protože byla vlastně zbytečná.

Napsal: 06 srp 2009, 22:05
od vasek125
Mockrát děkuju, vyzkouším. Myslím že je ale největší problém přerušení od sériového portu. Protože když je toto přerušení aktivní, tak nemůže být aktivní to timer přerušení. Jak mám nastavit, aby timer přerušení nebylo nikdy ničím rušeno? Mohu nějak přesunout obsluhu sériového portu do timer přerušení?

Napsal: 06 srp 2009, 22:20
od Návštěvník
A proč ty IRC obsluhuješ v přerušení od časovače a ne jako každý příčetný programátor jednočipů v přerušení od hrany na pinu? Takhle musíš strašně zatěžovat procesor, zbytečně. A dělit longinty v přerušení taky neukazuje moc na příčetnost.

Napsal: 06 srp 2009, 23:03
od vasek125
Přerušení od portu jsem zkoušel a ukázalo se jako horší než takto to řešit. Je tam více přerušení které mohou nastat ve stejný čas a docházelo k hrozným výkyvům a měření bylo pomalé.

Napsal: 07 srp 2009, 00:47
od vasek125
piitr: Jak myslíš povolit přerušení na začátku přerušení jiného? To tam stačí na začátek přerušení napsat sei;? Není to globální proměnná?

Napsal: 07 srp 2009, 08:55
od piitr
Já nevím, jak je to na AVR, ale na PICu je pro každý zdroj přerušení jeden bit, který ho povoluje. Pak je tam jeden bit, který povoluje přerušení jako takové - pokud je na 0, jsou zakázána všechna přerušení. Tento bit se při vstupu do přerušení automaticky nuluje, takže obsluha přerušení není dále přerušena. Instrukcí návratu z přerušení se ten bit zase nahodí. Tak si s tím nějak pohrát a u té dlouhé rutiny třeba přerušení hned na začátku povolit. Jak se to dělá na AVR, nevím.

Já jsem teda nekoukal, co všechno v tom přerušení od sériové linky máš, ale tak nějak bych zvažoval, tam dát jen uložení přijatého bajtu do bufferu, odeslání bajtu z jiného bufferu a zbytek dát do hlavního programu. Tak si nějak neumím představit, co tam může tak dlouho trvat.

Napsal: 07 srp 2009, 14:18
od piitr
Pokud to AVR nemá řízení přerušení podle priorit, taky je asi možné takové chování docílit programově. Jako že by se vždy na začátku přerušení otestovalo, jestli se má, nebo nemá provádět. Jelikož ale AVR neznám, nedokážu odhadnout, jak by to bylo pracné a rychlé. Takže bych šel asi tou cestou, aby v těch rutinách bylo jen nutné minimum - třeba ta komunikace přes buffer. Zatím mi takový přístup vždycky vyhověl.

Napsal: 07 srp 2009, 20:45
od Návštěvník
V čem je tak výhodné používat při výpočtu rychlosti dvě dělení:

Kód: Vybrat vše

finalSpeedL = (pulseL*(28800000/pulsecounterL))/1000;

oproti jednomu:

Kód: Vybrat vše

finalSpeedL = pulseL*28800/pulsecounterL;

?

Napsal: 07 srp 2009, 21:05
od Atlan
skor ako to prelozi prekladac :D

Napsal: 08 srp 2009, 14:37
od vasek125
Překladač to stejně určitě nepřeloží. Při stejném pwm vyjde ten můj výpočet cca 570, ten zjednodušený 130. Při použití závorek už to vyjde podobně ale ne stejně, protože to zaokrouhluje, proto ten 1000 navíc. Ačkoli to tak nevypadá, skutečně tomu tak je, mám to odzkoušené. Jinak sei použít na začátku přerušení opravdu jde, ale přerušení od sériového portu jsem musel nechat tak, jak je, protože jinak komunikace nefungovala, na to se opravdu sáhnout nedá. Přikládám nový kód, je o hodně rychlejší řízení, ale výsledná rychlost kolísá při stejném pwm +-50, což je určitě pokrok, protože je to při použití měření mezi 3 pulsy(tudíš nepřesnost není v senzoru, ale v programu). Stále to ale není ono. Tomu novéhu kódu na měření rychlosti moc nevěřím ani moc nerozumím, nemám jistotu že pulsy půjdou "po sobě" (Měření může být občas s chybou).