PS regulátor: Rozdiel medzi revíziami
Zo stránky 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...“ |
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;
}