Operácie

PS regulátor: Rozdiel medzi revíziami

Zo stránky SensorWiki

Balogh (diskusia | príspevky)
Vytvorená stránka „<source lang="c"> #include <avr/io.h> #include <avr/interrupt.h> #include <stdlib.h> #include <stdio.h> #include "pomocne.h" FILE mystdout_uart = FDEV_SETUP_STREAM(s...“
 
Balogh (diskusia | príspevky)
Bez shrnutí editace
Riadok 93: Riadok 93:


#define SETBIT(VAR,BIT) ((VAR)|=(1<<(BIT)))  
#define SETBIT(VAR,BIT) ((VAR)|=(1<<(BIT)))  
</source>
A samozrejme aj samotné funkcie ('''pomocne.c'''):
<source lang="c">
//#define  epsilon_0 1
#include <avr/io.h>
#include <avr/interrupt.h> 
#include "pomocne.h"
volatile unsigned char t_out_spust_prev;
volatile unsigned char t_100ms;
volatile unsigned int iii=0;
volatile unsigned char vypis=0;
// Z PSD regulatora je implementovany len PS regulator
// Vynechana je cast Rucne/Automaticka prevadzka (len automaticka)
// Vynechany je ARW
// Vynechane je zadavanie parametrov
// Vynechany je watchdog,...
// Pri vypocte akcneho zasahu je pouzita celociselna aritmetika
// Parametre a vveliciny su normovane takto:
// Zosilnenie regulatora je vynasobene 10-timi, to znamena, ze Kreg=15 predsravuje zosilnenie 1.5
// Integracna casova konstanta je vynasobena 1000. To znamena Ti_reg=500 predstavuje casovu konst. 0.5 sekundy
// Pozadovana hodnota w_zel je vynasobena 100-mi. To znamena w_zel1=450, predstavuje 4.5 V-ta.
// podobne to plati aj pre meranu velicinu.
// akcny zasah m_reg je z rozsahu 0 az % V.  Tato velicina je prepocitana na Plnenie (8-bit)
int K_reg=10; 
int Ti_reg=500;   
volatile long m_P_n=0,m_P_s=0,m_I_s=0,m_I_n=0;
volatile int m_reg= 0;   
int w_zel= 0;   
int w_zel1=400,w_zel2=100;   
volatile int reg_odch_n= 0; // velicina vypocitana v kroku (n*T_v)
volatile int reg_odch_s= 0; // velicina vypocitana v kroku ((n-1)*T_v)
volatile unsigned char plnenie=0;
volatile unsigned int y_reg;
int T_v= 19; // 110ms=109 20ms=19
/*  PS regulator */
void PS_reg(void)
{
   
// vyposuvanie velicin
reg_odch_s = reg_odch_n;
m_I_s      = m_I_n;
    m_P_s      = m_P_n;
// vypocet reg. odchylky
reg_odch_n = w_zel - y_reg;
// Algoritmus PS regulatora
// m(n*T_v)= m_P((x)*T_v)+ m_I((x)*T_v)
// x predstavuje krok (n*T_v) resp. ((n-1)*T_v)
    // Vypocet P zlozky regulatora
m_P_n = reg_odch_n * K_reg;
  if(Ti_reg)
  {   
  // Vypocet I zlozky regulatora
      m_I_n += (m_P_s*T_v)/Ti_reg;
  // co by sa dialo ak by sme predchadzajuci riadok zapisali takto?
  //m_I_n += (m_P_s/(Ti_reg))*T_v;
  }
  else
  { // nechceme delit nulou
    m_I_n = 0;
      }
 
//  epsilon vyjadruje posunutie IC zapojenie na vystupe regulatora
//  epsilon je z intervalu (0, 1>
//  tu uvazujeme lem krajne hodnoty
// epsilon = 0, znamena: po vypocitani sa zmeni hodnota akcneho zasahu okamzite
// epsilon = 1, znamena: hodnota akcneho zasahu sa zmeni az v dalsom kroku
#ifdef epsilon_0
//  vystup posunuty o krok
m_reg = (m_P_s + m_I_s)/10;
#else
//  vystup neposunuty; vypocitam a poslem
m_reg = (m_P_n + m_I_n)/10;
#endif  
 
 
   
  // obmedzenie  akcneho zasahu na interval <0 az 5 V>
  if(m_reg>500)
  {
    m_reg=500; // 5.00 V
  }
  if(m_reg < 0)
  {
    m_reg=0;
  }
  // Doplnte vypocet, ako sme dostali cislo 2?
  plnenie =(unsigned char) ((m_reg)/2);
  OCR1A = plnenie;
}
// pouziva sa pri generovani timeout-ov
// pretecenie kazdu 1024 us = 1.0ms (preddelic nastaveny na fosc/64)
//#pragma interrupt_handler timer2_ovf_isr:iv_TIM2_OVF
ISR (TIMER2_OVF_vect)
//void timer2_ovf_isr(void)
{
TCNT2 = 0x83; //reload counter value
if (t_out_spust_prev) t_out_spust_prev--;
else
{ t_out_spust_prev=T_v-1; // Tv = 110 ms = 109
SETBIT(ADCSRA,ADSC);//  spustenie dalsieho prevodu ADSC = TRUE
// rampa + meranie prechodovej charakteristiky
// if((iii++) <256) OCR1A=iii; else OCR1A=0x0;
}
// generator priebehu zelanej veliciny
if(t_100ms)t_100ms--;
else
{t_100ms = 99; // nastav pocitadlo 100 ms
  if(iii++==50 )w_zel=w_zel1;
  if(iii==100 )w_zel=w_zel2;
  if(iii==150 )w_zel=w_zel1;
  if(iii==200 )w_zel=w_zel2;
  if(iii==250 )w_zel=w_zel1;
  if(iii==300 )w_zel=w_zel2;
vypis=1; // kazdych 0.1 sekundy
}
}
// ************************************************************
// prerusenie od A/D prevodnika
// ************************************************************
ISR(ADC_vect)
  long pom;
  //conversion complete, read value (int) using...
  // value=ADCL;            //Read 8 low bits first (important)
  // value|=(int)ADCH << 8; //read 2 high bits and shift into top byte
    pom  = ADC;
    pom *= 500;
    pom /= 1024;
  y_reg  = pom; // nanormovane na <0.00 az 5.00)
  if (y_reg>500)
      y_reg=500;
    PS_reg();
}
//TIMER2 initialize - prescale:128
// WGM: Normal
// desired value: 1mSec
// actual value:  1,000mSec (0,0%)
void timer2_init(void)
{
TCCR2B = 0x00; //stop
ASSR  = 0x00; //set async mode
TCNT2 = 0x83; //setup
OCR2A = 0x7D;
OCR2B = 0x00;
TCCR2A = 0x00;
TCCR2B = 0x05; //start
TIMSK2 = 0x01;            // TOVIE2 = 1; Enable T2 overflow interrupt       
}
//ADC initialize
// Conversion time: 104uS
void adc_init(void)
{
ADCSRA = 0x00; //disable adc
ADMUX = 0x44;//b0100 0100;  //select adc input 4, Uref= 5,0V
//ADMUX    b7  b6  b5  b4    b3  b2  b1  b0
//                            ______________
//                                  MUX      = 0b0100 => 4. kanal
//                      0
//                ____
//                Right adjust = 0
//          ______
//          Refs  = 01 => Uref = AVCC
ACSR  = 0x80; // odpojenie Analog. komparator
// ADCSRB = 0x00;
ADCSRA = 0x8F;
//ADCSRA    b7  b6  b5  b4    b3  b2  b1  b0
//                                ___________
//                                  ADPS      = 0b111 =>  Division Factor =128 => 16MHz/128 = 125 kHz
//                            ____
//                            ADIE = 1 => povolenieprerusenia
//                    ____
//                    ADIF = 1 => vynulovanie prerusenia
//                  0
//            ____
//            ADSC = 1 => spustenie prevodu
//        ____
//        ADEN  = 01 => pripojenie AD na napatie
}
//TIMER1 initialize - prescale:64
// WGM: 5) PWM 8bit fast, TOP=0x00FF
// desired value: 2mSec
// actual value:  1,024mSec (48,8%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCCR1A = 0x81;
TCCR1B = 0x0B; //start Timer
// Na pin PB1 je pripojeny OC1A FPWM mod
DDRB|=0x02;
}
// Funkcie pre obsluhu serioveho komunikacneho rozhrania:
void inituart(void)
{
BAUD_RATE_REG = (unsigned char)BAUD_PRESCALE;    // Set baud rate: Load the UBRR register
UART_CONTROL_REG_B = (1 << ENABLE_RECEIVER_BIT)|
                    (1 << ENABLE_TRANSMITTER_BIT); // Enable receive + transmit
UART_CONTROL_REG_C = (3<<UCSZ00);                // Added: Async. UART, None
                                                  // Parity, 8-data, 1 stopbit
                                                 
}
int sendchar(char c, FILE *stream)
{
  UART_DATA_REG = c;                                  // prepare transmission
  while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT)));// wait until byte sendt
  UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT);          // delete TXCflag
  return 0;
}
int uart_putchar(char c, FILE *stream);
unsigned char recchar(void)
{
  while( !(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT)) );  // wait for data
  return UART_DATA_REG;
}


</source>
</source>

Verzia z 12:36, 17. december 2012

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

#include "pomocne.h"

FILE mystdout_uart = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);

int main(void)
{ 	
  	UCSR0B = 0x00;        // Disable RxD and TxD for UART0

	//  Inicializacia
	//  Nie vsetky registre su rozpisane; doplnte
   	inituart();		// inicializacia UARTU
	adc_init();		// inicializacia ADC
 	timer1_init();   	// inicializacia Timer1: PWM
	timer2_init();		// inicializacia Timer2: 1ms vzorky su zakladom 

        stdout = &mystdout_uart; 
	//printf("\x1B[1;1HAD [4]=");	

        sei();                 // Enable ALL interrupts             

	do{  
	  if(vypis){           // Vypis sa realizuje kazdych 100 ms
 	  vypis=0;
          //printf("\x1b[2;1H%04x %04d  %04d %04d %3d.%02d ",plnenie,iii,w_zel,reg_odch_n,(y_reg/100),(y_reg%100));
          printf("%d\r",y_reg/2);
          }
	} while(1);
}

K programu potrebujete aj knižnicu pomocne.h s pomocnými funkciami:

// Premenne:
extern int K_reg;   
extern int Ti_reg;  

extern volatile long m_P_s,m_P_n,m_I_s,m_I_n;
extern volatile int m_reg;    

extern int w_zel;    
extern int w_zel1,w_zel2;    
extern volatile int reg_odch_n; 
extern volatile int reg_odch_s; 

volatile unsigned char plnenie;
extern volatile unsigned int y_reg;
extern int T_v; // 110ms=109 20ms=19
extern volatile unsigned char t_out_spust_prev;
extern volatile unsigned char t_100ms;
extern volatile unsigned int iii;
extern volatile unsigned char vypis;


// Hlavne funkcie:

extern void PS_reg(void);

extern void adc_init(void);
extern void timer1_init(void);
extern void timer2_init(void);
extern void timer2_ovf_isr(void);

// Pomocne funkcie:
 
extern void inituart(void);
extern int sendchar(char c, FILE *stream);

 // Following calculation assumes that F_CPU is assigned in 'Project/Options'

#define BAUDRATE       9600      
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)

/* definitions for UART control */      
                                        // Valid for ATmega328
#define	BAUD_RATE_REG	        UBRR0   // 
#define	UART_STATUS_REG		UCSR0A  // OK, checked (but also control reg.)
#define	UART_CONTROL_REG_B	UCSR0B  // OK, checked
#define UART_CONTROL_REG_C      UCSR0C  // Added for mode setting
#define	ENABLE_TRANSMITTER_BIT	TXEN0   // OK, checked
#define	ENABLE_RECEIVER_BIT	RXEN0   // OK, checked
#define DATA_REGISTER_EMPTY_BIT UDRE0   // Added, for possible speed-up
#define	TRANSMIT_COMPLETE_BIT	TXC0    // OK, checked
#define	RECEIVE_COMPLETE_BIT	RXC0    // OK, checked
#define	UART_DATA_REG		UDR0    // OK, checked

#define SETBIT(VAR,BIT)			((VAR)|=(1<<(BIT)))

A samozrejme aj samotné funkcie (pomocne.c):

//#define  epsilon_0 1
#include <avr/io.h>
#include <avr/interrupt.h>  
#include "pomocne.h"

volatile unsigned char t_out_spust_prev;
volatile unsigned char t_100ms;
volatile unsigned int iii=0;
volatile unsigned char vypis=0;


// Z PSD regulatora je implementovany len PS regulator
// Vynechana je cast Rucne/Automaticka prevadzka (len automaticka)
// Vynechany je ARW
// Vynechane je zadavanie parametrov
// Vynechany je watchdog,...

// Pri vypocte akcneho zasahu je pouzita celociselna aritmetika
// Parametre a vveliciny su normovane takto:
// Zosilnenie regulatora je vynasobene 10-timi, to znamena, ze Kreg=15 predsravuje zosilnenie 1.5
// Integracna casova konstanta je vynasobena 1000. To znamena Ti_reg=500 predstavuje casovu konst. 0.5 sekundy
// Pozadovana hodnota w_zel je vynasobena 100-mi. To znamena w_zel1=450, predstavuje 4.5 V-ta.
// podobne to plati aj pre meranu velicinu.
// akcny zasah m_reg je z rozsahu 0 az % V.  Tato velicina je prepocitana na Plnenie (8-bit)

int K_reg=10;   
int Ti_reg=500;    
volatile long m_P_n=0,m_P_s=0,m_I_s=0,m_I_n=0;

volatile int m_reg= 0;    
int w_zel= 0;    
int w_zel1=400,w_zel2=100;    
volatile int reg_odch_n= 0; // velicina vypocitana v kroku (n*T_v)
volatile int reg_odch_s= 0; // velicina vypocitana v kroku ((n-1)*T_v)

volatile unsigned char plnenie=0;
volatile unsigned int y_reg;
int T_v= 19; // 110ms=109 20ms=19

/*  PS regulator */

void PS_reg(void)
{	
     
	 // vyposuvanie velicin
	 reg_odch_s = reg_odch_n;
	 m_I_s      = m_I_n;
     m_P_s      = m_P_n;

	 // vypocet reg. odchylky
	 reg_odch_n = w_zel - y_reg;

	// Algoritmus PS regulatora
	// m(n*T_v)= m_P((x)*T_v)+ m_I((x)*T_v)
	// x predstavuje krok (n*T_v) resp. ((n-1)*T_v)
    // Vypocet P zlozky regulatora
	 m_P_n = reg_odch_n * K_reg; 
	   if(Ti_reg)
	   {  		  
		  // Vypocet I zlozky regulatora

	      m_I_n += (m_P_s*T_v)/Ti_reg;
		  // co by sa dialo ak by sme predchadzajuci riadok zapisali takto?
		  //m_I_n += (m_P_s/(Ti_reg))*T_v;

	   }
	   else
	   { // nechceme delit nulou
	     m_I_n = 0;
       }
	   
//  epsilon vyjadruje posunutie IC zapojenie na vystupe regulatora
//  epsilon je z intervalu (0, 1>
//  tu uvazujeme lem krajne hodnoty
// epsilon = 0, znamena: po vypocitani sa zmeni hodnota akcneho zasahu okamzite
// epsilon = 1, znamena: hodnota akcneho zasahu sa zmeni az v dalsom kroku

#ifdef epsilon_0
//  vystup posunuty o krok
	m_reg = (m_P_s + m_I_s)/10;
#else 
//  vystup neposunuty; vypocitam a poslem
	m_reg = (m_P_n + m_I_n)/10;
#endif		  
	   
	 
	   
		    
	  // obmedzenie   akcneho zasahu na interval <0 az 5 V>
 	   if(m_reg>500)
	   {
	     m_reg=500; // 5.00 V
	   }
	   if(m_reg < 0)
	   {
	    m_reg=0;
	   }
	  // Doplnte vypocet, ako sme dostali cislo 2?
 	  plnenie =(unsigned char) ((m_reg)/2);
	  OCR1A = plnenie;
	

}



// pouziva sa pri generovani timeout-ov
// pretecenie kazdu 1024 us = 1.0ms (preddelic nastaveny na fosc/64)
//#pragma interrupt_handler timer2_ovf_isr:iv_TIM2_OVF
ISR (TIMER2_OVF_vect)
//void timer2_ovf_isr(void)
{
 TCNT2 = 0x83; //reload counter value

				
	if (t_out_spust_prev) t_out_spust_prev--;
	else 
	{	t_out_spust_prev=T_v-1; // Tv = 110 ms = 109

		SETBIT(ADCSRA,ADSC);//   spustenie dalsieho prevodu ADSC = TRUE
		
	// rampa + meranie prechodovej charakteristiky
	//	if((iii++) <256) OCR1A=iii; else OCR1A=0x0;
	
	}

// generator priebehu zelanej veliciny
	if(t_100ms)t_100ms--;
	else
	{t_100ms = 99; // nastav pocitadlo 100 ms
	  if(iii++==50 )w_zel=w_zel1;
	  if(iii==100 )w_zel=w_zel2;	
	  if(iii==150 )w_zel=w_zel1;	
	  if(iii==200 )w_zel=w_zel2;	
	  if(iii==250 )w_zel=w_zel1;	
	  if(iii==300 )w_zel=w_zel2;	

	vypis=1; // kazdych 0.1 sekundy
 }	
	
}

// ************************************************************	
// prerusenie od A/D prevodnika		
// ************************************************************	
ISR(ADC_vect)
{  
  long pom;
  //conversion complete, read value (int) using...
  // value=ADCL;            //Read 8 low bits first (important)
  // value|=(int)ADCH << 8; //read 2 high bits and shift into top byte

    pom  = ADC;
    pom *= 500;
    pom /= 1024;
  y_reg  = pom; // nanormovane na <0.00 az 5.00)
		
   if (y_reg>500) 
       y_reg=500;
			
    PS_reg();
}



//TIMER2 initialize - prescale:128
// WGM: Normal
// desired value: 1mSec
// actual value:  1,000mSec (0,0%)
void timer2_init(void)
{
 TCCR2B = 0x00; //stop
 ASSR  = 0x00; //set async mode
 TCNT2 = 0x83; //setup
 OCR2A = 0x7D;
 OCR2B = 0x00;
 TCCR2A = 0x00; 
 TCCR2B = 0x05; //start
 TIMSK2 = 0x01;            // TOVIE2 = 1; Enable T2 overflow interrupt         
}

//ADC initialize
// Conversion time: 104uS
void adc_init(void)
{
 ADCSRA = 0x00; //disable adc
 ADMUX = 0x44;//b0100 0100;  //select adc input 4, Uref= 5,0V
//ADMUX     b7  b6  b5  b4     b3  b2  b1  b0
//                             ______________
//                                   MUX      = 0b0100 => 4. kanal
//                      0 
//                 ____
//                 Right adjust = 0 
//          ______
//           Refs  = 01 => Uref = AVCC
 ACSR  = 0x80; // odpojenie Analog. komparator

// ADCSRB = 0x00;
 ADCSRA = 0x8F;
//ADCSRA    b7  b6  b5  b4     b3  b2  b1  b0
//                                ___________
//                                   ADPS      = 0b111 =>  Division Factor =128 => 16MHz/128 = 125 kHz
//                            ____
//                            ADIE = 1 => povolenieprerusenia
//                     ____
//                     ADIF = 1 => vynulovanie prerusenia
//                  0 
//             ____
//             ADSC = 1 => spustenie prevodu
//         ____
//         ADEN  = 01 => pripojenie AD na napatie
 
}

//TIMER1 initialize - prescale:64
// WGM: 5) PWM 8bit fast, TOP=0x00FF
// desired value: 2mSec
// actual value:  1,024mSec (48,8%)
void timer1_init(void)
{
 TCCR1B = 0x00; //stop
 TCCR1A = 0x81;
 TCCR1B = 0x0B; //start Timer
 // Na pin PB1 je pripojeny OC1A FPWM mod
 DDRB|=0x02; 
}

// Funkcie pre obsluhu serioveho komunikacneho rozhrania:

void inituart(void)
{
 BAUD_RATE_REG = (unsigned char)BAUD_PRESCALE;    // Set baud rate: Load the UBRR register

 UART_CONTROL_REG_B = (1 << ENABLE_RECEIVER_BIT)|
                    (1 << ENABLE_TRANSMITTER_BIT); // Enable receive + transmit 

 UART_CONTROL_REG_C = (3<<UCSZ00);                 // Added: Async. UART, None 
                                                   // Parity, 8-data, 1 stopbit
                                                   
}


int sendchar(char c, FILE *stream)
{

  UART_DATA_REG = c;                                   // prepare transmission
  while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT)));// wait until byte sendt
  UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT);          // delete TXCflag
  return 0;
}

 int uart_putchar(char c, FILE *stream);

unsigned char recchar(void)
{
  while( !(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT)) );  // wait for data
  return UART_DATA_REG;
}