Hallo,

kann es sein dass sich der UART Interrupt und der Timer Interrupt gegenseitig stören?

Erleutere aber am besten erst mal meine Problemstellung:

Atmega88, Programiersprache C

Also,

mit dem Timer Interrupt erzeuge ich mir ein Signal.
Bei diesem Signal (Highpegel ) sollen alle ca. 90ms neun Low-Pegel mit
einer bestimmten Länge erzeugt werden.

Also erst mal 90ms Highpegel, dann ein Lowpegel von 45µs, ein Highpegel
von 120µs, 50µs Low, 120µs High, 50µs Low, 120µs High, 50µs Low, 120µs
High, 50µs Low, 120µs High, 50µs Low, 120µs High, 50µs Low, 120µs High,
50 µs Low, 120 High, 40 µs Low und dann wieder 90ms Pause.

Mit diesem auf den ersten Blick komischen Signal soll ein Servo
angesteuert werden. Kein Standard Servo! Dieser Servo benötigt ein
Start-Bit(hier die 45 µs) und dann 8 weitere Bit für die jeweilige
Stellung. Dabei sind 40µs eine 0, und 50µs eine 1. Heißt also wenn
alle Bits 1 sind ganz nach rechts, wenn alle Bits 0 sind ganz nach
links. Die voreingestellten Werte sind für die Mittelstellung.

Nun soll ein ankommendes Byte über UART so ausgewertet werden, dass
mir die Bits entsprechend gesetzt werden. Funktioniert auch alles
bestens.

Nun benutze ich das STK500 mit einem Atmega88 drauf. AD-Wandler
eingerichtet und den Servo über ein Poti gesteuert. Klappt auch alles
Prima. Servo fährt in alle Positionen und auch ohne diese komischen
Ausschläge alle paar Sekunden.

Das Problem tritt nur auf, wenn ich jetzt zwei STK500 verwende. Das
eine verwende ich als Sender, das andere als Empfänger. Verbunden sind
die beiden über UART. Masse ist auch verbunden. Wenn ich nun mit einem
Poti an einen Board, den Servo am anderen Board steuern will treten
diese komischen Ausschläge des Servos alle paar Sekunden auf. Ansonsten
fährt der Servo aber in die gewünschten Positionen.

Nun weiß ich nicht wie ich diese komischen Ausschläge da weg bekommen
kann.....

Hier der Code:

Code:
#define F_CPU 14745600 

#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define FOSC 14745600 //Clock Speed
#define BAUD 9600
#define UBRR ((FOSC / (BAUD * 16L)) - 1)

#define STATE_IDLE    			10
#define STATE_SERVO1  			20
#define STATE_SERVO2  			30
#define STATE_PWM     			40

// Initialisierung Timer0
void timer0_init();

//// Initialisierung Timer1
void timer1_init();

// Initialisierung Timer2
void timer2_init();

//Initialisierung UART
void uart_init();

//Werte für das erste Signal
volatile unsigned char Array_Servo1[] = { 20, 45, 245, 54, 255, 54, 255, 54, 255, 54, 255, 54, 255, 54, 255, 54, 255, 35};

//Werte für das zweite Signal
volatile unsigned char Array_Servo2[] = { 20, 45, 245, 54, 255, 54, 255, 54, 255, 54, 255, 54, 255, 54, 255, 54, 255, 35};

//Zähler für ausgelösten Compare-Interrupt beim ersten Signal
volatile unsigned char NrCompare_Servo1 = 0;

//Zähler für ausgelösten Compare-Interrupt beim zweiten Signal
volatile unsigned char NrCompare_Servo2 = 0;

//Zähler für das erste Signal
volatile unsigned int Count_Servo1 = 0;

//Zähler für das zweite Signal
volatile unsigned int Count_Servo2 = 0;

unsigned char i, d;

//Hilfsaray zur Byteauswertung beim UART-Empfang für Servo1
unsigned char array1[8];

//Hilfsaray zur Byteauswertung beim UART-Empfang für Servo2
unsigned char array2[8];

//Zeiger für die Byteauswertung beim UART-Empfang für Servo1
unsigned char *tmp;

//Zeiger für die Byteauswertung beim UART-Empfang für Servo2
unsigned char *tmp2;

unsigned char c;


/*Funktion des Interrupts: Die Schleife wird 18 mal durchlaufen. Darin wird geschaut ob NrCompare_Servo1 in diesem Durchlauf 
  gerade oder ungerade ist und dementsprechend der Port ein oder ausgeschaltet. Hat NrCompare_Servo1 das ganze Array
  abgearbeitet, fängt es wieder von vorne an.
  Danach wird der neue Wert in das Register OCR2A geschrieben. Der Timer zählt dann bis zu diesem Wert, führt ein 
  Interrupt aus, schaltet den Port um und setzt den Timer wieder auf 0 (da CTC-Modus). Das ergibt hinterher ein 
  Signal mit einem dauernden Highpegel und neun "verschiedenen" Lowpegeln. Also erster Wert Array_Servo1[0] = Highpegel,
  zweiter Wert Array_Servo1[1] = Lowpegel usw.  
  Count_Servo1 wird dann noch bis 8216 hochgezählt, um zwischen den Signalen eine Pause von ca. 90ms zu erzeugen.*/
ISR(TIMER2_COMPA_vect)
{

//erstes Signal
  {
  if(Count_Servo1 <= 17 ){				//Schleife wird 18 mal durchlaufen, also für jeden Wert des Array_Servo1 ein mal

  if(NrCompare_Servo1 % 2 == 0)			//Wenn gerade, dann ausschalten
  	PORTC &= ~(1 << PC0);

  else
  	{PORTC |= (1 << PC0);}				//Wenn ungerade, dann einschalten
	                  

  NrCompare_Servo1++; 					//Wird bei jedem Interrupt um eins hochgezählt
  if( NrCompare_Servo1 == sizeof(Array_Servo1) / sizeof(unsigned char) ) 
	  NrCompare_Servo1 = 0;
	

	OCR2A = Array_Servo1[ NrCompare_Servo1];	// Den Timer damit laden
   }

  else
  {PORTC |= (1 << PC0);}  				//Highpegel während der 90ms Pause
  }

//Zweits Signal
  {

  
  if((Count_Servo2 >= 19) && (Count_Servo2 <= 36)){

  if(NrCompare_Servo2 % 2 == 0)
  	PORTC &= ~(1 << PC2);

  else
  	{PORTC |= (1 << PC2);}
	                  

  NrCompare_Servo2++; 
  if( NrCompare_Servo2 == sizeof(Array_Servo2) / sizeof(unsigned char) )
	  NrCompare_Servo2 = 0;
	

	OCR2A = Array_Servo2[NrCompare_Servo2];	// Den Timer damit laden
   }

  else
  {PORTC |= (1 << PC2);}
  }


  Count_Servo1++;
  	
  if(Count_Servo1 == 8216)  //erzeugt eine pause von ca.90ms
     Count_Servo1 = 0;


  Count_Servo2++;
  	
  if(Count_Servo2 == 8216) ////erzeugt eine pause von ca.90ms
     Count_Servo2 = 0;

}


void timer2_init()
{
  DDRC  =  0xFF; // PORTC als Ausgang schalten
  
  PORTC =  0x00; // Alle Ausgaenge auf 0 schalten

  OCR2A = 0;

  TCCR2B |= (1 << CS21);     // Teiler 8
  
  TCCR2A |= (1 << WGM21);	 // CTC Modus
   				
  TIMSK2 |= (1 << OCIE2A);   // Timer 2 Compare Interrupt enable

}

/* Timer0 initialisieren */
void timer1_init()
{

	OCR1A = 100;	//Wert 100 im Compare Register setzen

	DDRB   = 0xff;	// Als Ausgänge 

	PORTB =  0x00;

	TCCR1A = (1<<COM1A1)|(1<<COM1A0)|(1<<WGM10); //PWM Phase Correct

	TCCR1B = (1<<CS11) | (1 << WGM12); // No prescaling

}


void uart_init()
{

DDRB |= (1 << PB2) | (1 << PB4);

/* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);

/* baud rate*/
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;

/* Frame Format: 8Data-Bit, 2Stop-Bit*/
UCSR0C = (1 << USBS0) | (3 << UCSZ00);

}


// Das Hauptprogramm (Einsprungpunkt)
int main()
{
	
	//UART initialisieren
	uart_init();

	//Timer1 initialisieren
	timer1_init();

	//Timer2 initialisieren
	timer2_init();

    // Interrupts aktivieren
    sei();

    // Eine Endlosschleife.  
    while (1)
    {}
}


ISR(USART_RX_vect)
{

static unsigned char state = STATE_IDLE;

	c = UDR0;

	switch (state)
   {
    case STATE_IDLE:
             if(c == 'b')
             {
                 state=STATE_SERVO1;
             }
             if(c == 'c')
             {
                 state=STATE_SERVO2;
             }
			 if(c == 'a')
			 {
			 	state=STATE_PWM;
			 }
			 break;


    case STATE_SERVO1:
             tmp = array1;
  				for( i = 1; i; i *= 2 )
    			*(tmp++) = (c&i) ? 54 : 35;

				Array_Servo1[3]  = array1[0];
				Array_Servo1[5]  = array1[1];
				Array_Servo1[7]  = array1[2];
				Array_Servo1[9]  = array1[3];
				Array_Servo1[11] = array1[4];
				Array_Servo1[13] = array1[5];
				Array_Servo1[15] = array1[6];
				Array_Servo1[17] = array1[7];
			
			 state = STATE_IDLE;
             break;

	case STATE_SERVO2:
			tmp2 = array2;
  				for( i = 1; i; i *= 2 )
    			*(tmp2++) = (c&i) ? 54 : 35;

				Array_Servo2[3]  = array2[0];
				Array_Servo2[5]  = array2[1];
				Array_Servo2[7]  = array2[2];
				Array_Servo2[9]  = array2[3];
				Array_Servo2[11] = array2[4];
				Array_Servo2[13] = array2[5];
				Array_Servo2[15] = array2[6];
				Array_Servo2[17] = array2[7];
			
			 state = STATE_IDLE;
             break;


    case STATE_PWM:
			 OCR1A = c;

			 state = STATE_IDLE;
			 break;

    default:
             break;
    }
}