PS regulátor
Zo stránky SensorWiki
#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;
}