www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Probleme mit der Datenausgabe per UART durch Interrupts AtMega168


Autor: Christoph Büttgen (christophbu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

nachdem mir die Suchfunktion nicht mehr weiterhelfen kann und auch meine 
Bekannten mir nicht mehr helfen konnten wende ich mich mit meinem 
Problem ans Forum.

Ich habe die Aufgabe 2 4-schrittige Quadraturencoder auszulesen und 
diese Daten an den Rechner zu schicken, damit eine Weiterverarbeitung in 
Labview folgen kann. Das Programm zum Auslesen basiert auf dem 
Beispielcode von Peter Dannegger. Zur Kommunikation mittels Uart 
verwende ich fertige Dateien und Initialisierungsbefehle von Peter 
Fleury.
Ich verwende einen ATMega 168 Crumb Modul. Dieses Modul trägt den 
ATMega168 einen UART zu USB Wandler und ein Quarz das, auf 20 MHz 
taktet.
Die Versuche Strings per UART in der Mainmethode zu senden waren 
erfolgreich und konnten mit Putty angezeigt werden.

Es sollte ein Programm folgen, dass über Interrupts die Encoder 
ausliest, und die Werte sendet.
Ich möchte Timer 0 verwenden um die Encoder auszulesen und Timer 2 um 
die akkumulierten Werte auszugeben.
Um eine Beschädigung der Encoder vollständig auszuschließen. Wird das 
Programm getestet, ohne dass sie angeschlossen sind. Es müsste die 
durchgehende Ausgabe des Wertes 0 für jeden Encoder folgen.
Leider funktioniert nichts. Putty detektiert keine Datenausgabe des 
Mikrocontrollers. Die Kompilierung des C-Programms erzeugt 0 Warnungen.
Wo liegt der logische Fehler in diesem Programm?

gruß Christoph
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "uart.h"


#ifndef F_CPU

#warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 20000000"
#define F_CPU 20000000UL  // Systemtakt in Hz - Definition als unsigned long beachten 
                         // Ohne ergeben sich unten Fehler in der Berechnung
#endif
 
#define UART_BAUD_RATE      9600
//Target Atmega 168



#define PHASE_A1 (PINC & 1<<PINC0)
#define PHASE_B1 (PINC & 1<<PINC1)
#define PHASE_A2 (PINC & 1<<PINC2)
#define PHASE_B2 (PINC & 1<<PINC3)



int8_t enc_delta1; //-128 ... 127
int8_t enc_delta2;
int8_t Wert1 = 0;
int8_t Wert2 = 0;
char out1[4]  ;
char out2[4]  ;

void encode_init(void)
{
TCCR2B = (1<<WGM22) | (1<<CS22) | (1<<CS21) | (1<<CS20);
OCR2B = 10;
TCCR0B = (1<<WGM01) | (1<<CS02) | (1<<CS00);
OCR0B = 1;
TIMSK2 = 1<<OCIE2B;
TIMSK0 = 1<<OCIE0B; 
//beide Zähler initialisieren
}


ISR (TIMER2_COMPB_vect) //Abtastzeit
{
static int8_t last1;
static int8_t last2;
int8_t new1,diff1;
int8_t new2,diff2;
new1 = 0;
if(PHASE_A1)
  new1 = 3;
if(PHASE_B1)
  new1 ^=1; //convert grey to binary
diff1 = last1 -new1; //difference last - new
if (diff1 & 1){ //bit 0 = value (1)
  last1 = new1; //store new as next last
  enc_delta1 += (diff1 & 2) -1; //bit 1 = direction(+/-)
  }

new2 = 0;
if(PHASE_A2)
  new2 = 3;
if(PHASE_B2)
  new2 ^=1; //convert grey to binary
diff2 = last2 -new2; //difference last - new
if (diff2 & 1){ //bit 0 = value (1)
  last2 = new2; //store new as next last
  enc_delta2 += (diff2 & 2) -1; //bit 1 = direction(+/-)
  }

}

ISR (TIMER0_COMPB_vect){ //Interrupt, der per UART daten an den PC sendet
cli();
itoa(Wert1,out1,10);
itoa(Wert2,out2,10);
uart_puts(out1);
uart_puts("\r\n");
uart_puts(out2);
uart_puts("\r\n");
Wert1 = 0;
Wert2 = 0;
sei();
}



int8_t encode_read1(void) //read four step encoders
{
int8_t val1;
cli();
val1 = enc_delta1;
enc_delta1 &= 3;
sei();
return val1 >> 2;
}

int8_t encode_read2(void) //read four step encoders
{
int8_t val2;
cli();
val2 = enc_delta2;
enc_delta2 &= 3;
sei();
return val2 >> 2;
}

int main(void)
{
  
  encode_init();
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );   

  sei();
  
  while(42){
  
  Wert1 =Wert1 + encode_read1();
  Wert2 =Wert2 + encode_read2();
  }

return 0;
}

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ISR (TIMER0_COMPB_vect){ //Interrupt, der per UART daten an den PC sendet
cli();
itoa(Wert1,out1,10);
itoa(Wert2,out2,10);
uart_puts(out1);
uart_puts("\r\n");
uart_puts(out2);
uart_puts("\r\n");
Wert1 = 0;
Wert2 = 0;
sei();
}
Grusel.

Raus mit dem ganzen Zeug aus dem Interrupts. Dann klappts auch mit dem 
Encoder. Merke: In Interrupts kommt nur das allernotwendigste. 
Verarbeitung in main.

>Interrupt, der per UART daten an den PC sendet

Spätestens, wenn ich das 'U' in dem Kommentar tippen würde, würde ich 
wahrscheinlich so ein unkontrollierbares Zittern kriegen.

Autor: Tom M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schliesse mich meinem Vorredner an bezüglich UART...

Lass die sei() cli() Orgie in den ISR weg. cli macht ohnehin keinen Sinn 
in der ISR, da beim IRQ das I-Flag ohnehin gelöscht ist (keine "nested 
interrupts" per Default).

Bist sicher, dass uart_* bei gesperrten Interrupts funktioniert?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Wenn ich mich nicht verrechnet habe, schlägt dein Timerinterrupt 
(TIMER0_COMPB_vect) alle 102,4 µs zu. Die Übertragung eines Zeichens bei 
9600 Baud dauert 1,04mS. Das sollte dir zu denken geben. Ansonsten 
schließe ich mich  Grrrr an.

MfG Spess

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> schlägt dein Timerinterrupt
> (TIMER0_COMPB_vect) alle 102,4 µs

Na dann sollte Christoph mal seine Strategie neu überdenken. Alle 102,4 
µs was tun, was mindestens 1,04ms dauert? Da hilft auch auslagern in 
main nichts. Ist aber auf jeden Fall der bessere Weg.

Autor: Christoph Büttgen (christophbu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erst mal für die Antworten. Ich werde es ohne Interrupts 
versuchen.

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.