logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Regulator PID na ATmega16 - błędy w kodzie i konfiguracji portów

mn2000 14 Kwi 2008 21:30 8287 4
REKLAMA
  • #1 4912374
    mn2000
    Poziom 11  
    Posty: 5
    Mam problem z Regulatorem PID na ATmega16.

    kod programu:
    #include <inttypes.h>
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <stdlib.h>             
    #include "delay.h"
    #include "lcd.h"
    #include "stdint.h"
    
    
    #define F_OSC 8000000UL
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    
    
    // Zdefiniowanie uzywanych portów. 
    #define PORT_AD PORTA		// Port z wejściami analogowymi 
    #define DDR_AD DDRA			
    #define PORT_F PORTC		// Port do którego przyłączony jest przycisk. Bit 4 tego portu 
    							// jest wykorzystany jako flaga naciśnięcia klawisza
    #define DDR_F DDRC
    #define PIN_F PINC
    
    
    char buffer_n[5];  
    char buffer[5];  	    // Bufor do przechowywania wyniku konwersji z "unsigned int" na ASCII
    
    #define Kp 1.00
    #define SF  100
    
    #define MAX_INT         INT16_MAX
    #define MAX_LONG        INT32_MAX
    #define MAX_I_TERM      (MAX_LONG / 2)
    
    
    unsigned char a,b,licz=32;
    signed long warodn;
    signed long pomiar, pomiara, pomiarb;
    signed long error, errorpop,temp;
    signed long Sff,Kpp,Ki,Kd,P,I,D;
    signed long wynik,wartost;
    signed short wartpop,wart,reszta;
    signed short maxError;
    signed long sumerror, maxsumerror;
    signed short rozniczka;
    
    SIGNAL (SIG_OVERFLOW0)
    {
    
    ADCSRA |= _BV(ADSC);         // Rozpoczęcie przetwarzania
    while(bit_is_set(ADCSRA,ADSC))	// Oczekiwanie na zakończenie przetwarzania
    {};	
    //pomiarb=ADCL;
    pomiar=ADCH;
    pomiara=pomiar*5;
    //pomiar=pomiar;
    
    //pomiar=1180;
    
    maxError = MAX_INT / ( Kpp+ 1);
    
    error=warodn-pomiara;
    
    /*if (error > maxError){
        P = MAX_INT;
      }
      else if (error < -maxError){
        P = -MAX_INT;
      }
      else{*/
        P=Kpp*error;
     // }
    
    maxsumerror = MAX_I_TERM / (Ki+1);
    
    temp=sumerror+error;
    
    if(temp > maxsumerror){
        I = MAX_I_TERM;
        sumerror = maxsumerror;
      }
      else if(temp < -maxsumerror){
        I = -MAX_I_TERM;
        sumerror = -maxsumerror;
      }
      else{
        sumerror = temp;
        I = Ki*sumerror;
      }
    
    rozniczka=error-errorpop;
    
    D=Kd*rozniczka;
    
    wynik=((P)+(I)+D)/SF;
    //wynik=sizeof(unsigned short);
    
    errorpop=pomiara;
    
    //if(wynik> MAX_INT){
    //    wynik = MAX_INT;
    //  }
    //  else if(wynik < -MAX_INT){
    //    wynik = -MAX_INT;
    //  }
    
    
    wartost=(1023*wynik)/1275;
    //wartpop=sizeof(wart);
    
    wart=(short)wartost;
    
    OCR1A=wart;
    
    LCD_clr();     
    LCD_xy(0,0);
    write_text("Wynik: \n");  
    itoa(wynik, buffer_n, 10);  // Konwersja liczby unsigned int do asci
    write_text(buffer_n);          // Wysłanie na ekran LCD wyniku konwersji
    
    LCD_xy(0,1);
    write_text("Wzad: \n");  
    itoa(warodn, buffer, 10);  // Konwersja liczby unsigned int do asci
    write_text(buffer);          // Wysłanie na ekran LCD wyniku konwersji
    
    delay_ms(200);
    
    }
    
    
    void Inicjalizacja(void)
    {
    	DDR_AD=0x00;		// Port jako wejścia
    	PORT_AD=0x00;		// Port C wejścia bez podciągania
    	DDR_F=0xF0;			// Młodsza połowa portu jako wejścia starsze cztery bity jako wyjścia
    	PORT_F=0xFF;		// Wejścia z podciąganiem wyjścia w stanie wysokim
    	DDRD=0x00;
    	PORTD=0xff;
    // Inicjalizacja LCD  
    	lcd_init();			// Inicjalizacja wyswietlacza
    	LCD_clr();	
    // Wybranie wewnętrznego żródła napięcia odniesienia	
    	ADMUX |= _BV(REFS0);		
    	ADMUX |= _BV(REFS1);
    //	Wybranie sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
    	ADMUX |= _BV(ADLAR);		
    // Zezwolenie na konwersję	
    	ADCSRA |= _BV(ADEN);		
    // Wybranie częstotliwości dla taktowania przetwornika  (1/8 częstotliwosci zegara kontrolera) 
    	ADCSRA |= _BV(ADPS0);	 
    	ADCSRA |= _BV(ADPS1);	//
    	
    }
    
    int main(void)
    {
    pomiar=0;
    pomiara=0;
    error=0;
    rozniczka=0;
    warodn=1275;
    Kpp=Kp*SF;
    Ki=50;
    Kd=0;
    wartpop=0;
    sumerror=0;
    errorpop=0;
    
    
    Inicjalizacja();
    
    sbi(DDRD,PD5);
    
    TCCR1A = _BV(COM1A1)|_BV(COM1A0)|_BV(WGM10)|_BV(WGM11);
      
    TCCR1B = 0x03;                 
    TCNT1L=0x00;  
    TCNT1H=0x00;                 
      OCR1AH=0x03;     
      OCR1AL=0xff;
     
    TCCR0 = _BV(CS01)| _BV(CS00);
    
    TIMSK = _BV(TOIE0);
    
    
    sei();
    for (;;) {}
    }
    

    Zamieszczam cały bo może gdzieś indziej jest błąd a nie w kodzie PID
    Wartość pomiaru na razie jest zadawana potencjometrem przez ADC
    docelowo PID ma sterować temperaturą w układzie poprzez PWM.
    Dla samego regulatora P działa pięknie i to juz na regulacji temperatury mam zaimplementowane, Ale z kodem na PID nie mogę sobie poradzić
    Proszę o pomoc.
  • REKLAMA
  • #2 4920780
    lutecki
    Poziom 13  
    Posty: 49
    Pomógł: 3
    Ocena: 2
    Nie wgryzałem się za mocno, ale na pierwszy rzut oka: do <errorpop> powinno być przypisane <error>, a nie <pomiara>.
  • REKLAMA
  • #3 5030350
    mn2000
    Poziom 11  
    Posty: 5
    trochę to poprawiłem ale nadal nie działa, nadal liczy tak jak mu sie podoba. Prawdopodobnie błąd jest w tym wyliczaniu całki. Proszę pomóżcie!!:(


    
    #include <avr/io.h>
    #include <inttypes.h>
    #include <avr/interrupt.h>
    #include <avr/eeprom.h>
    #include <avr/signal.h>
    #include <string.h>
    #include <stdlib.h>
    #include <delay.h>
    #include <ds18x20.h>
    #include <onewire.h>
    #include <crc8.h>
    #include <lcd.h>
    
    
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    
    #define F_CPU 8000000UL
    #define F_OSC 8000000UL
    
    
    
    #define PORT_AD PORTA		// Port z wejściami analogowymi 
    #define DDR_AD DDRA			
    #define PORT_F PORTC		// Port do którego przyłączony jest przycisk. Bit 4 tego portu 
    							// jest wykorzystany jako flaga naciśnięcia klawisza
    #define DDR_F DDRC
    #define PIN_F PINC
    
    
    char buffer_n[4]="    ";  
    char buffer[4]="    ";  	    // Bufor do przechowywania wyniku konwersji z "unsigned int" na ASCII
    char bufor[4]="    ";
    
    
    uint8_t nSensors, i;
    uint8_t subzero, cel, cel_frac_bits;
    #define Kp 0.65
    #define SF  100
    
    static volatile uint8_t led;
    signed char a,b,licz=32;
    signed long warodn;
    signed long pomiar, pomiara, pomiarb;
    signed long error, errorpop,temp;
    signed short Sff,Kpp,Ki,Kd,P,I,D;;
    signed long wynik,wartost;
    signed short wartpop,wart,reszta;
    signed short sumerror;
    signed short rozniczka;
    uint16_t decicelsius;
    
    
    SIGNAL (SIG_OVERFLOW0)
    {
    
    /*
    ADCSRA |= _BV(ADSC);         // Rozpoczęcie przetwarzania
    while(bit_is_set(ADCSRA,ADSC))	// Oczekiwanie na zakończenie przetwarzania
    {};	
    //pomiarb=ADCL;
    pomiar=ADCH;
    pomiara=pomiar*5;
    //pomiar=pomiar;
    //pomiar=1180;
    */
    
    decicelsius = DS18X20_temp_to_decicel(subzero, cel, cel_frac_bits);
    
    pomiar=decicelsius;
    
    //pomiar=1180;
    
    //maxError = MAX_INT / ( Kpp+ 1);
    
    error=warodn-pomiar;
    
    
       P=Kpp*error;
    
    
    //maxsumerror = MAX_I_TERM / (Ki+1);
    
    temp=sumerror+error;
    
    if(temp > 5550){
        I = 1000;
       // sumerror = maxsumerror;
      }
      else if(temp < -5550){
        I = -1000;
       // sumerror = -maxsumerror;
      }
      else{
        sumerror = temp;
        I = Ki*sumerror;
      }
    
    rozniczka=wartpop-pomiar;
    
    D=Kd*rozniczka;
    
    wynik=(P+I+D)/SF;
    
    wartpop=pomiar;
    
    if(wynik<0){wynik=0;}
    
    wartost=(1023*wynik)/2500;
    
    wart=(short)wartost;
    
    OCR1A=wart;
    
    
    	LCD_clr();
    	LCD_xy(0,0);
    	write_text("Temp= ");
    	
    	
    	itoa((int)(decicelsius),bufor,10);
    	write_text(bufor);
    	    
    
    LCD_xy(0,1);
    write_text("wart: \n");  
    itoa(wart, buffer, 10);  // Konwersja liczby unsigned int do asci
    write_text(buffer);          // Wysłanie na ekran LCD wyniku konwersji
    
    delay_ms(500);
    
    }
    
    
    #define MAXSENSORS 5
    uint8_t gSensorIDs[MAXSENSORS][OW_ROMCODE_SIZE];
    
    uint8_t search_sensors(void)
    {
    	uint8_t i;
    	uint8_t id[OW_ROMCODE_SIZE];
    	uint8_t diff, nSensors;
    	
    	//uart_puts_P( "\rScanning Bus for DS18X20\r" );
    	
    	nSensors = 0;
    	
    	for( diff = OW_SEARCH_FIRST; 
    		diff != OW_LAST_DEVICE && nSensors < MAXSENSORS ; )
    	{
    		DS18X20_find_sensor( &diff, &id[0] );
    		
    		if( diff == OW_PRESENCE_ERR ) {
    			//uart_puts_P( "No Sensor found\r" );
    			break;
    		}
    		
    		if( diff == OW_DATA_ERR ) {
    			//uart_puts_P( "Bus Error\r" );
    			break;
    		}
    		
    		for (i=0;i<OW_ROMCODE_SIZE;i++)
    			gSensorIDs[nSensors][i]=id[i];
    		
    		nSensors++;
    	}
    	
    	return nSensors;
    }
    /*void LCD_put_temp(const uint8_t subzero, uint8_t cel, 
    	uint8_t cel_frac_bits)
    {
    	uint16_t decicelsius;
    	LCD_clr();
    	LCD_xy(0,0);
    	write_text("Temp= ");
    	decicelsius = DS18X20_temp_to_decicel(subzero, cel, cel_frac_bits);
    	write_to_lcd((subzero)?'-':'+');
    	itoa((int)(decicelsius/10),bufor,10);
    	write_text(bufor);
    	write_text(".");
    	itoa((int)(decicelsius%10),bufor,10);
    	write_text(bufor);
    	//write_to_lcd((decicelsius%10)+'0');
    	
    }
    */
    #ifdef DS18X20_EEPROMSUPPORT
    static void eeprom_test(void)
    {
        uint8_t sp[DS18X20_SP_SIZE], th, tl;
    	
    	//uart_puts_P( "\rDS18x20 EEPROM support test for fist sensor\r" ); 
    	// DS18X20_recall_E2(&gSensorIDs[0][0]); // already done at power-on
    	DS18X20_read_scratchpad( &gSensorIDs[0][0], sp);	
    	th = sp[DS18X20_TH_REG];
    	tl = sp[DS18X20_TL_REG];
    	//uart_puts_P( "TH/TL from EEPROM sensor 1 : " ); 
    	//uart_puti(th);
    	//uart_puts_P( " / " ); 
    	//uart_puti(tl);
    	//uart_puts_P( "\r" ); 
    	tl++; th++;
    	DS18X20_write_scratchpad( &gSensorIDs[0][0], 
    		th, tl, DS18B20_12_BIT);
    	//uart_puts_P( "TH+1 and TL+1 written to scratchpad\r" ); 
    	DS18X20_copy_scratchpad(  DS18X20_POWER_PARASITE,
    		&gSensorIDs[0][0] );
    	//uart_puts_P( "scratchpad copied to DS18x20 EEPROM\r" );
    	DS18X20_recall_E2(&gSensorIDs[0][0]);
    	//uart_puts_P( "DS18x20 EEPROM copied back to scratchpad\r" );
    	DS18X20_read_scratchpad( &gSensorIDs[0][0], sp);
    	//if ( (th == sp[DS18X20_TH_REG]) && (tl == sp[DS18X20_TL_REG]) ) 
    	//	uart_puts_P( "TH and TL verified\r" );
    	//else 
    	//	uart_puts_P( "verify failed\r" );
    	th = sp[DS18X20_TH_REG];
    	tl = sp[DS18X20_TL_REG];
    	//uart_puts_P( "TH/TL from EEPROM sensor 1 now : " ); 
    	//uart_puti(th);
    	//uart_puts_P( " / " ); 
    	//uart_puti(tl);
    	//uart_puts_P( "\r" ); 
    }
    #endif
    
    	
    
    
    
    ///****************** PROGRAM GLOWNY ********************////
    int main (void)
    
    {	
    Kpp=Kp*SF;
    Ki=50;
    Kd=12;
    wartpop=0;
    sumerror=0;
    errorpop=0;
    warodn=340;	
    	
    	
    	DDRC=0x00;
    	PORTC=0x00;
    	DDR_AD=0x00;		// Port jako wejścia
    	PORT_AD=0x00;		// Port C wejścia bez podciągania
    	DDR_F=0xF0;			// Młodsza połowa portu jako wejścia starsze cztery bity jako wyjścia
    	PORT_F=0xFF;		// Wejścia z podciąganiem wyjścia w stanie wysokim
    	DDRD=0x00;
    	PORTD=0xff;
    
    // Wybranie wewnętrznego żródła napięcia odniesienia	
    	ADMUX |= _BV(REFS0);		
    	ADMUX |= _BV(REFS1);
    //	Wybranie sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
    	ADMUX |= _BV(ADLAR);		
    // Zezwolenie na konwersję	
    	ADCSRA |= _BV(ADEN);		
    // Wybranie częstotliwości dla taktowania przetwornika  (1/8 częstotliwosci zegara kontrolera) 
    	ADCSRA |= _BV(ADPS0);	 
    	ADCSRA |= _BV(ADPS1);	//
    
      sbi(DDRD,PD5);                 // ustawienie kierunku wyjscia PWM
      TCCR1A = _BV(COM1A1)|_BV(COM1A0)|_BV(WGM10)|_BV(WGM11);
      TCCR1B = 0x03;                 
     TCNT1L=0x00;  
     TCNT1H=0x00;                 
      OCR1AH=0x03  ;     
      OCR1AL=0xff;
     
     
    	
    TCCR0 = _BV(CS01)| _BV(CS00);
    TIMSK = _BV(TOIE0);
    	
    	
        lcd_init();
    	LCD_clr();
    	
    	nSensors = search_sensors();
    
    #ifdef DS18X20_EEPROMSUPPORT
    	if (nSensors>0) {
    		eeprom_test();
    	}
    #endif
    while(1){
    //if ( nSensors == 1 ) {
    
    
    //	if (!ow_reset()) {write_text("Jest Czujnik !");}
    	//else write_text("Brak Czujnika !");
    cli();
    
    i = gSensorIDs[0][0]; // family-code for conversion-routine
    		DS18X20_start_meas( DS18X20_POWER_PARASITE, NULL );
    		delay_ms(DS18B20_TCONV_12BIT);
    		DS18X20_read_meas_single(i, &subzero, &cel, &cel_frac_bits);
    		//LCD_put_temp(subzero, cel, cel_frac_bits);
    		//delay_ms(1000);
    	sei();	
    	}
    	
    }
    
  • REKLAMA
  • #4 5030983
    McRancor
    VIP Zasłużony dla elektroda
    Posty: 5326
    Pomógł: 479
    Ocena: 124
    Wydzieliłem i przeniosłem z Automatyka i Robotyka
REKLAMA