Operácie

PS regulátor: Rozdiel medzi revíziami

Z SensorWiki

(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...“)
 
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 zo dňa a času 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;
}