Operácie

Riadenie sústavy 1. rádu: Rozdiel medzi revíziami

Z SensorWiki

(Vytvorená stránka „ '''Úloha 1:''' Odmerajte časový priebeh signálov pri nabíjaní kondenzátora C cez rezistor R. Z nameraného grafu určte hodnotu časovej konštanty T a spresnite…“)
 
(Regulácia sústavy)
 
(25 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 1: Riadok 1:
  
'''Úloha 1:''' Odmerajte časový priebeh signálov pri nabíjaní kondenzátora C cez rezistor R. Z nameraného grafu určte hodnotu časovej konštanty T a spresnite hodnoty R a C.
 
  
 
+
Azda najjednoduchší dynamický elektrický obvod je tvorený odporom a kondenzátorom. Takýto RC člen má výrazné filtračné účinky, používa sa napríklad na vyhladenie PWM priebehov, filtráciu vysokofrekvenčných zložiek signálu, ochranu kontaktov relé a pod. Veľa krát je vo funkcii filtra PWM signálu, je regulovaná sústava. To je náš prípad.
Azda najjednoduchší dynamický elektrický obvod je tvorený odporom a kondenzátorom. Takýto RC člen má výrazné filtračné účinky, používa sa napríklad na vyhladenie PWM priebehov, filtráciu vysokofrekvenčných zložiek signálu, ochranu kontaktov relé a pod.
 
  
 
<div style='text-align: center;'>
 
<div style='text-align: center;'>
Riadok 10: Riadok 8:
 
</div>
 
</div>
  
Schému zapojenia doplníme o označenie vstupných a výstupných signálov. Bude nás zaujímať, aký je presný priebeh napätia na kondenzátore C, ak náhle pripojíme na vstup napájacie napätie 5 Voltov. Je zrejmé, že kondenzátor sa bude nabíjať a že rýchlosť nabíjania bude závisieť od veľkosti rezistora R. Čim vyššia bude hodnota odporu, tým menší bude nabíjací prúd a tým dlhšie sa bude kondenzátor nabíjať. Podobná situácia bude platiť aj pre vybíjanie. Ale aký bude presný tvar nabíjacej krivky?  
+
Schému zapojenia doplníme o označenie vstupných a výstupných signálov. . Bude nás zaujímať priebeh napätia na kondenzátore po pripojení napätia 5V. Je zrejmé, že kondenzátor sa bude nabíjať a že rýchlosť nabíjania bude závisieť od veľkosti rezistora R. Čim vyššia bude hodnota odporu, tým menší bude nabíjací prúd a tým dlhšie sa bude kondenzátor nabíjať. Podobná situácia bude platiť aj pre vybíjanie. Ale aký bude presný tvar nabíjacej krivky? Nabíjacia krivka je vlastne prechodová charakteristika. Prepokladáme, že pripojený zdroj má prakticky nulový vnútorný odpor.
  
 
<div style='text-align: center;'>
 
<div style='text-align: center;'>
Riadok 37: Riadok 35:
 
</math></div>
 
</math></div>
  
kde <math>K=1</math> je tzv. ''zosilnenie'' obvodu a <math>T = RC</math> je tzv. ''časová konštanta''. Jej veľkosť určuje tvar a rýchlosť nabíjacej/vyníjacej krivky kondenzátora.
+
kde <math>K=1</math> je tzv. ''zosilnenie'' obvodu a <math>T = RC</math> je tzv. ''časová konštanta''. Jej veľkosť určuje tvar a rýchlosť nabíjacej krivky kondenzátora.  
 
+
 +
Pre opačný priebeh, t.j. vybíjanie kondenzátora, je potrebné na vstup pripojiť napätie 0 V, nestačí len rozpojiť spínač. Náboj musí niekam odtiecť, pri odpojení by ostal
 +
na kondenzátore. Tvar krivky pre vybíjanie je podobný, ale samozrejme jej matematický opis je trocha iný a naviac musíme započítať aj iné (nenulové) počiatočné podmienky.
 +
Pre naše meranie zabezpečíme pripojenie napätia aj jeho odpojenie a pripojenie na zem kvôli vybíjaniu pomocou jedného z digitálnych výstupov mikroprocesora. Pri stave
 +
log. 1 bude na vstupe (takmer) 5 V a naopak, pri log. 0 bude kondenzátor pripojený cez odpor R k zemi a tak sa bude môcť vybiť.
  
  
Riadok 56: Riadok 58:
  
 
teda na 63,2% z ustálenej hodnoty. To vieme vypočítať celkom presne, je to 0,632*5 = 3,16 V.
 
teda na 63,2% z ustálenej hodnoty. To vieme vypočítať celkom presne, je to 0,632*5 = 3,16 V.
Ak teda nájdenme na grafe hodnotu napätia  3,16 V, na časovej osi tomu zodpovedajúci čas je priamo hodnota T. Na obrázku vyššie je tento čas 2 sekundy, ale keďže skoková zmena na vstupe nastala v čase 1 sekunda, hodnota časovek konštanty je 2-1 = 1 sekunda.
+
Ak teda nájdeme na grafe hodnotu napätia  3,16 V, na časovej osi tomu zodpovedajúci čas je priamo hodnota T. Na obrázku vyššie je tento čas 2 sekundy, ale keďže skoková zmena na vstupe nastala v čase 1 sekunda, hodnota časovej konštanty je (2-1) = 1 sekunda.
 +
 
 +
 
 +
 
 +
== Identifikácia sústavy ==
 +
 
 +
 
 +
No a presne to treba spraviť aj pomocou vášho mikropočítača. Aby sme merania vedeli priradiť k reálnemu času, potrebujeme merania robiť s nejakou presnou periódou vzorkovania.
 +
Na to nám poslúži počítadlo T2, ktoré nastavíme tak, aby vyvolalo požiadavku o výpis hodnoty napätia na kondenzátore každých 10 ms. Samotné počítadlo bude generovať prerušenie každé 2 ms. Toto prerušenie použijeme ako “generátor” 10ms vzoriek a na opakované spustenie AD prevodu. <ref>Pravdepodobne zistíte, že 8-bitovým počítadlom T0 s kryštálom 16 MHz sa vám nepodarí nastaviť preddelič a register OCR na takú kombináciu, aby interval bol naozaj presne 10,00 ms. V rámci presnosti nášho merania to nevadí, ale je to principiálny problém. Buď by sme museli použiť 16-bitové počítadlo T1, alebo zmeniť hodnotu kryštálu napr. na 18,432 MHz, v takom prípade by nám čas vyšiel presne.</ref>. Teoretická hodnota časovej konštanty je 0,5 s. T.j.  Presnosť merania postačuje.
 +
Napätie na kondenzátore je merané nasledovným spôsobom: AD prevodník je nastavený na maximálnú možnú rýchlosť realizácie AD prevodu. Prevod je spustený v prerušení od T2, t.j. každé 2ms. Je povolené prerušenie od ukončenia AD prevodu.  V obsluhe prerušenia prečítame napätie na kondenzátore. Ak treba, môžeme ho aj, napr. Filtrom typu “kĺzavý priemer” filtrovať. Ak by sme merali viac AD kanálov nastavili by sme ďalší analógový vstup. Spustenie AD prevodu sa zase uskutoční v prerušení od T2 (každé 2 ms).
  
No a presne to treba spraviť aj pomocou vášho mikropočítača. Aby sme merania vedeli priradiť k reálnemu času, potrebujeme merania robiť s nejakou presnou periódou vzorkovania. Na to nám poslúži celkom dobre počítadlo T0, ktoré každých 10 ms vyvolá prerušenie. Takáto presnosť nám postačí<ref>Pravdepodobne zistíte, že 8-bitovým počítadlom T0 s kryštálom 16 MHz sa vám nepodarí nastaviť preddelič a register OCR na takú kombináciu, aby interval bol naozaj presne 10,00 ms. V rámci presnosti nášho merania to nevadí, ale je to principiálny problém. Buď by sme museli použiť 16-bitové počítadlo T1, alebo zmeniť hodnotu kryštálu napr. na 18,432 MHz, v takom prípade by nám čas vyšiel presne.</ref>. V obsluhe prerušenia zmeriame hodnotu napätia a pošleme ju po sériovej linke do PC, kde ju potom graficky znázorníme. Dobré bude, keď okrem napätia na kondenzátore budeme merať aj napätie na vstupe, aspoň uvidíme aká je jeho reálna hodnota (pomôcka: nebude to 5,0 V). Okrem toho by sme k týmto dvom hodnotám mali priradiť aj časový údaj. Na to si spravíme jednoduchú premennú, ktorú v každom prerušení inkrementujeme.  
+
Vzorový program predpokladá pripojenie 5V (pin D5) na RC člen. V takomto prípade by sme mohli vykreslovať aj meraný priebeh napätia nav stupe RC člena. My ale budeme vstupné napätie generovať ako PWM signal (Fast PWM MOD3 výstup na pin D5). T.j. bude vhodnejšie vykreslovať teoretický priebeh strednej hodnoty PWM signálu. Na začiatku nastavíme plnenie na nulu, čo odpovedá napätiu 0V a po 1 s zmeníme na plnenie odpovedajúce hodnote napr. 4V (plnenie nastavíme do  registra … ako číslo z intervalu (0 až 255)). Teoretický čas ustálenia napätia na kondenzátore je 5*T (časová konštanta RC člena -  T=R*C) Po tomto čase výpis cez sériový kanál na SERIAL PLOTER ukončíme. Ak by sme chceli opakovanie vykreslovať prechodovú charakteristiku, musíme najskôr kondenzátor vybiť. To sad á napr. Tak, že pripojíme malý resistor, napr. 330Ohm cez pin D4. Ten na začiatku nastavíme ako výstupný na hodnotu LOW. V okamžiku začatia generovania PWM signálu pin D4 nastavíme ako vstupný a vybíjanie tým ukončíme. Keďže potrebujeme poznať čas ( násobok 10ms)  budeme na základe info s T2 inkrementovať premenú, ktorá bude načítavať  údaj o čase.   Je vhodné do grafu okrem napätia na kondenzátore vykreslovať ustálenú hodnotu a hodnotu odpovedajúcu “časovej konštante”. Vykreslovať môžeme realizovať v rozsahu 0 až 5V, resp. v rozsahu AD prevodníka 0 až 1023, resp. v tzv. MU rozsah 0 až 1.
  
Z teoretickej analýzy vieme odhadnúť, že na celé meranie nám bude stačiť 10 sekúnd a preto po ich uplynutí meranie ukončíme, aby sme graf nemuseli zastavovať na PC odadom od ruky.
+
<div style='text-align: center;'>
 +
[[Súbor:RC-schema3.png|350px]]<BR>
 +
''Schéma zapojenia pre identifikáciu aj reguláciu.''
 +
</div>
  
  
  
<!--
+
'''Úloha 1:''' Odmerajte časový priebeh signálov pri nabíjaní kondenzátora C cez rezistor R. Z nameraného grafu určte hodnotu časovej konštanty T a spresnite hodnoty R a C.
  
Tuto je nejaky text s odkazom na literaturu o Arduine
 
<ref group="REF">[http://ARDUINO_V2.pdf Arduino UNO V3 pinout]</ref>
 
a tuto pokracuje iny text, kde chcem len uviest malu poznamku
 
<ref>Číslo portu zistíte z Device Managera.</ref>
 
-->
 
  
Zdrojovy kod pre AVRGCC a ARDUINO
+
Zdrojové kódy pre AVRGCC
 
------------------------------------
 
------------------------------------
 +
 +
'''POZN.:''' 
 +
* Projekt otvorte cez šablónu MIPS a okrem nového <code>main.c</code> si pridajte aj oba súbory <code>p_f_1.h</code> a <code>p_f_1.c</code>
 +
* V nastaveniach projektu je potrebné zmeniť rýchlosť z pôvodnej hodnoty 9600 na 115200 cez <code>Project -> Properties -> Toolchain -> Symbols -> BAUD = 115200</code>
 +
* Výstup programu sledujeme v programe '''SerialPlot''', treba tam nastaviť rýchlosť na 115200, počet kanálov na 4, data oddelené čiarkou a počet bodov pre graf 500.
 +
* Aby sa vám ľahšie odčítali potrebné hodnoty, vykreslujeme okrem napätia na kondenzátore aj aktuálny čas, ustálenú hodnotu a 63% ustálenej hodnoty. Posledné dve veličiny však musíte najprv v programe správne vypočítať.
  
 
<tabs>
 
<tabs>
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;">
+
<tab name="main.c"><source lang="c++" style="background: LightYellow;">
/* **********************************************************
+
/*
 +
* Cvicenie 12 - RC identifikacia
 +
*  
 +
* Definicie:
 +
*             ATmega328P
 +
*             F_CPU 16000000UL
 +
*             BAUDRATE 115200
 
  *
 
  *
  * Hruba kostra programu na identifikaciu parametrov RC clena
+
  * Pripojenie:
  *  
+
  *               D5 cez R 10k pripoj C 47 uF na zem
  * Odpor je pripojeny a) na niektory digitalny vystup
+
  *               D4 cez cca 330 ohm pripoj na C
  *                   b) zaroven na analogovy vstup
+
  *               A0 pripoj na C
  * Kondenzator je pripojeny na iny analogovy vstup
+
  *               GND pripoj na zaporny pol C
* Okrem merania dvoch velicin mame premennu sysTime, ktoru
 
* kazdych 10ms inkrementujeme a tak "meriame cas".
 
* Namerane udaje odosielame ako trojicu cas,input,output\n\
 
* po seriovej linke rychlostou min. 19200 Bd do PC, kde si
 
* hodnoty zobrazime graficky.
 
 
  *
 
  *
  * Pozor: toto je len kostra, ktoru musite doplnit spravnymi
+
  * Konfiguracia:
  * konfiguracnymi parametrami, aby to fungovalo!
+
  *               SerialPlot 500 krokov. 115200 Baud
 
  *
 
  *
  ************************************************************ */
+
  */  
+
 
#include <stdio.h>
 
 
#include <avr/io.h>
 
#include <avr/io.h>
#include <avr/interrupt.h>
+
#include "p_f_1.h"            // pomocne funkcie pre toto cvicenie
 +
 
 
#include "uart.h"
 
#include "uart.h"
#include "adc.h"
+
#undef  BAUD_RATE            // chceme rychlejsiu komunikaciu
 +
#define BAUD_RATE 115200
  
 +
#include <stdio.h>            // a tiez pouzivat printf
 +
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
 +
                             
 +
                             
 +
int main(void)
 +
{
 +
  hw_init();
 +
  uart_init();
 +
  stdout = &mystdout;          // printf() works from now
  
#define RCinput          // Digitalny (budiaci) vstup RC clena
+
  /* 0. Toto je uloha pre studentov    */
#define vIn           // Analogovy vstup RC clena
+
  unsigned int y_oo = 0;        // tu nahradte hodnotu vypocitanou pre ADC zodpovedajuce ustalenej hodnote 4V
#define vOut              // Analogovy vystup RC clena
+
  unsigned int y_63 = 0;        // tu nahradte hodnotu vypocitanou pre 63 ustalenej
 +
 
  
unsigned volatile static int sysTime=0;
+
 
 +
    /*  1. Najprv vybijeme kondenzator: */
 +
set_bit(DDRD,pinB );      // Pin nastavime ako vystupny
 +
clear_bit(PORTD,pinB);    // a dame tam log. 0
  
  
/* Prerusenie od casovaca T0 kazdych 10 ms */
+
    /* 2. Pokracujeme incializaciou:  */
 +
    ini_TC2();                // Tv_zaklad = 2ms, v preruseni x5 = 10ms
 +
ini_PWM();           
 +
adc_init();
 +
sei();                    // Povolenie preruseni, aby to vsetko slapalo
  
ISR (TIMER0_COMPA_vect)          
+
while(1)
{  
+
{
     sprintf(outString,"%d,%d,%d\n",sysTime, adc_read(vIn),adc_read(vOut));  
+
    uart_puts(outString);
+
    /* 3. pockame az do casu 1.0 s aby sme vybili kondenzator */ 
sysTime++;
+
if (poc_time == 100 )     // 100 x 10ms = 1 sekunda
 +
{
 +
        clear_bit(DDRD,pinB);  // Pin odpojime, t.j. input, "odstranim skrat"
 +
OCR0B = 204;          // a na vystup poslem PWM, ktore zodpoveda 4V
 +
}
 +
 +
 +
/* 4. a teraz od 0.0 az po 5.0 sec sledujeme napatie na C */
 +
 +
if( (flag_T_v)&&(poc_time<500 ))
 +
{                                        // 400 * Tv = 5s; 6*T + T + 1s;  chyba  == cca 2-promile
 +
flag_T_v = 0;       
 +
                                        // Vypiseme: aktualny cas, napatie na kondenzatore a dve pomocne veliciny 
 +
printf("%u,%u,%u,%u\r\n",poc_time,y_C,y_oo,y_63); // ako dekadicke hodnoty
 +
}
 +
 +
// po uplynuti 5 sekund uz nerobime nic
 +
     
 +
  }
  
 +
 
 +
  return(0);
 
}
 
}
 +
 +
 +
 +
 +
</source></tab>
 +
<tab name="p_f_1.h"><source lang="c++" style="background: LightYellow;">
 +
/*
 +
* p_f_1.h
 +
*
 +
*  Pomocne funkcie na cvicenie 12 s RC clenom
 +
*  Date: 30. 04. 2024
 +
*  Author: S. Chamraz
 +
*/
 +
 +
#ifndef P_F_1_H_
 +
#define P_F_1_H_
 +
 +
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
#include <stdio.h>
 +
 +
#define toggle_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
 +
 +
#define con_T_v  5-1 // T_v = 10 ms  (5 * 2ms) - vypis  kazdych 10ms
 +
 +
// port D
 +
#define  pinA 5 // skok 5,0V, 
 +
#define  pin_PWM 5 // resp. PWM
 +
#define  pinB 4 // vybijanie kondenzatora
 +
 +
 +
void ini_TC2(void);
 +
void ini_PWM(void);
 +
void adc_init(void);
 +
 +
 +
#define f_opak_TC2 500 // 500 Hz -> 2ms
 +
#define N_D_TC2 128 // Delic = 128
 +
#define OCR2A_f_opak_TC2 F_CPU/f_opak_TC2/N_D_TC2 - 1 // Vysledkom je 2ms casova vzorka !!!!!
 +
 +
extern volatile int poc_time ; // prirastok 10ms
 +
 +
extern volatile int y_C ;  // u_C = y_C; 
 +
 +
extern volatile unsigned char flag_T_v ;
 +
extern volatile unsigned char poc_T_v;
 +
 +
//unsigned char vyk_w_zel = 0;
 +
                         
 +
extern volatile unsigned char poc_T_vypis; // vypis aj v nultej vzorke
 +
//extern volatile unsigned char flag_Vypisov;
 +
 +
 +
#endif /* P_F_1_H_ */
 +
 +
</source></tab>
 +
<tab name="p_f_1.c"><source lang="c++" style="background: LightYellow;">
 +
/*
 +
* p_f_1.c
 +
*
 +
*  Pomocne funkcie na cvicenie 12 s RC clenom
 +
*  Date: 30. 04. 2024
 +
*  Author: S. Chamraz
 +
*/
 +
 +
#include "uart.h"
 +
#include "p_f_1.h"
 +
volatile int poc_time = 0; // prirastok 10ms
 +
volatile int y_C = 0;  // u_C = y_C; 
 +
 +
volatile unsigned char flag_T_v = 0;
 +
volatile unsigned char poc_T_v = 0;
 +
 +
 +
void ini_PWM(void)                            // T0 (D6) budeme pouzivat ako "analogovy" vystup
 +
{
 +
    OCR0B  = 0;
 +
TCCR0A = (1<<COM0B1)|(0<<COM0B0)          // Turn output off when TCNT0 >= OCR0B
 +
              |(1<<WGM01)|(1<<WGM00);        // Select Fast PWM Mode       
 +
    TCCR0B = (0<<CS02)|(1<<CS01)|(1<<CS00);    // fopak = cca 1kHz
 +
    DDRD  |= (1<<pin_PWM);           // output  PD5
 +
 +
}
 +
 +
 +
void ini_TC2(void)
 +
{                                           //  Nastavenie TC2
 +
                                          // 7 6        5 4        3 2    1 0
 +
                                          // COM2A[1:0]  COM2B[1:0]  - -   WGM2[1:0]
 +
TCCR2A = 0b00000011;                   // OC2B  PWM mod = 7
 +
TCCR2B = 0b00001101;                   // fosc/128
 +
 +
OCR2A = OCR2A_f_opak_TC2;                  // nastavenie frekvencie opakovania na 2ms
 +
TIMSK2  = (1<<TOIE2);                      // Enable interrupts @ overflow TC2 MOD 7
 +
}
 +
 +
 +
ISR(TIMER2_OVF_vect)                         
 +
{                                        // toto sa vykona kazde 2,0ms
 +
set_bit(ADCSRA,ADSC);                //  spustenie dalsieho prevodu ADSC = TRUE
 
 
 +
if (!poc_T_v)
 +
{ flag_T_v = 1; // priznak vypoctu PI reg.
 +
toggle_bit(PORTB,LED);
 +
        poc_time++;
 +
poc_T_v = con_T_v;
 +
}
 +
else poc_T_v--;
 +
}
 +
 +
void adc_init(void){
 +
ADMUX = (0<<REFS1)|(1<<REFS0); // AVCC - nastavenie zdroja ref. napatia
 +
ADCSRA = (1<<ADEN) // "zapnutie" ADC
 +
            |(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // nastavenie preddelica
 +
                                    // fADC = 125kHz
 +
                                    // trvanie jedneho prevodu cca 0,1ms
 +
                                    // zarovnanie doprava
 +
ADMUX = (ADMUX & 0xF8); // nastavenie kanalu AD0
 +
ADCSRA |= (1<<ADSC)|(1<<ADIE); // spustenie prevodu, povolenie prerusenia od AD
 +
}
 +
 +
ISR(ADC_vect){
 +
                                            // precitanie AD prevodu kanal 0;
 +
                                            // ak treba tu nastavíme dalsi kanal
 +
                                            // a spustíme az v preruseni od TC2
 +
                                            // a vycitame posledne ukonceny prevod
 +
y_C = ADC;                                  // precitanie AD0
 +
}
 +
 +
 +
</source></tab>
 +
<tab name="Arduino code"><source lang="arduino" style="background: #9dd1e1;">
 +
 +
/* Arduino code az niekedy inokedy */
 +
 +
 +
</source></tab>
 +
</tabs>
 +
 +
 +
<div style='text-align: center;'>
 +
[[Súbor:RC-SerialPlot01.png|800px]]<BR>
 +
''Výstup zo “SerialPtot“ by mohol vyzerať takto.''
 +
</div>
 +
 +
== Regulácia sústavy ==
 +
 +
V druhej časti cvičenia bude našou snahou vytvoriť regulátor, ktorý bude udržiavať napätie na výstupe (t.j. na kondenzátore) na požadovanej hodnote a to aj pri zmene záťaže. Na podobnom princípe pracujú aj spínané zdroje, ktoré sa využívajú vo všetkých možných oblastiach.
 +
 +
 +
Zdrojové programy upravíme tak, aby sme mohli regulovať napätie na kondenzátore. Najskôr pomocou P regulátora.  Na začiatku treba povedať, že vstupom regulátora sú <math>w_{zel}</math> a <math>y_C</math> v rozsahu 0 až 1023. Výstup (plnenie PWM signálu) je z rosahu  (0 až 255)). To znamená, že ak chceme nastaviť zosilnenie P regulátora na hodnotu <math>K_P</math>, musí tomu odpovedať rovnica:
 +
 +
<math>
 +
          m_{reg} (nT_v) =  (  e(nT_v) K_P )/4;
 +
</math>
 +
kde  <math> 4 = 1024/256 </math>.
 +
 +
Regulačnú odchýlku počítame podľa vzťahu
 +
<math>
 +
        e(nT_v) = w_{zel}(nT_v) - y_C(nT_v);
 +
</math>
 +
 +
Samozrejme nesmieme zabudnúť na obmedzenie akčného zásahu (min = 0 a max = 255).
 +
 +
Na “pozadí” beží spojitý čas <code>timeVal</code> a my z neho využívame len disktretne vzorky, teda
 +
<math>
 +
        timeVal = n*T_v =  poc_{time}*T_v.
 +
</math>
 +
 +
V programe použíjeme namiesto <math>n</math> premennú <code>poc_time</code> typu int.
 +
 +
Môžeme to povedať, aj tak, že regulovaný system  mimo týchto okamžikov pracuje “v otvorenej slučke”. Perióda vzorkovania <math>T_v</math> musí byť dostatočne malá, aby sa stav systému medzi vzorkami zmenil len nepatrne. V zhode s prednáškou vyhovuje <math> T_v = 10</math> ms. Ak by sme použili PI, resp. PS regulátor, bolo by vhodné nastaviť samostatnú periódu vzorkovania pre zbiehanie PS algoritmu a samostatnú pre výpis priebehu regulovanej veličiny, akčného zásahu, želanej veličiny,... 
 +
 +
 +
<div style='text-align: center;'>
 +
[[Súbor:RC-SerialPlot02.png|800px]]<BR>
 +
''Výstup zo “SerialPtot“ pre P regulátor so zosilnením 5 by mohol vyzerať takto.''
 +
</div>
  
void timer0_init(void)  /* Mode 2: clear on CTC match */
 
{
 
TCCR0A =
 
    TCCR0B =
 
OCR0A =            // Nastav periodu 10ms
 
TCNT0  =            // Vynuluj pocitadlo
 
TIFR0  =  // Clear CTC flag
 
  TIMSK0  =            // Enable Overflow Interrupt
 
}
 
  
 +
Pri realizáci P-regulátora využijeme program, ktorý sme vytvorili vyššie na identifikáciu parametrov sústavy. Musíme do neho doprogramovať samotný
 +
regulátor, viď nižšie. Keďže hodnoty sa aktualizujú mimo funkcie v prerušení od časovača, všetky premenné sú globálne (deklarované mimo tela funkcie)
 +
a tie, ktoré meníme v prerušení navyše ako typ volatile. Definícia funkcie patrí ešte '''pred''' funkciu main.
  
void hw_init(void)
+
<tabs>
{
 
/* tu nastavite spravne vstupy a vystupy */
 
}
 
  
 +
<tab name="P_regulator.c"><source lang="c++" style="background: LightYellow;">
  
 +
int K_P = 1; // P zlozka regulatora: 1,2,3 max. 10
 +
 +
int e_reg = 0;          // e - regulacna odchylka
 +
int w_zel = 0;          // w - zelana hodnota
 +
int u_reg = 0;          // u - akcny zasah
  
int main(void)
+
/*    Jednoduchy  P-regulator                          *
{    
+
*                                                      *
   cli();                  // cez inicializaciu zakazeme prerusenia
+
*    Kedze pocitame vsetky veliciny v rozsahu 0-1023   *
    
+
*   ale PWM je len 8-bitove, musime napokon vysledok  *
   hw_init();
+
*   prepocitat do rozsahu 0-255 a taktiez ak nam vy-  *
   uart_init(57600);      
+
*   sledok vyjde viac ako 255 alebo menej ako 0, tak  *
  timer0_init();
+
*   ho musime obmedzit.                              *
  adc_init();  
+
*                                                      */
 +
void P_reg(void)                
 +
{                                // Regulator: vypocty
 +
e_reg = w_zel - y_C;         // regulacna odchylka e = w - y
 +
u_reg = K_P*e_reg;           // akcny zasah        u = K*e
 +
u_reg = u_reg>>2 ;           // 0-1023 do rozsahu  0-255
 
 
  sei();  
+
if (u_reg <  0 ) u_reg = 0; // limiter
 
+
if (u_reg > 255 )  u_reg = 255;
  while(1)
+
 
    {
+
OCR0B  = u_reg ;         // a napokon 'u' posleme von
 +
}
 +
 
 +
 
 +
</source></tab>
 +
</tabs>
 +
 
 +
 
 +
Hlavnú programovú slučku potom doplníme nasledovne:
 +
* (11) v čase 1 s ( v programe 100, t.j. vtedy, keď vybijeme kondenzátor na 0V ) nastavíme hodnotu želanej veličiny na 800
 +
* (14-18) v čase 3,5 s ( v programe 350, to musíme ešte doplniť)  nastavíme hodnotu želanej veličiny na 600
 +
* (27) do slučky treba doplniť samotné volanie funkcie <code>P_reg();</code>, ktorý vypočíta regulačnú odchylku a zmení akčný zásah.
 +
* (30) navyše by bolo dobré zmeniť vykreslované hodnoty, a namiesto veličín y_oo a y_63 si vypísať (a vykresliť) aktuálnu hodnotu želanej hodnoty w_zel a akčného zásahu u_reg.
  
//     Part 1: identification of the system
+
<tabs>
 +
<tab name="P_regulator.c"><source lang="c++" line style="background: LightYellow;" highlight="11,14-18,27,30">
 +
... 
 +
while(1)
 +
  {
 +
 +
    /* 3. pockame az do casu 1.0 s aby sme vybili kondenzator */ 
 +
if (poc_time == 100 )      // 100 x 10ms = 1 sekunda
 +
{
 +
        clear_bit(DDRD,pinB);  // Pin odpojime, t.j. input, "odstranim skrat"
 +
OCR0B = 204;          // a na vystup poslem PWM, ktore zodpoveda 4V
 +
 +
w_zel = 800;
 +
}
 +
  
if ( sysTime == 100)         // v prvej sekunde
+
if (poc_time == 350 )     // 100 x 10ms = 1 sekunda
          set_bit(PORTx,RCinput);    // start charge
 
 
if ( timeVal == 600)          // v siestej sekunde
 
          clear_bit(PORTx,RCinput);  // start dischg
 
 
if (timeVal>1000)            // po 10 sekundach STOP
 
 
{
 
{
          cli();
+
w_zel = 600;
  while(1);  /* stop here forever, end of experiment */ 
 
 
}
 
}
 
 
        //nothing to do here, everything else is in ISR
+
    }
+
/* 4. a teraz od 0.0 az po 5.0 sec sledujeme napatie na C */
}
+
 +
if( (flag_T_v)&&(poc_time<500 ))
 +
{                                                     
 +
                  flag_T_v = 0;       
  
</source></tab>
+
                  P_reg();                                              // Zavolame regulator
<tab name="Arduino code"><source lang="arduino" style="background: #9dd1e1;">
 
  
/* Arduino code nabuduce */
+
                                                                        // Vypiseme: aktualny cas, napatie na kondenzatore a dve pomocne veliciny 
 +
                  printf("%u,%u,%u,%u\r\n",poc_time,y_C,u_reg,w_zel); // ako dekadicke hodnoty
 +
}
 +
 +
// po uplynuti 5 sekund uz nerobime nic
 +
     
 +
  }
 +
...
  
 
</source></tab>
 
</source></tab>
 
</tabs>
 
</tabs>
  
 +
'''Úloha 2:'''
 +
 +
# Realizovať regulator pre K_P = 1, 2,3 a porovnať teoretickú a skutočnú trvalú regulačnú odchýlku.
 +
# Akým skutočným napätiam zodpovedajú hodnoty 800 a 600? Overte meraním pomocou multimetra.
 +
# Ak sa niekomu podarí doplniť aj I zložku regulátora môže pripojiť aj záťaž regulovaného systému. Viď. prednáška.
 +
 +
 +
'''Poznámka:''' Pre jednotkový skok vieme vypočítať veľkosť trvalej regulačnej odchýlky v ustálenom stave pre uzavretý regulačný obvod so sústavou prvého rádu (K, T) a P-regulátor (K_P) vypočítať podľa vzťahu
 +
 +
 +
 +
<html>
 +
<!-- math>e_\infty = 1 - \frac{K_P*K}{1+K_P*K}</math -->
 +
 +
<math display="block" class="tml-display" style="display:block math;">
 +
  <mrow>
 +
    <msub>
 +
      <mi>e</mi>
 +
      <mi>∞</mi>
 +
    </msub>
 +
    <mo>=</mo>
 +
    <mn>1</mn>
 +
    <mo>−</mo>
 +
    <mfrac>
 +
      <mrow>
 +
        <msub>
 +
          <mi>K</mi>
 +
          <mi>P</mi>
 +
        </msub>
 +
        <mo>⋅</mo>
 +
        <mi>K</mi>
 +
      </mrow>
 +
      <mrow>
 +
        <mn>1</mn>
 +
        <mo>+</mo>
 +
        <msub>
 +
          <mi>K</mi>
 +
          <mi>P</mi>
 +
        </msub>
 +
        <mo>⋅</mo>
 +
        <mi>K</mi>
 +
      </mrow>
 +
    </mfrac>
 +
  </mrow>
 +
</math>
 +
 +
 +
</html>
 +
 +
 +
Samozrejme, že podkladové programy nie sú napísané dokonale. Študenti môžu programy upravovať a vylepšovať. Napr.:  AntiWindUpReset, Ručné riadenie, Zmena w_zel pomocou potenciometra, …
  
 
== Literatúra ==
 
== Literatúra ==

Aktuálna revízia z 10:35, 2. máj 2024


Azda najjednoduchší dynamický elektrický obvod je tvorený odporom a kondenzátorom. Takýto RC člen má výrazné filtračné účinky, používa sa napríklad na vyhladenie PWM priebehov, filtráciu vysokofrekvenčných zložiek signálu, ochranu kontaktov relé a pod. Veľa krát je vo funkcii filtra PWM signálu, je regulovaná sústava. To je náš prípad.

RC-modul.jpgRC-schema1.png
Komerčný modul na ochranu kontaktov relé a jeho schéma zapojenia (RC obvod).

Schému zapojenia doplníme o označenie vstupných a výstupných signálov. . Bude nás zaujímať priebeh napätia na kondenzátore po pripojení napätia 5V. Je zrejmé, že kondenzátor sa bude nabíjať a že rýchlosť nabíjania bude závisieť od veľkosti rezistora R. Čim vyššia bude hodnota odporu, tým menší bude nabíjací prúd a tým dlhšie sa bude kondenzátor nabíjať. Podobná situácia bude platiť aj pre vybíjanie. Ale aký bude presný tvar nabíjacej krivky? Nabíjacia krivka je vlastne prechodová charakteristika. Prepokladáme, že pripojený zdroj má prakticky nulový vnútorný odpor.

RC-schema2.png
Jednoduchý RC obvod s doplneným označením veličín.

V elektrickom obvode podľa obrázku podľa Kirchoffovho zákona platí, že súčet napätí v uzavretej slučke je nulový:


  u_{in}(t) - R i(t) - u_{out}(t) = 0,

kde i(t) je prúd v slučke a R je odpor rezistora, pričom pre výstupné napätie u_{out} ďalej platí


  u_{out}(t) = \frac{1}{C} \int_{0}^{t} i(t) dt,

kde C je kapacita kondenzátora.


Po zohľadnení počiatočných podmienok dostaneme riešením diferenciálnej rovnice pre skokovú zmenu vstupného napätia u_{in} z hodnoty 0 na U_0 v čase t=0 nasledovný priebeh výstupného napätia u_{out}:


   u_{out}(t) = U_{0} K (1-e^{-t/T})

kde K=1 je tzv. zosilnenie obvodu a T = RC je tzv. časová konštanta. Jej veľkosť určuje tvar a rýchlosť nabíjacej krivky kondenzátora.

Pre opačný priebeh, t.j. vybíjanie kondenzátora, je potrebné na vstup pripojiť napätie 0 V, nestačí len rozpojiť spínač. Náboj musí niekam odtiecť, pri odpojení by ostal na kondenzátore. Tvar krivky pre vybíjanie je podobný, ale samozrejme jej matematický opis je trocha iný a naviac musíme započítať aj iné (nenulové) počiatočné podmienky. Pre naše meranie zabezpečíme pripojenie napätia aj jeho odpojenie a pripojenie na zem kvôli vybíjaniu pomocou jedného z digitálnych výstupov mikroprocesora. Pri stave log. 1 bude na vstupe (takmer) 5 V a naopak, pri log. 0 bude kondenzátor pripojený cez odpor R k zemi a tak sa bude môcť vybiť.


RC-simulaciaT.png
Časové priebehy vstupného (modrá) a výstupného (červená) napätia - simulácia.


Ako z nameraného priebehu zistíme časovú konštantu? Zabudnite na poučky o dotyčnici v počiatočnom bode...

Pozrime sa, na akú hodnotu stihne vystúpiť napätie za čas rovný presne jednej časovej konštante. Ak do funkcie pre priebeh výstupného napätia dosadíme za čas t = T, dostaneme


   u_{out}(T) = U_{0} K (1-e^{-T/T})  = U_{0} K (1-e^{-1})  = 0,632 U_{0} K

teda na 63,2% z ustálenej hodnoty. To vieme vypočítať celkom presne, je to 0,632*5 = 3,16 V. Ak teda nájdeme na grafe hodnotu napätia 3,16 V, na časovej osi tomu zodpovedajúci čas je priamo hodnota T. Na obrázku vyššie je tento čas 2 sekundy, ale keďže skoková zmena na vstupe nastala v čase 1 sekunda, hodnota časovej konštanty je (2-1) = 1 sekunda.


Identifikácia sústavy

No a presne to treba spraviť aj pomocou vášho mikropočítača. Aby sme merania vedeli priradiť k reálnemu času, potrebujeme merania robiť s nejakou presnou periódou vzorkovania. Na to nám poslúži počítadlo T2, ktoré nastavíme tak, aby vyvolalo požiadavku o výpis hodnoty napätia na kondenzátore každých 10 ms. Samotné počítadlo bude generovať prerušenie každé 2 ms. Toto prerušenie použijeme ako “generátor” 10ms vzoriek a na opakované spustenie AD prevodu. [1]. Teoretická hodnota časovej konštanty je 0,5 s. T.j. Presnosť merania postačuje. Napätie na kondenzátore je merané nasledovným spôsobom: AD prevodník je nastavený na maximálnú možnú rýchlosť realizácie AD prevodu. Prevod je spustený v prerušení od T2, t.j. každé 2ms. Je povolené prerušenie od ukončenia AD prevodu. V obsluhe prerušenia prečítame napätie na kondenzátore. Ak treba, môžeme ho aj, napr. Filtrom typu “kĺzavý priemer” filtrovať. Ak by sme merali viac AD kanálov nastavili by sme ďalší analógový vstup. Spustenie AD prevodu sa zase uskutoční v prerušení od T2 (každé 2 ms).

Vzorový program predpokladá pripojenie 5V (pin D5) na RC člen. V takomto prípade by sme mohli vykreslovať aj meraný priebeh napätia nav stupe RC člena. My ale budeme vstupné napätie generovať ako PWM signal (Fast PWM MOD3 výstup na pin D5). T.j. bude vhodnejšie vykreslovať teoretický priebeh strednej hodnoty PWM signálu. Na začiatku nastavíme plnenie na nulu, čo odpovedá napätiu 0V a po 1 s zmeníme na plnenie odpovedajúce hodnote napr. 4V (plnenie nastavíme do registra … ako číslo z intervalu (0 až 255)). Teoretický čas ustálenia napätia na kondenzátore je 5*T (časová konštanta RC člena - T=R*C) Po tomto čase výpis cez sériový kanál na SERIAL PLOTER ukončíme. Ak by sme chceli opakovanie vykreslovať prechodovú charakteristiku, musíme najskôr kondenzátor vybiť. To sad á napr. Tak, že pripojíme malý resistor, napr. 330Ohm cez pin D4. Ten na začiatku nastavíme ako výstupný na hodnotu LOW. V okamžiku začatia generovania PWM signálu pin D4 nastavíme ako vstupný a vybíjanie tým ukončíme. Keďže potrebujeme poznať čas ( násobok 10ms) budeme na základe info s T2 inkrementovať premenú, ktorá bude načítavať údaj o čase. Je vhodné do grafu okrem napätia na kondenzátore vykreslovať ustálenú hodnotu a hodnotu odpovedajúcu “časovej konštante”. Vykreslovať môžeme realizovať v rozsahu 0 až 5V, resp. v rozsahu AD prevodníka 0 až 1023, resp. v tzv. MU rozsah 0 až 1.

RC-schema3.png
Schéma zapojenia pre identifikáciu aj reguláciu.


Úloha 1: Odmerajte časový priebeh signálov pri nabíjaní kondenzátora C cez rezistor R. Z nameraného grafu určte hodnotu časovej konštanty T a spresnite hodnoty R a C.


Zdrojové kódy pre AVRGCC


POZN.:

  • Projekt otvorte cez šablónu MIPS a okrem nového main.c si pridajte aj oba súbory p_f_1.h a p_f_1.c
  • V nastaveniach projektu je potrebné zmeniť rýchlosť z pôvodnej hodnoty 9600 na 115200 cez Project -> Properties -> Toolchain -> Symbols -> BAUD = 115200
  • Výstup programu sledujeme v programe SerialPlot, treba tam nastaviť rýchlosť na 115200, počet kanálov na 4, data oddelené čiarkou a počet bodov pre graf 500.
  • Aby sa vám ľahšie odčítali potrebné hodnoty, vykreslujeme okrem napätia na kondenzátore aj aktuálny čas, ustálenú hodnotu a 63% ustálenej hodnoty. Posledné dve veličiny však musíte najprv v programe správne vypočítať.
/*
 * Cvicenie 12 - RC identifikacia
 * 
 * Definicie:
 *              ATmega328P
 *              F_CPU 16000000UL
 *              BAUDRATE 115200
 *
 * Pripojenie: 
 *                D5 cez R 10k pripoj C 47 uF na zem
 *                D4 cez cca 330 ohm pripoj na C
 *                A0 pripoj na C
 *                GND pripoj na zaporny pol C
 *
 * Konfiguracia:
 *                SerialPlot 500 krokov. 115200 Baud
 *
 */ 

#include <avr/io.h>
#include "p_f_1.h"            // pomocne funkcie pre toto cvicenie

#include "uart.h"
#undef  BAUD_RATE             // chceme rychlejsiu komunikaciu 
#define BAUD_RATE 115200

#include <stdio.h>            // a tiez pouzivat printf
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
                              
							                              
int main(void)
{
   hw_init();
   uart_init();
   stdout = &mystdout;           // printf() works from now

   /* 0. Toto je uloha pre studentov    */
   unsigned int y_oo = 0;        // tu nahradte hodnotu vypocitanou pre ADC zodpovedajuce ustalenej hodnote 4V
   unsigned int y_63 = 0;        // tu nahradte hodnotu vypocitanou pre 63 ustalenej
   

   
    /*  1. Najprv vybijeme kondenzator: */
	set_bit(DDRD,pinB );       // Pin nastavime ako vystupny
	clear_bit(PORTD,pinB);     // a dame tam log. 0


    /* 2. Pokracujeme incializaciou:   */
    ini_TC2();                 // Tv_zaklad = 2ms, v preruseni x5 = 10ms
	ini_PWM();             
 	adc_init();
 	sei();                     // Povolenie preruseni, aby to vsetko slapalo

	while(1)
	{
	
	    /* 3. pockame az do casu 1.0 s aby sme vybili kondenzator */  
		if (poc_time == 100 )      // 100 x 10ms = 1 sekunda
		{
        	clear_bit(DDRD,pinB);  // Pin odpojime, t.j. input, "odstranim skrat"
			OCR0B = 204;           // a na vystup poslem PWM, ktore zodpoveda 4V 
		}
					
		
		/* 4. a teraz od 0.0 az po 5.0 sec sledujeme napatie na C */
		
		if( (flag_T_v)&&(poc_time<500 ))
		{                                        // 400 * Tv = 5s; 6*T + T + 1s;  chyba  == cca 2-promile
			flag_T_v = 0;        
		                                         // Vypiseme: aktualny cas, napatie na kondenzatore a dve pomocne veliciny  
			printf("%u,%u,%u,%u\r\n",poc_time,y_C,y_oo,y_63); 	// ako dekadicke hodnoty
		} 
		
		// po uplynuti 5 sekund uz nerobime nic
				       									
  }

  
  return(0);
}
/*
 * p_f_1.h
 *
 *  Pomocne funkcie na cvicenie 12 s RC clenom
 *  Date: 30. 04. 2024
 *  Author: S. Chamraz
 */ 

#ifndef P_F_1_H_
#define P_F_1_H_

#include <avr/io.h>
#include <avr/interrupt.h> 
#include <stdio.h>

#define toggle_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))

#define con_T_v  5-1		// T_v = 10 ms  (5 * 2ms) - vypis  kazdych 10ms

// port D
#define  pinA 5		// skok 5,0V,  
#define  pin_PWM 5		// resp. PWM 
#define  pinB 4		// vybijanie kondenzatora 


void ini_TC2(void);
void ini_PWM(void);
void adc_init(void);


#define f_opak_TC2 500		// 500 Hz -> 2ms
#define N_D_TC2 128			// Delic = 128
#define OCR2A_f_opak_TC2 F_CPU/f_opak_TC2/N_D_TC2 - 1		// Vysledkom je 2ms casova vzorka !!!!!

extern volatile int poc_time ;	// prirastok 10ms

extern volatile int y_C ;  // u_C = y_C;  
 
extern volatile unsigned char flag_T_v ;
extern volatile unsigned char poc_T_v;

//unsigned char vyk_w_zel = 0;
                          
extern volatile unsigned char poc_T_vypis; // vypis aj v nultej vzorke
//extern volatile unsigned char flag_Vypisov;	


#endif /* P_F_1_H_ */
/*
 * p_f_1.c
 *
 *  Pomocne funkcie na cvicenie 12 s RC clenom
 *  Date: 30. 04. 2024
 *  Author: S. Chamraz
 */ 

#include "uart.h"
#include "p_f_1.h"
volatile int poc_time = 0;	// prirastok 10ms
volatile int y_C = 0;  // u_C = y_C;  
 
volatile unsigned char flag_T_v = 0;
volatile unsigned char poc_T_v = 0;


void ini_PWM(void)                             // T0 (D6) budeme pouzivat ako "analogovy" vystup
{
    OCR0B  = 0;
	TCCR0A = (1<<COM0B1)|(0<<COM0B0)           // Turn output off when TCNT0 >= OCR0B
               |(1<<WGM01)|(1<<WGM00);         // Select Fast PWM Mode         
    TCCR0B = (0<<CS02)|(1<<CS01)|(1<<CS00);    // fopak = cca 1kHz
    DDRD  |= (1<<pin_PWM);			           // output  PD5	
	
}


void ini_TC2(void)
{	                                           //  Nastavenie TC2
	                                           // 7 6         5 4         3 2     1 0
	                                           // COM2A[1:0]  COM2B[1:0]  - - 	  WGM2[1:0]
	TCCR2A = 0b00000011;	                   // OC2B  PWM mod = 7
	TCCR2B = 0b00001101;	                   // fosc/128
	
	OCR2A = OCR2A_f_opak_TC2;                  // nastavenie frekvencie opakovania na 2ms
	TIMSK2  = (1<<TOIE2);                      // Enable interrupts @ overflow TC2 MOD 7
}


ISR(TIMER2_OVF_vect)                           
{                                        // toto sa vykona kazde 2,0ms
 	set_bit(ADCSRA,ADSC);                //   spustenie dalsieho prevodu ADSC = TRUE
	
	if (!poc_T_v)
	{	flag_T_v = 1;			// priznak vypoctu PI reg.
		toggle_bit(PORTB,LED);
        	poc_time++;
		poc_T_v = con_T_v;		
	} 
	else poc_T_v--;		
}

void adc_init(void){
	ADMUX = (0<<REFS1)|(1<<REFS0);				// AVCC - nastavenie zdroja ref. napatia
	ADCSRA = (1<<ADEN)							// "zapnutie" ADC
             |(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // nastavenie preddelica
			                                    // fADC = 125kHz
			                                    // trvanie jedneho prevodu cca 0,1ms
			                                    // zarovnanie doprava
	ADMUX = (ADMUX & 0xF8);						// nastavenie kanalu AD0
	ADCSRA |= (1<<ADSC)|(1<<ADIE);				// spustenie prevodu, povolenie prerusenia od AD
}

ISR(ADC_vect){
                                             	// precitanie AD prevodu kanal 0;
	                                            // ak treba tu nastavíme dalsi kanal 
	                                            // a spustíme az v preruseni od TC2 
	                                            // a vycitame posledne ukonceny prevod
	y_C = ADC;                                  // precitanie AD0
}
/* Arduino code az niekedy inokedy */


RC-SerialPlot01.png
Výstup zo “SerialPtot“ by mohol vyzerať takto.

Regulácia sústavy

V druhej časti cvičenia bude našou snahou vytvoriť regulátor, ktorý bude udržiavať napätie na výstupe (t.j. na kondenzátore) na požadovanej hodnote a to aj pri zmene záťaže. Na podobnom princípe pracujú aj spínané zdroje, ktoré sa využívajú vo všetkých možných oblastiach.


Zdrojové programy upravíme tak, aby sme mohli regulovať napätie na kondenzátore. Najskôr pomocou P regulátora. Na začiatku treba povedať, že vstupom regulátora sú w_{zel} a y_C v rozsahu 0 až 1023. Výstup (plnenie PWM signálu) je z rosahu (0 až 255)). To znamená, že ak chceme nastaviť zosilnenie P regulátora na hodnotu K_P, musí tomu odpovedať rovnica:


          m_{reg} (nT_v) =  (   e(nT_v) K_P )/4;
kde  4 = 1024/256 .

Regulačnú odchýlku počítame podľa vzťahu 
         e(nT_v) = w_{zel}(nT_v) - y_C(nT_v);

Samozrejme nesmieme zabudnúť na obmedzenie akčného zásahu (min = 0 a max = 255).

Na “pozadí” beží spojitý čas timeVal a my z neho využívame len disktretne vzorky, teda 
        timeVal = n*T_v =  poc_{time}*T_v.

V programe použíjeme namiesto n premennú poc_time typu int.

Môžeme to povedať, aj tak, že regulovaný system mimo týchto okamžikov pracuje “v otvorenej slučke”. Perióda vzorkovania T_v musí byť dostatočne malá, aby sa stav systému medzi vzorkami zmenil len nepatrne. V zhode s prednáškou vyhovuje  T_v = 10 ms. Ak by sme použili PI, resp. PS regulátor, bolo by vhodné nastaviť samostatnú periódu vzorkovania pre zbiehanie PS algoritmu a samostatnú pre výpis priebehu regulovanej veličiny, akčného zásahu, želanej veličiny,...


RC-SerialPlot02.png
Výstup zo “SerialPtot“ pre P regulátor so zosilnením 5 by mohol vyzerať takto.


Pri realizáci P-regulátora využijeme program, ktorý sme vytvorili vyššie na identifikáciu parametrov sústavy. Musíme do neho doprogramovať samotný regulátor, viď nižšie. Keďže hodnoty sa aktualizujú mimo funkcie v prerušení od časovača, všetky premenné sú globálne (deklarované mimo tela funkcie) a tie, ktoré meníme v prerušení navyše ako typ volatile. Definícia funkcie patrí ešte pred funkciu main.

int K_P = 1;		// P zlozka regulatora: 1,2,3 max. 10
					 
int e_reg = 0;          // e - regulacna odchylka
int w_zel = 0;          // w - zelana hodnota
int u_reg = 0;          // u - akcny zasah

/*    Jednoduchy   P-regulator                          *
 *                                                      *
 *    Kedze pocitame vsetky veliciny v rozsahu 0-1023   *
 *    ale PWM je len 8-bitove, musime napokon vysledok  *
 *    prepocitat do rozsahu 0-255 a taktiez ak nam vy-  *
 *    sledok vyjde viac ako 255 alebo menej ako 0, tak  *
 *    ho musime obmedzit.                               *
 *                                                      */
void P_reg(void)                  
{                                // Regulator: vypocty
	e_reg = w_zel - y_C;         // regulacna odchylka e = w - y
	u_reg = K_P*e_reg;           // akcny zasah        u = K*e
	u_reg = u_reg>>2 ;            // 0-1023 do rozsahu  0-255
	
 	if (u_reg <   0 )  u_reg = 0;  // limiter
	if (u_reg > 255 )  u_reg = 255;

	OCR0B  = u_reg ;	         // a napokon 'u' posleme von
}


Hlavnú programovú slučku potom doplníme nasledovne:

  • (11) v čase 1 s ( v programe 100, t.j. vtedy, keď vybijeme kondenzátor na 0V ) nastavíme hodnotu želanej veličiny na 800
  • (14-18) v čase 3,5 s ( v programe 350, to musíme ešte doplniť) nastavíme hodnotu želanej veličiny na 600
  • (27) do slučky treba doplniť samotné volanie funkcie P_reg();, ktorý vypočíta regulačnú odchylku a zmení akčný zásah.
  • (30) navyše by bolo dobré zmeniť vykreslované hodnoty, a namiesto veličín y_oo a y_63 si vypísať (a vykresliť) aktuálnu hodnotu želanej hodnoty w_zel a akčného zásahu u_reg.
 1 ...  
 2 while(1)
 3   {
 4 	
 5 	    /* 3. pockame az do casu 1.0 s aby sme vybili kondenzator */  
 6 		if (poc_time == 100 )      // 100 x 10ms = 1 sekunda
 7 		{
 8         	clear_bit(DDRD,pinB);  // Pin odpojime, t.j. input, "odstranim skrat"
 9 			OCR0B = 204;           // a na vystup poslem PWM, ktore zodpoveda 4V 
10 			
11 			w_zel = 800;
12 		}
13 					
14 
15 		if (poc_time == 350 )      // 100 x 10ms = 1 sekunda
16 		{
17 			w_zel = 600;
18 		}
19 		
20 		
21 		/* 4. a teraz od 0.0 az po 5.0 sec sledujeme napatie na C */
22 		
23 		if( (flag_T_v)&&(poc_time<500 ))
24 		{                                                       
25                   flag_T_v = 0;        
26 
27                   P_reg();                                              // Zavolame regulator
28 
29                                                                         // Vypiseme: aktualny cas, napatie na kondenzatore a dve pomocne veliciny  
30                   printf("%u,%u,%u,%u\r\n",poc_time,y_C,u_reg,w_zel); 	// ako dekadicke hodnoty
31 		} 
32 		
33 		// po uplynuti 5 sekund uz nerobime nic
34 				       									
35   }
36 ...

Úloha 2:

  1. Realizovať regulator pre K_P = 1, 2,3 a porovnať teoretickú a skutočnú trvalú regulačnú odchýlku.
  2. Akým skutočným napätiam zodpovedajú hodnoty 800 a 600? Overte meraním pomocou multimetra.
  3. Ak sa niekomu podarí doplniť aj I zložku regulátora môže pripojiť aj záťaž regulovaného systému. Viď. prednáška.


Poznámka: Pre jednotkový skok vieme vypočítať veľkosť trvalej regulačnej odchýlky v ustálenom stave pre uzavretý regulačný obvod so sústavou prvého rádu (K, T) a P-regulátor (K_P) vypočítať podľa vzťahu


e = 1 K P K 1 + K P K


Samozrejme, že podkladové programy nie sú napísané dokonale. Študenti môžu programy upravovať a vylepšovať. Napr.: AntiWindUpReset, Ručné riadenie, Zmena w_zel pomocou potenciometra, …

Literatúra




Návrat na zoznam cvičení...
  1. Pravdepodobne zistíte, že 8-bitovým počítadlom T0 s kryštálom 16 MHz sa vám nepodarí nastaviť preddelič a register OCR na takú kombináciu, aby interval bol naozaj presne 10,00 ms. V rámci presnosti nášho merania to nevadí, ale je to principiálny problém. Buď by sme museli použiť 16-bitové počítadlo T1, alebo zmeniť hodnotu kryštálu napr. na 18,432 MHz, v takom prípade by nám čas vyšiel presne.