Forum: Mikrocontroller und Digitale Elektronik RS232 Daten übertragung


von Achim (Gast)


Lesenswert?

Hi.

Ich will über eine rs232 schittstelle daten übertragen.
Um dem AVR ein kommando zu senden, sende ich einfach ein byte. nun muss
ich aber auch in manchen fällen werte (von mehreren bytes) zum AVR
übertragen.
Jetzt wollte ich fragen, wie ich das am besten mache. Da müsst ich ja
ein kommando voraus senden, das mir eine mehr byte übertragung
initialisiert. oder wär es besser, jedes kommando aus 3 bytes bestehen
zu lassen? Das erste byte wäre dann immer das kommando und die 2
anderen die (optimalen) parameter.

Gibts dazu ein beispiel, wie ich sowas machen kann ?

MfG Achim

von Hubert (Gast)


Lesenswert?

In C gibt es für so was Librarys

von Dieter (Gast)


Lesenswert?

"In C gibt es für so was Librarys"
Prima sinnfreie Aussage. Hättest auch schreiben können:
"In Assembler gibt es für so was Librarys".

Über die Rechtschreibung und das gute Deutsch schreibe ich jetzt mal
lieber nichts.

Zum Thema:

Wie Du das am besten machst, hängt von der Anwendung ab.
In mittleren bis grossen Applikationen ist es sinnvoll, das Ganze über
eine Zustandsmaschine mit (Ring-)Puffer und Interrupt zu lösen.

Was muss denn der MC alles machen?

von Achim (Gast)


Lesenswert?

Der µC mus folgendes machen:

- Messwerte von sensor erfassen (jede 3 Sekunden)
- Ein 4x 27 Text-Display ansteuern (mit menü)
- Werte in EEprom speichern und auslesen
- 3 Taster Pollen
- und halt den UART ansteuern

bis jetzt habe ich den µC nur per Interrupt auf 1 Byte-Befehle
reagieren lassen:


SIGNAL (SIG_UART_RECV) {
  unsigned char data = UDR;
  switch (data) {
      case '1': uart_puts("Test\n"); break;
      case 'i': uart_puts("Text\n"); break;
      default: uart_puts("Befehl nicht erkannt");break;
  }
}

Bis jetzt hats so auch immer gereicht, aber jetzt muss der AVR auch
daten (einstellungen) empfangen können.
Das mit dem Ring-Puffer verstehe ich nicht ganz.
Ich hab mal überlegt das so zu lösen:

unsigned int char_index;
unsigned char puffer[3];

SIGNAL (SIG_UART_RECV) {
  unsigned char data = UDR;
        if (char_index > 0)
        {
            puffer[char_index] = data;
            if (char_index >= 3)
            {
               char_index = 0;
               bearbeite_befehl(&puffer);
            }
        }
        else
   switch (data) {
      case '1': uart_puts("Test\n"); break;
      case 'i': uart_puts("Text\n"); break;
      case 's': char_index=1;puffer[0] = data;break;
      default: uart_puts("err");break;
    }
}

(nur ein beispiel aus dem kopf)
aber wenn meine datenübertragung mittden drin abbricht, dann hab ich
ein Problem (mein µC denkt, es kommen noch einstellungsbytes und
übernimmt somit falsche daten)

Gruß

von Dieter (Gast)


Lesenswert?

Die komplette Datenverarbeitung solltest Du aus dem Interrupt
rausnehmen. Deshalb auch der Ringpuffer: Das ist nichts anderes als ein
(virtuell) ringförmiger Speicherbereich, der kein Ende und keinen Anfang
hat, es gibt halt zwei Zeiger, einer zeigt auf die nächste zu
beschreibende Speicherstelle, der andere auf das letzte, nicht
bearbeitete Datum. Immer, wenn ein Receive-IRQ kommt, wird das Datum in
den Puffer geschrieben und der Zeiger eins hochgesetzt.
Die Auswertung machst Du dann in einem Interrupt niederer Priorität
oder im Hauptprogramm.
Das Problem, dass Deine Routine hängenbleiben kann, löst Du, indem Du
einen TimeOut einbaust, z.B. bei Beginn der Auswertung ein Flag setzen
und dann im Timer-IRQ nach einer gewissen Zeit zurücksetzen.

von Achim (Gast)


Lesenswert?

@Dieter:
Wie meinst du das, die komplette datenverarbeitung raus nehmen ?
Soll ich in der Interrupt Routine nur noch der datenempfang realisieren
oder wie ?
soll ich dann sobald der puffer voll ist, erst zu einer
datenverarbeitungsroutine wechseln und dort das empfangene (puffer
inhalt) verarbeiten.

Das mit dem zurücksetzen habe ich verstanden.
wo stehen denn die interrupt prioritäten ?

MfG

von Dieter (Gast)


Lesenswert?

Das mit der Verarbeitung siehst Du richtig.
Den Puffer kannst Du im Prinzip jederzeit verarbeiten, natürlich aber
so, dass er nicht überläuft (abhängig von der UART-Geschwindigkeit).
Am besten in Form einer Zustandsmaschine, d.h. nach jedem verarbeitetem
Zeichen wird der Zustand gewechselt und gegebenfalls die Maschine
zurückgesetzt. Das würde ich dann aber mit einer Start- und
Stopp-sequenz machen, das spart den Timeout.
Bei mir habe ich etwas Ähnliches laufen (Freisprecheinrichtung für das
Telefon im Auto samt SMS, etc.), also auch UART, Display, Tasten.
Da der AVR ja unverständlicherweise keine Hardware-IRQ-Level wie andere
MCs hat, habe ich das in Software implementiert, d.h. UART hat hohe
Priorität und ist nicht unterbrechbar. Dazu zwei Timer-IRQs, von denen
der eine unterbrechbar ist und in diesem IRQ findet bei mir die
Verarbeitung des Empfangspuffers statt. Im anderen Timer-IRQ dann so
etwas wie Echtzeituhr, Tastatur-Entprellen, LEDs, etc.
In der Hauptschleife läuft dann das User-Interface, also die
Menüsteuerung.

von Achim (Gast)


Lesenswert?

Hallo Dieter.
Klingt ja mega interessant !
könntest du mir evtl. deinen code zuschicken, damit ich mir das alles
mal anschauen kann ? Wär echt nett !
(hab leider grad keine eigene email (wegen providerwechsel) nehm
einfach die: simonfr [at] web.de )

Vielen Dank schonmal im voraus!
Gruß Achim

von Florian (Gast)


Lesenswert?

Ich habe so was bei mir bereitgestellt:
http://www.blafusel.de/misc/atmega8_io.html#6
Vielleicht hilft ja ein Studium der (einfachen) Sourcen Dir weiter.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.