Forum: Mikrocontroller und Digitale Elektronik Problem mit static bzw. volatile (Regelung)


von Stefan G. (Gast)


Lesenswert?

Hallo, ich möchte eigentlich eine ganz simple Sache machen, aber 
irgendwie funzt es nicht:

Um das Regelverhalten meines Ventils beurteilen zu können, möchte ich 
Sollwert und Istwert über das komplette Spektrum auftragen. D.h. ich 
erhöhe kontinuierlich den Sollwert (kann Werte zwischen 0 und 1023 
annehmen) und sehe mir dazu die Istwerte an. Geregelot wird jedes mal 
wenn ein Interrupt aufgerufen wird in der ISR. Am Ende meiner ISR erhöhe 
ich meine globale Variable j um 1, jedes mal wenn j den Wert 100 
erreicht, wird mein Sollwert um 1 erhöht und j wieder zurück auf Null 
gesetzt. Unabhängig davon, ob ich j als static oder volatile definiere 
funktioniert die ganze Sache nicht. Wißt ihr woran das liegen könnte 
oder habt ihr eine bessere Lösung? Hier das Programm:

/*********************************************
Project : Programm zur Beurteilung des Regelverhaltens: v_soll wird 
kontinuierlich erhöht und v_ist entsprechend auf dem Terminal 
ausgegeben.

Chip type           : ATmega323
Program type        : Application
Clock frequency     : 3.686400 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 512
*********************************************/

#include <mega323.h>

// Standard Input/Output functions
#include <stdio.h>
#include <stdlib.h>
#include <delay.h>


#define ADC_VREF_TYPE 0x00
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE;
// Start the AD conversion
ADCSR|=0x40;
// Wait for the AD conversion to complete
while ((ADCSR & 0x10)==0);
ADCSR|=0x10;
return ADCW;
}

unsigned int v_ist;
int e_k;    // Regelabweichung
int e_k_alt;
float k_p =1;    // 1.446 Verstärkungsfaktor
int u_p;        // Stellgröße
int u_p_alt;
unsigned int v_soll;
int stell;
char istwert[4];
static int j;




// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
  // aktuelle Spannung einlesen (Wert zwischen 0 und 1023):
  v_ist = read_adc(0);


  // Regelabweichung e_k berechnen:
   e_k = v_soll - v_ist;


   // P-Regler (mit "gleitendem" Offset v_soll)
    u_p = e_k * k_p + v_soll;


      // Stellgrößenbegrenzung:
       if (u_p > 600) u_p = 600;
       else if (u_p < 400) u_p = 400;

       // Stellgröße in entsprechenden PWM Wert umrechnen:
       stell = (int) u_p;

       // Pulsbreite setzen:
       OCR1A = stell;

       u_p_alt = u_p;
       e_k_alt = e_k;


       itoa(read_adc(0),istwert);
       puts(istwert);
        // Laufvariable j um 1 erhöhen:
       j++;
}


void main(void)
{


// Input/Output Ports initialization
// Port A initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In 
Func7=In
// State0=T State1=T State2=T State3=T State4=T State5=T State6=T 
State7=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In 
Func7=In
// State0=T State1=T State2=T State3=T State4=T State5=T State6=T 
State7=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func0=Out Func1=Out Func2=Out Func3=Out Func4=Out Func5=Out Func6=Out 
Func7=Out
// State0=1 State1=1 State2=1 State3=1 State4=1 State5=1 State6=1 
State7=1
PORTC=0xFF;
DDRC=0xFF;

/// Port D initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=Out Func6=In 
Func7=In
// State0=T State1=T State2=T State3=T State4=T State5=0 State6=T 
State7=T
PORTD=0x00;
DDRD=0x20;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;


// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value:
// TCCR1B=0x04: 4.400 kHz/ 2046 = 7 Hz
// TCCR1B=0x01: 3686.400 kHz/2046 = 1800 Hz
// Mode: Ph. correct PWM top=03FFh
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x83;
TCCR1B=0x01;
TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;


// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: TCCR2=0x07: 3600 Hz  -> t_0 = 1/(3600/255) = 70.83 ms
//    TCCR2=0x06; 14400 Hz -> t_0 = 1/(14400/255) = 17,708 ms
//    TCCR2=0x05; 28800 Hz -> t_0 = 1/(28800/255) = 8,85 ms
//              TCCR2=0x02; 460800 Hz -> t_0 = 1/(460800/255) = 0,553 ms
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
GICR|=0x00;
MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 115200
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x01;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
// Analog Comparator Output: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 115,200 kHz => T=1/f=1/115200 Hz = 0,00868 ms
// ADC Voltage Reference: AREF pin
ADMUX=ADC_VREF_TYPE;
ADCSR=0x85;

// Global enable interrupts
#asm("sei")


// ################## PROGRAMMSTART ######################
// zum Starten des Programmas wird das Zeichen "s" eingelesen:
if (getchar() == 's')
{

  // Timer 2 der die Interrupts auslöst loslaufen          //lassen:
  TCCR2=0x05;


        // bis v_soll seinen Maximalwert 1023 erreicht hat, 
//folgendes tun:
  while (v_soll < 1024)
  {
        // jedes mal wenn j den Wert 100 erreicht hat,
        // wird der Sollwert um 1 erhöht:
  if (j == 100)
  {
    v_soll += 1;

    // j wieder zurücksetzen
    j = 0;
  }
  }
}
}

von Stefan G. (Gast)


Lesenswert?

Hallo,
vielleicht war das alles etwas kompliziert ausgedrückt. ich probier´s 
nochmal einfacher:

Ich habe eine Variable die innerhalb einer Interrupt Service Routine 
verwendet wird. Diese Variable vom Typ int soll, nachdem die Interrupt 
Service Routine 100 mal aufgerufen wurde um 1 erhöht werden. Dies soll 
solange passieren, bis die Variable den Wert 1023 erreicht hat. Kann ja 
eigentlich nicht so schwer sein. Aber wie mache ich das so, daß es 
funktioniert?

(Alternativ kann die Variable auch erstmal bei jedem Aufruf der ISR um 
1 erhöht werden.)
Hat nun jemand eine Idee wie ich das bewerkstelligen kann?
Gruß,
Stefan

von Oliver (Gast)


Lesenswert?

Hallo Stefan,

statt static für v_soll und j volatile verwenden.

Dies sollte funktionieren. Übrigens, werden Variablen außerhalb einer 
Funktion definiert, so sind sie immer static, oder irre ich mich da?

Grüße
Oliver

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.