www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Amega8 Kommunikation mit Interrups


Autor: Joe F. (joe1234)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Forengemeinde,

also vorab: ich bin ein totaler Anfänger! Aber ich gebe mir Mühe.

Ich habe den Atmega8 und das STK500-Board. Dazu habe ich einen Code 
geschrieben, den ich dann auf den Atmega8 flashe.

CODE:

#include <avr/io.h>          // Register Definition fuer ATmega8
#include <avr/interrupt.h>    // Für Timer1 Overflow-Interrupt
#include <util/delay.h>      // Für Delay-Funktion

#define FOSC 8000000      // Clock Speed = Oszillator-Freq.
#define BAUD 9600        // Muss in Matlab übereinstimmen
#define MYUBRR FOSC/16/BAUD-1  // Siehe Datenblatt unter USART

/*------------------------------------------------------------------
globale Variablen
------------------------------------------------------------------*/
volatile uint16_t stepsTiH;
volatile uint16_t stepsTiL;
volatile uint16_t stepsTw;

/*------------------------------------------------------------------
Funktionen zum USART - RS232
------------------------------------------------------------------*/
// Initialisierung --> Einstellungen in Matlab MÜSSEN GLEICH SEIN
void USART_Init( unsigned int ubrr)
{
  /* Set baud rate */
  UBRRH = (unsigned char)(ubrr>>8);
  UBRRL = (unsigned char)ubrr;
  /* Enable receiver and transmitter */
  UCSRB = (1<<RXEN);
  /* Set frame format: 8data, 2stop bit */
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

// 8-bit Wort empfangen
uint16_t USART_Receive(void)
{
  /* Wait for data to be received */
  while(!(UCSRA & (1<<RXC)))
  {
  }
  /* Get and return received data from buffer */
  return UDR;
}

/*------------------------------------------------------------------
Funktionen zum Timer1
------------------------------------------------------------------*/
void Timer1_WriteTCNT1(void)
{
  unsigned char sreg;
  /* Save Global Interrupt Flag */
  sreg = SREG;
  /* Disable interrupts */
  cli();
  /* Set TCNT1 to i */
  TCNT1H = stepsTiH;     //Lade Timer1 mit Wert
  TCNT1L = stepsTiL;    //Anzahl Schritte bis zum Overflow
  /* Restore Global Interrupt Flag */
  SREG = sreg;
}

//Zeitpunkt des Aufrufs von Timer1_An() entspricht SOI
void Timer1_AN(void)
{
  Timer1_WriteTCNT1();
  PORTB = 0b00000000;
  TCCR1B = (1<<CS10);   //kein prescale verwenden
    TIMSK = (1<<TOIE1);   //Interrupt für Timer1 enable
  sei();          //globale Interrupts enable
  SREG |= (1 << SREG_I);
}

void Timer1_AUS(uint16_t anzSchritte)
{
  TCCR1B = (0<<CS10);    //Timer1 aus
  PORTB = 0b11111111;    //Ausgang PortB

  for(int i = 0; i < anzSchritte; i = i+1)
  {
    _delay_ms(10);    //Wartezeit
  }
}

ISR(TIMER1_OVF_vect)
{
  Timer1_AUS(stepsTw);  //Warteroutine
  Timer1_AN();
}

/*------------------------------------------------------------------
main
------------------------------------------------------------------*/
int main (void)
{
  USART_Init(MYUBRR);          //UART initialisieren

  DDRB = 0b11111111;          //PORTB als Ausgang
  PORTB = 0b11111111;

  uint16_t checkSum = 0;
  uint16_t data1 = 0;
  uint16_t data2 = 0;
  uint16_t data3 = 0;

  while(1)
  {
    data1 = USART_Receive();    //Empfangene Daten1,ti(1..8)
    data2 = USART_Receive();    //Empfangene Daten2,ti(9..16)
    data3 = USART_Receive();    //Empfangene Daten3,tw(1..8)

    checkSum = data1+data2+data3;  //Summe der 3 Daten(Urzustand)

    if(checkSum == 0)
    {
      TCCR1B = (0 << CS10);    //Timer1 aus
      PORTB = 0b11111111;      //Ausgang PortB
    }
    else
    {
      stepsTiH = data1;      //Definieren stepsTiH
      stepsTiL = data2;      //Definieren stepsTiL
      stepsTw = data3;      //Definieren stepsTw
      Timer1_AN();        //Starten von Timer1
    }
  }
}

Kurze Erläuterung:
Ich übertrage 3 Variablen mit Matlab. Diese werden in data1,data2,data3 
gespeichert. Die Variablen (data...) benötige ich für den Timer1_AN().
Im Grunde genommen liegt eine Spannung an, die für einen "Augenblick" 
(hier ist die Eingabe von data1 und data2 zuständig) unterbrochen wird. 
data3 ist eine Art "Wartezeit" bis zum nächsten Start.

Nun habe ich auf dieser Seite
http://www.mikrocontroller.net/articles/Interrupt
gesehen, dass man neben senden auch empfangen kann. Hier wird sogar eine 
LED zum Morsen von Daten verwendet. Leider verstehe ich den Code nicht 
wirklich. Vor allem empfängt meine Funktion "uint16_t 
USART_Receive(void)" ein 8 Bit Wort, in dem Beispielcode ist aber nur 
von einem String die Rede.

Meine Frage nun: Wie kann ich die 2 Sachen kombinieren?

Endsituation sollte sein:
Ich möchte Daten übertragen, die übertragenen Daten sollen 
zurückgesendet werden, am besten mit dieser Morseled, und dann sollten 
auch noch meine Timer1_AN() Funktion anlaufen.

Gruß Joe

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes F. schrieb:

> Nun habe ich auf dieser Seite
> http://www.mikrocontroller.net/articles/Interrupt
> gesehen, dass man neben senden auch empfangen kann. Hier wird sogar eine
> LED zum Morsen von Daten verwendet. Leider verstehe ich den Code nicht
> wirklich. Vor allem empfängt meine Funktion "uint16_t
> USART_Receive(void)" ein 8 Bit Wort, in dem Beispielcode ist aber nur
> von einem String die Rede.
>
> Meine Frage nun: Wie kann ich die 2 Sachen kombinieren?

Hmm.
Irgendwie verstehe ich die Fragestellung nicht wirklich.
Denn auch die Sende-Funktionalität für Strings stützt sich letzten Endes 
auch auf eine Funktion die 1 Byte sendet. Du hast einzelne Bytes und 
eine Funktion die 1 Byte senden kann. Passt doch perfekt!

Am besten siehst du dir den Artikel aus dem avr-gcc-tutorial näher an:
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Da wird dir UART senden auf die einfachere Variante (ohne Interrupt) 
näher gebracht.

> Endsituation sollte sein:
> Ich möchte Daten übertragen, die übertragenen Daten sollen
> zurückgesendet werden, am besten mit dieser Morseled,

zurückgesendet wohin?
Und wozu brauchst du dann die Morseled?
Diese LED ist doch nur 1 Beispiel, was man mit den Daten machen kann hat 
aber mit dem eigentlichen Thema UART senden/empfangen nichts zu tun.

Autor: joe1234 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal danke für die Antwort!

Vorab:
MorseLED sollte nur auf mein Board, wenn es möglich ist, also als ein 
kleiner Bonus.

Wie man aus meinem Programm sieht, habe ich das Senden und Empfangen 
OHNE Interrupt erfolgreich hinbekommen. Problem ist halt, dass ich in 
der while- Schleife ständig im Zustand "data1 = USART_Receive();" mich 
befinde, erst wenn was gesendet wird, dann geht es weiter. Dies wollte 
ich nun umgehen, so dass ich mich ebend NICHT in diesem Zustand befinde. 
Ich SOLL erst in diesen Zustand, wenn auch wirklich ein Information 
geschickt wird, also ein Interrupt ausgelöst wird.

Frage:
Welche Funktion im Beispielcode entspricht meiner "USART_Receive()" 
Funktion?

Gruß Joe

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
joe1234 schrieb:

> Wie man aus meinem Programm sieht, habe ich das Senden und Empfangen
> OHNE Interrupt erfolgreich hinbekommen. Problem ist halt, dass ich in
> der while- Schleife ständig im Zustand "data1 = USART_Receive();" mich
> befinde, erst wenn was gesendet wird, dann geht es weiter.

Dann ändere das doch :-)
Deine USART_Receive muss ja nicht in der while Schleife hängen, wenn 
nichts da ist. Du bist der Programmierer. Du bestimmst, was passieren 
soll. Die Funktion kann genau so gut auch zum Aufrufer zurückkehren und 
mitteilen: "War nichts da!"
Und der Aufruf sagt sich dann: Na gut, wenn nichts da ist, dann mach ich 
auch nichts oder ich mach in der Zwischenzeit was anderes und schau in 
einer Hunderstelsekunde oder wann ich das nächste mal wieder Zeit habe, 
erneut nach. Das nennt sich dann Polling: in regelmässigen Zeitabständen 
nachsehen, ob es was zu tun gibt.

> Welche Funktion im Beispielcode entspricht meiner "USART_Receive()"
> Funktion?

Das kann man so nicht vergleichen
IM Beispielcode wird von der UART ein Interrupt ausgelöst, wenn ein 
Zeichen vollständig reinkommt und die ISR(USART_RXC_vect) aufgerufen. 
Die behandelt dann das eine Zeichen.

Autor: joe1234 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier habe ich nun einen Code geschrieben, leider OHNE Interrups. :-(
Problem bei meinem Code ist, dass wenn ich z.B. ti und tw auf 10 setze, 
bruacht der Atmega8 fast 1:40 min um die Operation auszuführen. Danach 
geht die LED erst wieder an. Mache ich da was flasch???

Code:
#include <avr/io.h>          // Register Definition fuer ATmega8
#include <avr/interrupt.h>    // Für Timer1 Overflow-Interrupt
#include <util/delay.h>      // Für Delay-Funktion

#define FOSC 8000000      // Clock Speed = Oszillator-Freq.
#define BAUD 9600        // Muss in Matlab übereinstimmen
#define MYUBRR FOSC/16/BAUD-1  // Siehe Datenblatt unter USART

/*------------------------------------------------------------------
globale Variablen
------------------------------------------------------------------*/
volatile uint16_t stepsTiH;
volatile uint16_t stepsTiL;
volatile uint16_t stepsTw;

/*------------------------------------------------------------------
Funktionen zum USART - RS232
------------------------------------------------------------------*/
// Initialisierung --> Einstellungen in Matlab MÜSSEN GLEICH SEIN
void USART_Init(unsigned int ubrr)
{
  /* Set baud rate */
  UBRRH = (unsigned char)(ubrr>>8);
  UBRRL = (unsigned char)ubrr;
  /* Enable receiver and transmitter */
  UCSRB = (1<<RXEN)|(1<<TXEN);
  /* Set frame format: 8data, 2stop bit */
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

// 8-bit Wort empfangen
uint16_t USART_Receive(void)
{
  /* Wait for data to be received */
  while(!(UCSRA & (1<<RXC)))
  {
  }
  /* Get and return received data from buffer */
  return UDR;
}

// 8-bit Wort senden
void USART_Transmit(unsigned char data)
{
  /* Wait for empty transmit buffer */
  while ( !( UCSRA & (1<<UDRE)) )
  {
  }
  /* Put data into buffer, sends the data */
  UDR = data;
}

/*------------------------------------------------------------------
Funktionen zum Timer1
------------------------------------------------------------------*/
void Timer1_WriteTCNT1(void)
{
  unsigned char sreg;
  /* Save Global Interrupt Flag */
  sreg = SREG;
  /* Disable interrupts */
  cli();
  /* Set TCNT1 to i */
  TCNT1H = stepsTiH;     //Lade Timer1 mit Wert
  TCNT1L = stepsTiL;    //Anzahl Schritte bis zum Overflow
  /* Restore Global Interrupt Flag */
  SREG = sreg;
}

//Zeitpunkt des Aufrufs von Timer1_An() entspricht SOI
void Timer1_AN(void)
{
  Timer1_WriteTCNT1();
  //PORTC = 0b00000000;
  PORTC = (0 << PC0);
  TCCR1B = (1<<CS10);   //kein prescale verwenden
    TIMSK = (1<<TOIE1);   //Interrupt für Timer1 enable
  sei();          //globale Interrupts enable
  SREG |= (1 << SREG_I);
}

void Timer1_AUS(uint16_t anzSchritte)
{
  TCCR1B = (0<<CS10);    //Timer1 aus
  //PORTC = 0b11111111;  //Ausgang PortC
  PORTC = (1 << PC0);

  for(int i = 0; i < anzSchritte; i++)
  {
    _delay_ms(10);    //Wartezeit midestens 10 ms
  }
}

ISR(TIMER1_OVF_vect)
{
  Timer1_AUS(stepsTw);  //Warteroutine
  Timer1_AN();
}

/*------------------------------------------------------------------
main
------------------------------------------------------------------*/
int main (void)
{
  USART_Init(MYUBRR);        //UART initialisieren

  DDRC = (1 << PC0);         // PC0 als Ausgang festlegen für Impuls
  PORTC = (1 << PC0);        // PC0 aktivieren
  DDRB = (1 << PB1);         // PB1 als Ausgang festlegen für Diode


  uint16_t checkSum = 0;
  uint16_t data1 = 0;
  uint16_t data2 = 0;
  uint16_t data3 = 0;


  while(1)
  {
    PORTB = (0 << PB1);       //PB1 aktivieren, LED leuchtet

    data1 = USART_Receive();    //Empfangene Daten1,ti(1..8)
    data2 = USART_Receive();    //Empfangene Daten2,ti(9..16)
    data3 = USART_Receive();    //Empfangene Daten3,tw(1..8)

    checkSum = data1+data2+data3;  //Summe der 3 Daten(Urzustand)


    if(checkSum == 0)
    {
      USART_Transmit(73);      //I
      USART_Transmit(78);      //N
      USART_Transmit(74);      //J
      USART_Transmit(69);      //E
      USART_Transmit(67);      //C
      USART_Transmit(84);      //T
      USART_Transmit(79);      //O
      USART_Transmit(82);      //R
      USART_Transmit(data1);    //Übertragen data1
      USART_Transmit(data2);    //Übertragen data2
      USART_Transmit(data3);    //Übertragen data3
      PORTB = (1 << PB1);     //PB1 deaktivieren, LED geht aus
      TCCR1B = (0 << CS10);    //Timer1 aus
      PORTC = (1<<PC0);      //PC0 auf 1 legen, Ausgangszustand
    }
    else
    {
      stepsTiH = data1;      //Definieren stepsTiH
      stepsTiL = data2;      //Definieren stepsTiL
      stepsTw = data3;      //Definieren stepsTw
      USART_Transmit(data1);    //Übertragen data1
      USART_Transmit(data2);    //Übertragen data2
      USART_Transmit(data3);    //Übertragen data3
      PORTB = (1 << PB1);     //PB1 deaktivieren, LED geht aus
      Timer1_AN();        //Starten von Timer1
    }
  }
}

Autor: joe1234 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin schier am verzweifeln...
Wenn ich die 2 Befehle mit LED aus der while- Schleife entferne, dann 
läuft alles rund. Sobald ich sie wieder benutze, zickt der Atmega8!!!

Gruß Joe

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.