mikrocontroller.net

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


Autor: Stefan G. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
  }
  }
}
}

Autor: Stefan G. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.