Program PID regulátoru mikropájky
Jedním z cílů vlastní konstrukce pájecí stanice bylo, naučit se naprogramovat PID regulátor teploty. Proporcionální, integrační i derivační složka regulátoru je realizována programem v procesoru ATmega8. Do regulátoru vstupuje regulační odchylka, ta je vypočtena jako rozdíl požadované a naměřené teploty na termočlánku pájecího pera. Vystupuje akční veličina, tou je střída PWM signálu, kterým je řízeno napájení topné těleso pájky Solomon 24V/48W. Při programování a měření jsem se seznámil s fyzikálními vlastnostmi řízené soustavy: topné těleso, poblíž uložený termočlánek a kovové pájecí pero s relativně velkou teplotní setrvačností.
Zapojení pájecí stanice je převzaté ze stránek PaJa. Místo stabilizátoru 7805 je osazen step-down měnič s MC34063, protože jsem chtěl vyzkoušet, jak moc bude spínaný zdroj rušit chod měření. Výsledek: používaná hodnota napětí z převodníku musí být průměrována alespoň z pěti naměřených hodnot, aby se dalo využít 12-ti bitů. Jako AD převodník jsem použil LTC1286, protože byl zrovna v šuplíku. Podrobným popisem zapojení se zabývali mí předchůdci, já se ve svém článku zaměřím na programování stanice, speciálně na regulátor teploty.
Na úvod je zapotřebí říct, že řídit výkon pájecího pera PID regulací a PWM signálem je zbytečný přepych, stačí obyčejný termostat. I když při použití termostatu bude teplota naměřená termočlánkem uvnitř pera kmitat v rozsahu 3 – 4°K, teplota na hrotu se nezmění víc, než o stupeň. Je to proto, že termočlánek je někde blízko topného tělesa, které je obaleno spoustou kovu. Ten kmitání teploty stabilizuje. Termostat ve srovnání s PWM regulací navíc nevyzařuje spoustu rušivých kmitočtů, které můžou vadit při oživování pájeného obvodu. Hrál jsem si s tím hlavně proto, abych se na jednoduché aplikaci seznámil s programováním PID regulátoru.
Návrh programu
Po zapnutí přístroje program nastaví registry I/O portů a inicializuje proměnné. Nastaví přerušení INT1, které je použito pro snímání údajů z rotačního kodéru. Nastaví časovač T1, který je v režimu PWM. Kanál A ovládá tranzistor BUZ11 a tím výkon pájky, kanál B jsem dodatečně použil k ovládání piezoměniče. Potom jsou z paměti EEPROM procesoru načteny proměnné, jejichž hodnotu lze měnit v MENU programu. Nakonec je aktivován displej.
V hlavní smyčce programu je na displej vypisována aktuální teplota pájky, požadovaná teplota pájky a aktuální výkon PWM. Na konci smyčky je zavolána funkce, která vyhodnocuje stav tlačítka rotačního kodéru. Pokud je stisknuto, bude možné v programu MENU_Global() nastavit jednotlivé proměnné, používané v programu.
while(1) { LCD_Position( 0, 0 ); // prvni radek LCD_WriteCString( "Tsold = " ); LCD_PrTemp( TempSolder ); // teplota telesa // LCD_PrIntDec( IntegralRozdil ); LCD_WriteCString( " " ); LCD_Position( 1, 0 ); LCD_PrTemp( TempSet ); // nastavena teplota LCD_PrPwm( SolderPWM / 8 ); // aktualni vykon v desetinach procenta _delay_ms( 100 ); if (ROT_Key() > 2) MENU_Global(); // ceka na stisk rotacniho koderu }
Měření napětí z AD převodníku, výpočet teploty a program PID regulátoru, který nastavuje PWM kanál je součástí programu přerušení T1. Proměnná TempSet – teplota, kterou se snaží regulátor udržet na pájecím peru, je na začátku nastavena na hodnotu převzanou z EEPROM. Potom je možné ji měnit prostřednictvím rotačního kodéru a na něj napojeného programu přerušení INT1.
Měření napětí na termočlánku mikropájky
Napětí na svorkách termočlánku se pohybuje v rozmezí 0 – 18mV pro teploty od 20 – 500°C. Toto napětí je operačním zesilovačem OP07 zesíleno přibližně 240 krát, aby byla využita velká část rozsahu AD převodníku. Ten je 0 – 4,096V, protože toto napětí je dodáváno referenčním zdrojem TL431.
K obsluze AD převodníku slouží funkce LTC1686(), která vrací 16-ti bitové číslo ve formátu unsigned int. Doopravdy je z 16-ti bitů použito pouze dvanáct, takže hodnota bude v rozsahu 0 – 4095. Při daném zapojení odpovídá jednotka čísla z funkce LTC1286() přibližně 4µV na svorkách termočlánku. Naměřené napětí můžeme na displeji zobrazit procedurou LCD_PrIntDec( LTC1286()).
unsigned int LTC1286(void) { unsigned char ADcount; unsigned int ADval=0; AD_CS_Clr; // sestupna na CS AD_CLK_Clr; AD_CLK_Set; // hodinovy impuls AD_CLK_Clr; AD_CLK_Set; // hodinovy impuls AD_CLK_Clr; for(ADcount=0;ADcount<13;ADcount++) { AD_CLK_Set; // hodinovy impuls AD_CLK_Clr; if ((PIND & 0x40) == 0x40) ADval++; // kdyz je H, bude nulty bit=1 if(ADcount<12) ADval <<= 1; // posune prijimana data } AD_CS_Set; return ( ADval ); }
Převodník LTC1286 a výpočet průměrné hodnoty z několika měření
V programu pájecí stanice je fukce AD převodníku spouštěna v programu obsluhy přerušení časovače T1. Registry ovládájící časovač jsou nastaveny tak, aby bylo přerušení časovače spouštěno 1000x za sekundu, když je kmitočet procesoru nastaven na 8MHz.
TCCR1A = 0b10100010; // Frekvence = F krystal TCCR1B = 0b00011001; // rezim PWM 14 TIMSK = 0b00000100; // preruseni pri preteceni ICR1 = 8000; // 1000 Hz kmitocet PWM OCR1A = 0; // pajka PWM = 0% OCR1B = 4000; // 50% PWM pro piezomenic
Měření tedy probíhá 1000x za sekundu, ale data z AD převodníku jsou zatížena šumem, proto je počítán průměr s několika měření. První nápad byl, uložit několik měření do pole dat MeanArray, potom data v poli sečíst. Součet vydělit množstvím dat v poli a tak získat průměr. Nevýhoda je, že rozdíl mezi dvěmi takto získanými hodnotami může být velký. Zároveň trvá dlouho, než je vypočítaná další hodnota, což zpomaluje reakce regulátoru. Přemýšlel jsem, jestli by bylo možné k součtu MeanAdd při každém spuštění programu přerušení časovače T1 přičíst nově naměřenou hodnotu a odečíst hodnotu, která byla naměřena někdy v minulosti.
Následující řádky programu ukládají naměřené hodnoty do pole MeanArray. Velikost pole je nastavena v menu programu a uložena z EEPROM do proměnné MeanMax. Do proměnné MeanAdd je při každém měření přičtena aktuálně naměřená hodnota, ta je zároveň uložena do pole a odečtena hodnota z druhého konce pole. Takže MeanAdd / MeanMax zobrazuje vždy aktuální průměr hodnot z posledních měření. Množstvím hodnot (velikostí pole v proměnné MeanMax) určujeme přesnost měření a rychlost odezvy v čase. Velké pole hodnot reaguje pomaleji na změny teploty, optimální je kolem 20 měřených hodnot.
MeanArray[ MeanPointer ] = LTC1286(); // nameri se hodnota MeanAdd += MeanArray[ MeanPointer ]; // pricte namerenou hodnotu if (MeanPointer < MeanMax) MeanPointer++; else MeanPointer=0; // ovladani ukazatele v poli MeanAdd -= MeanArray[ MeanPointer ]; // odecte namerenou z konce pole MeanOld = Mean; // ulozi hodnotu z minuleho mereni Mean = (unsigned int) (MeanAdd / MeanMax); // vypocte prumer
Výpočet teploty (proměnná TempSolder) z naměřené hodnoty (proměnná Mean)
Abych se v programu vyhnul použití aritmetiky s pohyblivou čárkou, probíhají všechny výpočty v množině celých čísel a až procedura zobrazení na displeji vloží na vhodné místo desetinnou čárku. Vzhledem k rozlišení AD převodníku jsem se rozhodl, že rozlišení proměnných které zobrazují teploty, bude desetina stupně. Úkolem tedy je, přepočítat číslo z AD převodníku na desetiny stupně.
Závislost napětí z termočlánku na teplotě je lineární, je tedy popsána rovnicí přímky. Pokud je operační zesilovač a AD převodník lineární, bude i závislost údaje z AD převodníku na teplotě popsána rovnicí přímky. K přibližnému sestavení rovnice budeme potřebovat teploměr a voltmetr. Voltmetr dáme na výstup operačního zesilovače a sondu teploměru vložíme do dutiny místo hrotu pájky. Zesílení operačního zesilovače nastavíme tak, aby při 450°C bylo na jeho výstupu něco kolem 3,8V. Tím je dosaženo optimálního využití rozsahu AD převodníku. Na přímce, která popisuje závislost napětí na teplotě vyznačíme dva body následujícím způsobem:
Bod pro 100°C označíme číslem 1000 (to jsou desetiny stupně) a k němu přiřadíme napětí z operačního zesilovače, 700mV.
M = [ Mx; My ] = [ 1000; 700 ]
Bod pro 400°C označíme číslem 4000 a k němu přiřadíme napětí z operačního zesilovače, 3437mV.
N = [ Nx; Ny ] = [ 4000; 3437 ]
Vypočteme vektor přímky u = ( Nx – Mx; Ny – My) = ( 3000; 2737 )
Rovnice přímky jsou:
X = Mx + u1 * t
Y = My + u2 * t
Dosadíme: X = 1000 + 3437 * t
Y = 700 + 2737 * t, z toho 2737 * t = Y – 700 a z toho t = ( Y – 700 ) / 2737
Rovnici t = ( Y – 700 ) / 2737 dosadíme do X = 1000 + 3437 * ( Y – 700 ) / 2737
Postupně zjednodušíme:
2737 * X = 2737000 + ( Y – 700 ) * 3437
2737 * X = 2737000 + 3437 * Y – 2405900
2737 * X = 3437 * Y + 331100 dělěno 20
137 * X = 172 * Y + 16555
Y je napětí, X je teplota, takže rovnice bude:
TempSolder = (unsigned int) ((( Primka1 * Mean ) + Primka2 ) / Primka3 ); Rozdil = TempSet - TempSolder;
Proměnná Primka1 = 172, Primka2 = 1655, Primka3 = 137.
Proměnná Rozdil zobrazuje regulační odchylku mezi požadovanou a naměřenou teplotou v desetinách stupně.
Přesnější rovnici sestavíme s pomocí teploměru a údaje z AD převodníku. V tomto okamžiku už je dobré mít naprogramovaný regulátor, aby se teplota na pájecím peru ustálila a z teploměru bylo možné přečíst stabilní údaj. Údaj z AD převodníku si zobrazíme na displeji pomocí funkce LCD_PrIntDec. Já tuto část naprogramoval v MENU_Global. Pro teploty 100°C a 400°C si opíšeme aktuální čísla z převodníku. Tyto čísla respektují vlastnosti konkrétního pájecího pera, konkrétního nastavení zesílení na vstupním operačním zesilovači a konkrétního referenčního napětí. Proto není důležité, mít referenční napětí a zesílení nastaveno na nějakou přesnou hodnotu. Ale je důležité nastavit dobře linearitu, to znamená, zkontrolovat údaje naměřené teploměrem na větším množství teplot. Hodnoty z AD převodníku dosadíme do rovnice přímky a vypočítáme nové konstanty Primka1, Primka2, Primka3.
LCD_Position( 0, 0 ); LCD_WriteCString( "U=" ); LCD_PrIntDec( Mean ); // napise napeti z prevodniku LCD_WriteCString( " " ); LCD_PrTemp( TempSolder ); // napise vypoctenou teplotu LCD_Position( 1, 0 ); LCD_PrTemp( TempMenu ); // nastavena teplota v MENU LCD_WriteCString( " " ); LCD_PrIntDec( LTC1286() ); LCD_WriteCString( " ");
Program PID regulátoru, nastavení a zobrazení PWM regulace
Srozumitenlý popis PID regulace je např. zde.
Hodinový kmitočet procesoru je 8MHz, kmitočet pro práci časovače T1 odpovídá hodinovému kmitočtu. Přerušení od časovače je nastaveno na 8000, to odpovídá kmitočtu 1000Hz a periodě 0,001s, s kterou bude spouštěn program přerušení časovače. PWM kanály reprezentované registry OCR1A a OCR1B mají tedy rozlišení 8000 dílků. Kanál B je použit pro ovládání piezoměniče, jeho střída je tedy nastavena na 50%. To odpovídá hodnotě OCR1B = 4000. Kanál A je použit pro ovládání výkonu pájecího pera, pro OCR1A = 0 bude výkon 0%, pro OCR1A = 8000 bude výkon 100%. Na displeji můžeme výkon zobrazovat po 1/80 = 0,0125 dílcích procenta. Já zobrazuji proměnnou SolderPWM / 8 s tím, že desetinná čárka je před číslicí nejnižšího řádu, tedy desetiny procenta.
Proporcionální regulace
Proporcionální složka regulace určuje aktuální výkon z rozdílu požadované a naměřené teploty. To jsou funkce:
Rozdil = TempSet – TempSolder
SolderPWM = (Rozdil * SolderPWM1 / 100)
První počítá velikost regulační odchylky a druhá počítá aktuální výkon tělesa. Konstanta SolderPWM1 je převzata z EEPROM a může být změněna v MENU. Pokud je její hodnota např. 3000, bude při rozdílu nastavené a naměřené teploty 10°K nastaven výkon 37,5% PWM regulace. Když bude rozdíl nastavené a naměřené teploty 1°K, bude výkon 10 * 3000 / 100 / 80 = 3,75%. Pokud bude regulační odchylka záporná, teplota tělesa bude větší než nastavená teplota, funkce if ( SolderPWM < 0 ) SolderPWM = 0; nastaví 0%.
Tento proporcionální regulátor lze prostřednictvím konstanty SolderPWM1 nastavit do dvou režimů: konstanta je velká, vypočteným výkonem bude překročena požadovaná teplota a napájení pájecího pera se odpojí. Teplota poklesne pod požadovanou hodnotu, znovu nastavený výkon překročí nastavenou teplotu… systém se rozkmitá kolem nastavené teploty. V druhém režimu je konstanta menší a nastavené teploty nebude po ustálení systému dosaženo, protože když je regulační odchylka nulová, je nulový i výkon pájecího pera a není čím pokrýt výkonové ztráty, které pero vyzáří do vzduchu, nebo předá ohřívané součástce.
Proporcionálním regulátorem jsem dosáhl stavu, kdy se teplota termočlánku přiblíží k nastavené, nebo kolem ní kmitá v rámci několika °C. Pro aplikaci pájecí stanice tohle stačí, teplota kovového tělesa a hrotu nestihne tak rychle kopírovat teplotu topného tělíska – bude stabilní. Další části programu regulátoru jsem napsal pro vlastní rozvoj a pro pozdější použití v jiných aplikacích.
Pro dosažení nastavené teploty s přesností na několik desetin stupně je potřeba k proporcionální složce přičíst integrační složku.
Integrační složka regulátoru
Integrace průběhu regulační odchylky v čase je realizována sčítáním regulačních odchylek jednotlivých měření. Tato složka je k proporcionální přičítána následovně:
SolderPWM = (Rozdil * SolderPWM1 / 100) + (IntegralRozdil * SolderPWM2 / 10000)
Složka v mém programu začne působit, až když je rozdíl nastavené a naměřené teploty menší, než 5°K. Když je teplota nízká, jede jenom proporcionální regulátor, když je naměřená teplota vysoká, regulátor odpojí napájení pájecího pera.
Pokud je rozdíl teplot v intervalu ( 0, +5°K ) bude při každém dalším měření zvýšena integrační složka, výkon tělesa se bude postupně zvětšovat.
Pokud je rozdíl teplot v intervalu ( -5°K, 0 ) bude při každém dalším měření snížena integrační složka, výkon tělesa se bude postupně snižovat.
Rychlost změny velikosti integrační složky v čase je dána velikostí konstanty SolderPWM2.
Při konstantní spotřebě tepla např. vyzářením do vzduchu se derivační + integrační složka regulátoru a tím i výkon tělesa za chvíli ustálí na velikosti, která je nutná k udržení požadované teploty.
V mém programu se integrační složka zvýší, nebo sníží vždy o jednotku, takže to není zrovna integrál průběhu regulační odchylky v čase. Správné by bylo přičítat vždy aktuální velikost regulační odchylky. Jenomže to se rozkmitávalo, tak jsem to změnil.
Nastavení výkonu PWM na základě vypočteného rozdílu mezi nastavenou a naměřenou teplotou
if (( Rozdil > 50 ) || ( Rozdil < -50 )) IntegralRozdil = 0; // rozdil teplot je vic nez 5 stupnu if (( Rozdil > -50 ) && ( Rozdil < 0 ) && ( IntegralRozdil > -200000 )) IntegralRozdil--; // rozdil je zaporny, slozka klesa if (( Rozdil > 0 ) && ( Rozdil < 50 ) && ( IntegralRozdil < 200000 )) IntegralRozdil++; // rozdil je kladny, slozka roste SolderPWM = (Rozdil * SolderPWM1 / 100) + (IntegralRozdil * SolderPWM2 / 10000); // * * * * * * * * * * * * * * * * * * vyhodnoti interval a nastavi PWM if ( SolderPWM < 0 ) SolderPWM = 0; if (( SolderPWM > 8000 ) || ( Rozdil > 400 )) SolderPWM = 8000; // rozdil je vic nez 40 stupnu, PWM bude 100% OCR1A = SolderPWM;
Přičtením integrační složky jsem dosáhl přesnějšího nastavení výkonu tak, aby teplota kmitala v rámci několika desetin °C, pokud je odběr tepla z pájecího pera stabilní. V okamžiku, kdy dojde ke změně množství odebíraného tepla, poklesne teplota pera. Až po poklesu teploty začne reagovat integrační složka, postupně přidávat výkon tělesa.
Derivační složka regulátoru
Derivací funkce získáme směrnici tečny ke grafu funkce. Čím rychleji funkce roste, tím větší bude hodnota derivace. Derivace bude mít zápornou hodnotu v místě, kde bude graf fuknce klesat. Funkcí, kterou se zabýváme, je průběh regulační odchylky (rozdíl požadované a naměřené teploty) v čase. Její derivace nám tedy řekne, jestli a jak rychle regulační odchylka roste, nebo klesá. Jinými slovy, z derivace funkce zjistíme, jak rychle se teplota pájecího pera přibližuje, nebo vzdaluje od nastavené hodnoty. Vynásobením vypočtené derivace s konstantou získáme derivační složku, která bude přičtena proporcionální a integrační složce:
SolderPWM = (Rozdil * SolderPWM1 / 100) + (IntegralRozdil * SolderPWM2 / 10000) + (DerivRozdil * SolderPWM3 / 10000)
Derivační složka zlepší vlastnosti regulátoru v okamžiku, kdy je změněna požadovaná teplota, nebo se změní výkon odebíraný z pera. V takové situaci začne integrační složka pomalu přičítat, nebo odečítat a pomalu měnit výkon vzhledem k nové situaci. Ale derivace hned na začátku spočítá, kterým směrem se mění situace (směrnice funkce) a podle toho změní dodávaný výkon.
A jak to realizovat v programu? Naměřená a zprůměrovaná hodnota z AD převodníku je Mean. Vždy před uložením nové hodnoty AD převodníku tu původní schovávám do MeanOld. Rozdíl regulační odchylky spočítané z Mean a odchylky spočítané z MeanOld je derivací funkce v tomto bodě.
Projekt napsaný v AVR studiu je ke ztažení zde: Pajeci_stanice 01.
8 komentářů: „Program PID regulátoru mikropájky“