Jednosmerný letecký regulátor - 3. časť

Tak, tu je tretí diel. Sú tu popísané základné rutiny programu a ako fungujú, aké hardvérové funkcie som použil. Chcel som to napísať tak, aby to bol nejaký návod, akým systémom som to riešil, keby sa tým dakto chcel inšpirovať. Nechcel som, aby to bol preklad datašítu, teda vysvetľovať, ako funguje generátor PWM, to si každý podrobne prečíta v datašíte.

Tým návodom som mienil aj to, aby ten, kto sa tým bude chcieť inšpirovať, to nezobral , tak že toto skopírujem sem, toto tam a pôjde to. Ale len popis princípov činnosti. Aby ten, kto by to chcel použiť, to bral len ako pomôcku, aké hardvérové funkcie sa na to dajú použiť a ako ich použiť v softvéri. Aby sám rozmýšľal, čo od toho bude on chcieť a spravil si to podľa svojich požiadaviek.

autor: Andrej B.

 

 

Dostal som podnety na napísanie podrobnejšieho popisu riadiaceho programu, takže som napísal aj tretiu časť článku.
 


Začnem na začiatku zdrojového kódu, pri hlavičkových súboroch. V programe používam funkcie na obsluhu vstupov a výstupov mikrokontroléra, prerušenia, spánkové režimy a oneskorovacie slučky, takže je potrebné vložiť príslušné hlavičkové súbory:
 

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


Ešte pripomeniem, že je použitý mikrokontrolér ATtiny2313, taktovaný 1 MHz vnútorným RC oscilátorom. Podrobný popis hardvérových funkcií je v datašíte  . 

Teraz niečo o výstupe regulátora. Ako som vravel, regulátor generuje šírkovo modulovaný signál a ním spína výkonový tranzistor. Na generovanie tohto PWM signálu používam 8 bitový časovač (Timer/Counter 0) a jeho funkciu Output compare v režime Rýchla PWM. Aby som generoval signál a dostal ho na výstup, musím zapnúť časovač, generátor PWM a pripojiť ho k výstupu (nastavením príslušnej V/V nožičky ako výstup).
 

DDRD = 0x20;       // výstup na PD5, zvyšok portu vstup
OCR0B = 127;       // nastavenie striedy
TCCR0A = 0x23;   // PWM na OC0B, aktívna úroveň 1
TCCR0B = 0x02;   // zapnem časovač, delenie taktu 8


Časovač0 má dva PWM kanály, ja som použil B. Aktívna úroveň 1 znamená, že keď je na výstupe µC 1, tak je otvorený aj výkonový tranzistor (pozri schému), tiež že so zväčšovaním hodnoty OCR, sa zväčšuje aj šírka impulzu na výstupe (výkon). Taktovanie časovača odvodzujem od systémových hodín, avšak s delením frekvencie 8, aby som dosiahol f výstupného signálu 488 Hz (tá je = f pretekania časovača). Po týchto príkazoch časovač beží, na nožičke PD5 (výstup OC0B) je signál so striedou 50% určenou hodnotou registra OCR0B. Keď chcem zmeniť šírku impulzu, iba jednoducho mením hodnotu tohto registra. Tu treba pamätať na to, že keď OCR má hodnotu 0, tak na výstupe je signál so striedou 1/256, nie trvalá nula. Dosiahnuť na výstupe nulu je troška zložitejšie, treba vypnúť PWM a pre istotu explicitne nastaviť príslušný výstup na 0. 

Regulátor ako vstup používa signál z prijímača, rovnaký ako pre servo. Jedná sa o impulzy, ktoré svojou šírkou určujú nastavenie príkonu motora. Teda potrebujem zmerať ich šírku. Na to používam 16 bitový časovač s funkciou Input capture. Jej princípom je uloženie hodnoty akú mal časovač, keď prišla na vstup hrana signálu. Keďže input capture sa nastavuje na reakciu pri nejakej hrane a v tomto prípade potrebujem merať čas medzi nábežnou a dobežnou hranou, za každou hranou musím zmeniť nastavenie detekcie na opačnú hranu (nábežná -> dobežná a naopak) aby časovač zachytil každú hranu. Hodnoty časovača uložené pomocou input capture do hlavnej funkcie vyberám z ICR v prerušení a tam aj mením nastavenia.
Samotné zapnutie časovača a input capture vyzerá takto:

 

PORTD |= _BV(PD6);   // zvyšovací odpor pre ICP
TCCR1B = 0x81;           // IC na dobežnú hranu, odstraňovač šumu, // časovač zapnutý - taktovanie bez delenia
TIMSK = 0x88;               // povolené prerušenia input capture, pretečenie 1
sei();                                // globálne povolenie prerušení

Zvyšovací odpor na nožičku kde je vstup ICP zapínam, aby v prípade, keby nebol na vstup pripojený Rx, bola na vstupe definovaná a stála úroveň. Pri takomto nastavení taktovania je rozlíšenie merania 1 µs. Potom treba nastaviť aké prerušenia z časovačov používam. Potom už len v obsluhe prerušenia vyberám hodnotu z ICR a ukladám si ju do premenných a zmením detekčnú hranu input capture. (pretečenia využívam ako signalizáciu chybového stavu - vstup bez signálu). 

Ďalším vstupom regulátora je napätie pohonného akumulátora. Regulátor zisťuje jeho veľkosť - či je vyššie alebo nižšie ako hranica pre vypnutie. V tomto prípade som použil µC, ktorý nemá ADC, miesto neho som použil analógový komparátor. Jeho použitie mi síce nedáva presnú informáciu o veľkosti U, ale dá sa zaobísť aj bez toho a je oveľa jednoduchšie. Komparátor je predvolene zapnutý (na rozdiel od ostatných periférií), takže jedinou obsluhou je zisťovanie stavu jeho výstupu. V datašíte je odporúčané vypnúť digitálne vstupy nožičiek kde sú pripojené napätia vstupujúce do komparátora, toto urobím ako prvý príkaz v programe. Takže obsluha komparátora môže vyzerať nejako takto:
 

DIDR = 0x03;                               // odpojenie digitálnych vstupov

if(bit_is_clear(ACSR,ACO))
{   // pokiaľ je U aku nízke vykoná sa niečo
...
}


Môj regulátor funguje systémom, že väčšinu času procesor spí a o funkcie sa starajú periférie (časovače), zo spánku ho zobúdzajú prerušenia, keď na vstup príde hrana signálu. Potom vyhodnotí vstup, nastaví výstup a znova prejde do spánkového režimu a tak dokola. Spánkový režim sa dá nastaviť buď priamo nastavením hodnoty MCUCR alebo pomocou makier zo sleep.h. Potom ho ešte treba povoliť a µC uspať, po zobudení sa odporúča spánok hneď zakázať:
 

sleep_enable();       // povolenie spánku
sleep_cpu();            // uspanie µC v nastavenom režime
sleep_disable();     // zakázanie spánku po zobudení


 Teraz niečo k počítaniu. Po zapnutí regulátora najprv treba zmerať impulz pri vypnutom motore (stiahnutý plyn), aby regulátor vedel kedy má byť motor vypnutý. To dosiahnem popísaným spôsobom merania impulzov tak, že v obsluhe prerušenia najprv zistím aká hrana prišla a podľa toho príslušnej premennej priradím hodnotu z ICR. V hlavnom programe vypočítam šírku impulzu ako rozdiel týchto hodnôt. Tu je vhodné obmedziť aký impulz regulátor akceptuje (v nejakom intervale hodnôt). 

Hlavnou činnosťou regulátora je meranie vstupného signálu a podľa neho výpočet výstupu. Vždy keď sa procesor zobudí, skontroluje aká hrana signálu ho zobudila, pokiaľ to bola nábežná tak ešte nemá odmeraný čas aktuálneho impulzu z Rx a teda výpočet sa nemôže vykonať a spí ďalej. Ak sa cpu zobudil po dobežnej hrane, tak najprv skontroluje Uaku, ak je nižšie ako hranica (ACO == 0), poznačí si to a postupne ráta koľkokrát sa vyskytol pokles U. Ak bol týchto poklesov bez prerušenia určitý počet, aku je vybitý a motor treba vypnúť. Ak sa po niekoľkých poklesoch objaví znova Uaku vyššie ako hranica, bol to len krátkodobý pokles (napr pri pridaní plynu) a počítadlo poklesov vynulujem. Keď je napätie dostatočne vysoké, motor môže bežať a pokračujem výpočtom výstupu.
Najprv vypočítam aký dlhý bol impulz ako rozdiel času na jeho začiatku (pri nábežnej hrane) a na konci. Potom zistím či je v intervale od polohy vypnutý (preto som meral impulz pri zapnutí) po max hodnotu, akú môže mať (2 ms, ale dalo by sa to tiež odmerať, aby bolo nastavovanie presnejšie), ak áno vykonám výpočet, ak nie, je to chybný impulz a ignorujem ho. Keďže nechcem aby motor bežal pri akejkoľvek odchýlke kniplu od nuly, musím si určiť hranicu kedy sa zapne (aj kvôli určitej hysteréze motora pri rozbiehaní a zastavovaní), ja som ju určil ako kalibračný impulz + 60 µs. Teraz nasleduje rozhodnutie či je vstupný impulz >= ako tento minimálny alebo nie. Ak áno vypočítam výstup podľa vstupu, ak nie, výstup bude 0. Výstup určím ako nejaký násobok vstupu tak, aby mi pre možný rozsah vstupných impulzov vychádzal výstup v rozsahu 0 - 255. Tento násobok som nastavil 4/15. Výpočet vyzerá takto:
 

 

uint8_t vystup;                                     // šírka výstupného impulzu
uint16_t impulz = koniec - zaciatok;     // dĺžka impulzu v
µs

if((impulz >= kalibracny) && (impulz < 2051)) { /* výpočet iba ak šírka impulzu patrí do tohto intervalu */
if(impulz >= minimalny)
vystup = ((impulz - kalibracny) << 2) / 15;
else                                                   // pokiaľ by bol < ako minimálny, motor sa vypne
vystup = 0;
if(impulz > 1940) /* výpočet neni presný, v tomto prípade motor pustím naplno, bez ohľadu na výsledok výpočtu */
vystup = 255;
}


Potom ešte treba hodnotu premennej výstup vložiť do časovača generujúceho výstupný PWM signál. Predtým však treba zistiť či má hodnotu 0, ak áno musím vypnúť PWM generátor aby motor nebežal. (Dôvod je popísaný v časti o output compare). Ak má nenulovú hodnotu, tak PWM generátor zapnem. Potom vložím výstup do OCR0B.
 Ešte niečo o vypnutí regulátora v prípade vybitého akumulátora. Vypnem generovanie PWM, výstup nastavím na 0 aby bol motor vypnutý, vypnem prerušenia (aby sa nemohol zobudiť) a uspím µC.
 

To by bol popis funkčných blokov zdrojového kódu.

Dávam k dispozícii plošný spoj a preložený program pre regulátor. V prípade záujmu pošlite mail na adresu

rcmodely@cevaro.sk

a súbory vám budú obratom doručené do vašej mailovej schránky.
                                     Andrej


 


 


 

 

 


<Staršie | tento článok | Novšie>

Napísané: 5. 12. 2011, 17:15 | Prečítané: 7360x | Kategórie: Elektronika | Napísal: admin |
Komentáre: 4
.:. Janko O
Dávam k dispozícii plošný spoj a preložený program pre regulátor. V prípade záujmu pošlite mail na adresu

rcmodely@cevaro.sk

a súbory vám budú obratom doručené do vašej mailovej schránky.
Andrej
Odpoveď | 2011-12-10 13:25:03
.:. LQd | mail
PWM sa dá jednoducho vypnúť nastavením pinu na vstup, s časovačom netreba nič robiť, mám to vyskúšané na atmegách, pre attiny to bude asi rovnaké. Podľa mňa je to pohodlnejšie, ale zas prepnutie vstupu na výstup (aktivácia PWM) bez ohľadu na časovač môže spôsobiť (a na 99% aj spôsobí) nekorektnú šírku prvého pulzu, čo za normálnych okolností vôbec nevadí, iba ak by bola požiadavka na 100% kvalitný signál, potom je lepšie časovač vypnúť, alebo vynulovať jeho hodnotu tesne pred zmenou vstupu na výstup.
To len taká poznámočka na okraj, som si neodpustil :-D

Mimochodom pekná práca, držím palce na ďalšie projekty a prajem hodne síl a pevné nervy :)
Aj ja uvažujem nad podobnou konštrukciou, zhorel mi regulátor na accu vŕtačke a peniažky, ktoré by som nadžgal do vačku opravárovi za nový (a ešte čakal tri mesiace, kým ho objedná) viem použiť aj lepšie...
Odpoveď | 2012-02-15 22:46:04 | Príspevok upravený: 2012-02-15 22:49:41
.:. Andrej B
prepnúť výstup na vstup má jeden zádrhel. Ak sa to prepne v momente kedy je na výstupe aktívna úroveň (v tomto regulátore jednotka) a ak je na výstup pripojený nejaký prvok ovládaný prúdom(bipolárny tranzistor, optočlen, ledka,...) tak to nevadí, tranzistor sa zavrie apod. ALE ak je na výstup pripojený mosfet, tak tento zostane otvorený (kvôli kapacite Cgs) a bude sa zatvárať niekoľko sekúnd. A to je výborný spôsob na jeho odpálenie.
Keď na výstupe nastavím trvalú neaktívnu úroveň, tak sa aj MOSFET zaručene okamžite vypne a bude vypnutý dokým na výstup nepripojím aktívnu úroveň.
Odpoveď | 2012-03-07 10:17:32
.:. pato | mail
Je na tom to regulatore aj spiatočka
Odpoveď | 2014-11-21 20:33:56
Pridaj komentár
Meno
Web
Mail
Kontrola Zadajte číslo päť
Text

:-)
:-D
:-(
|-/
:-[]
;-)
8-|
8-o
Tučné | Podrazené | Kurzíva  | zdroják | odkaz
  • Pre odoslanie správy môžete aj použiť klávesovoú skratku Alt+S. (Podporujú len niektoré prehliadače)
  • HTML znaky budú prevedené na entity.
  • Vyjadrujte sa tu ako doma, aby sme vedeli ako to u Vás vypadá.
  • Odkazy začínajúce http:// budú automaticky prevedené na odkazy , nepoužívajte však v jednom príspevku viac ako 3 - to robia len spam roboti:-)
správca | ICQ-Vaše ICQ | Podpora miniRS | Styl LazyDays | Sk preklad by beekeeper | Veľkosť databázy: 39974.79 kb