PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART&Timer Interrupt gleichzeitig?



Funky
05.09.2006, 08:41
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:


#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;
}
}