16F877a PI-PD kontrol algoritması (Hi-tech Pro C 10/12/16)

ABYS

Üye
Katılım
17 Nis 2008
Mesajlar
219
Puanları
1
u kontrol işareti (pwm çıkışı ccp1)
ref referans işareti (analog giriş AN0)

Kod:
#include <htc.h>
#include "delay.h"
#define ref 1                                       //referans
#define T 0.1                                      //ornekleme zamani
#define Kpi 5                                      //PI-PD kontrol katsayıları
#define Kd 2.5
#define Kpd 1.3
#define Ki 2.7
float geribesleme();                                             // sistemin çıkışını okuyan fonksiyon (ADC)
void controller(float);                                          // kontrolör fonksiyonu
void kontrolpwm(float);                                          // pwm (u) üreten fonksiyon
static void interrupt kesmeler(void);                       
void timerbasla();                                               // timer1 i başlatan fonk
float h,u,e,u1,sys_out_1=0,ud;                   // h: geribesleme veya çıkış işareti, u:kontrol işareti
																 // sys_out_1 : sistem çıkışının önceki değeri  ud: PD den gelen kontrol işareti
float integral=0,turev=0;  //  türev,integral: türev ve integral kontrol işareti
int a;															 // timer1'in bir periyodunu T'te eşitlemek için kullanılan sayi.
void main(void) 												 // main fonksiyon
{
	TRISA=1;													 // RA0 analog giriş.
	TRISC=0;													 // C portu çıkış (PWM- CCP1)
	PORTA=0;
	PORTC=0;
	GIE=1;														 // Genel kesme izin biti
	a=(int)(1000000*T/8);										 // timer1'in bir periyodu T'ye eşit olması için timera yüklenecek sayi hesabı
	timerbasla();												 // Timer1 başlatılır.
	while (1){
		h=(geribesleme()/1023)*5;								 // AN0 dan alınan veri 0-5 V a çevriliyor.
		controller(h);													 // AN0 dan alına veri kontolöre gönderiliyor.
	}
}

void timerbasla(){												 // Timer1 başlatan fonksiyon
	TMR1H=-a/256;												 // Hesaplanan a değeri Timer1e yükleniyor
	TMR1L=-a%256;
	TMR1CS=0;													  // Dahili osilatör
	T1CKPS1=1; 													  // Prescaler 1:8
	T1CKPS0=1;
	T1SYNC=1;													  // Senkronizasyon yok
	TMR1IF=0; 													  // Timer1 kesme bayrağı sıfırlanıyor
	TMR1IE=1; 													  // Timer1 kesme izin biti
	TMR1ON=1; 													  // Timer1 enable biti
	PEIE=1; 													  // Yardımcı kesmeler enable biti
}

float geribesleme(){											  // AN0 dan analog veri(geribesleme) okuma
	float value;
	ADCON1=0b10001110;											  // AN0 analog	(PCFG0..4), sağa sola dayalı(ADFM), Fosc/8(ADCS2-0) bitleri.
	ADCON0=0b01000001;											  // Fosc/8(ADCS1:0-01) , AN0 seçim bitleri (CHS0..3- 000), çevrim başla(ADGO-0),ADC enable(ADON-1) bitleri
	DelayUs(25);												  // 25 uS bekler
	ADGO=1;  													  // Çevrimi başlatırr
	while(!ADGO);												  // ÇEvrim bitene kadar bekler
	value=(ADRESL+(ADRESH*256));								  // Veri yi float değişkene atar.
	return value;
}
void controller(float sys_out){									   // PI-PD kontrol
	if(timeflag==1){											   // her T(örnekleme) periyotta kontrolör güncellenir
	e=ref-sys_out;												   // dış kapalı çevrim için hata
	if((u>0||e>-1.5)&&(u<4.98||e<1.5)) integral=integral+e*T*Ki;   // PI için integral hesabı. sarmayı engellemek için sınırlamalar.
	u1=integral+Kpi*e;											   // PI çıkışı u1
	turev=Kd*(sys_out-sys_out_1)/T;								   // PD için türev hesabı. PD iç çevrimde geri besleme yolu üzerinde çıkışın
																   // türevini alır. sys_out_1: çıkışın önceki değeri.
	ud=Kpd*sys_out+turev;										   // PD kontrol işareti ud
	u=u1-ud;													   // kontrol işareti u1-ud
	sys_out_1=sys_out;											   // çıkış değeri çıkışın önceki değerine atanır
	timeflag=0;													   // bir sonraki T periyodu için timeflag sıfırlanır
	}
	if (u<0) u=0;													// saturasyon
	if (u>4.98) u=4.98;
	kontrolpwm(u);													// kontrol işareti PWM fonksiyonuna gönderilir.
}
void kontrolpwm(float value){
	int duty;
	value=value*50;													// gelen deger 0-5 aralığında olduğu için 50 ile çarparak 0-250 aralığında bir değer elde ederiz
	duty=(int)value;
	PR2=249;														// PEriyot
	CCPR1L=duty;													// duty cycle
	CCP1CON= 0b00101100;									        // PWM modu
	T2CKPS0=1; T2CKPS0=1;											// Timer2 prescale 1:16
	TMR2ON=1;														// Timer2 enable
}
static void interrupt
kesmeler(void)
{
	GIE=0;
	if(TMR1IF) {													// Timer1 kesme bayrağı 1 oldugunda
		timeflag=1;													// timeflag i bir yap. Kontrol işaretini güncelemek için gereken bayrak
		TMR1H=-a/256;
		TMR1L=-a%256;
		TMR1IF=0;
		}
	GIE=1;
}
 

Forum istatistikleri

Konular
129,755
Mesajlar
929,687
Kullanıcılar
452,504
Son üye
davut111

Yeni konular

Geri
Üst