UART String einlesen

Gast #932057
Lesenswert?

Hi

Kann mir jemand sagen was für Flags gesetzt werden, wenn auf der 
seriellen Schnittstelle Daten daherkommen?

Ich möchte in einer while(1) schleife Strings einlesen. (Aber nur dann 
einlesen wenn welche daherkommen).

Kann mir jemand ein Teilfragment vom einlesen eines Strings posten?

mfg
Gast #932433
Lesenswert?

Atmega 64.

Hier meine Problembeschreibung:

Ich möchte mit dem Atmega64 SMS lesen und versenden können.
Dafür würde ich ja wie immer uart_gets() benutzen um etwas vom modem
einzulesen.
Jedoch weiß ich ja nicht wann eine sms eintrifft und um dies zu erkennen
müsste der µC ja permanent an der seriellen Schnittstelle auf text
warten.
Dies wäre mit dem aufruf von uart_gets() erledigt, da die funktion erst
beendet wird wenn die max string länge erreicht wurde oder ein string
endzeichen erkannt wird.
eine ausgabe vom modem wäre z.B. +CMTI:"SM",3 diese zeile sagt mir das
eine neue sms im speicherbereich 3 gespeichert wurde.
die darauf folgende antwort vom µC wäre dann (öffne SMS 3)-->AT+CMGR=3.
folglich wird der inhalt der sms ausgegeben mit dem sich dann arbeiten
ließe.

mein problem ist nun:
nach dem aufruf der funktion uart_gets() wartet der µC auf zeichen.
falls aber keine sms eintrifft, empfängt der µC keine zeichen vom modem,
wartet bis ins nächste jahrhundert und beendet die uart_gets()
funktion nicht um mit dem programm fortzufahren.

kurz gesagt in zwei fällen soll reagiert werden:
wenn sich pinX verändert und wenn eine sms mit befehl eintrifft.

wie löse ich dieses problem?
#932445
Lesenswert?

Hallo,

schau mal ins Datenblatt vom ATMega64. In einem UART-Register UCSRA 
gibt's ein Flag, das heißt RXC. Es wird auf 1 gesetzt, wenn ein Zeichen 
empfangen wurde.
Es reicht also wenn du vor dem Aufruf von uart_gets() überprüfst ob 
dieses Bit gesetzt ist. Wenn nein kannst den PinX abfragen, oder 
sonstige Aktionen durchführen.

Gruß, Florian
Moderator (Firma: Titel) Persönliche Seite #932461
Lesenswert?

Wenn du mit
>uart_gets()
nichts anfangen kannst, dann ist das die falsche Funktion für dich.

In eine Hauptprogrammschleife vom Typ
while(1){}
gehört nichts, was die Ausführung der Schleife grundsätzlich verhindern 
kann.

Mein Tipp:
1) sieh nach, ob ein Zeichen gekommen ist z.B. über uart_getc()
2) falls nein: mach weiter mit der Schleife 4)
3) falls ja: füge es zu deinem String dazu,
   ist es ein CR oder LF dann ersetze es durch \0 und
   werte dann den so erhaltenen String aus
4) Tu den Rest der Schleife (Pinabfrage....)
5) Weiter bei 1)
Gast #932753
Lesenswert?

Kann mir jemand sagen wo da der Fehler liegen könnte.
Der Atmega bleibt in der While(1) schleife hängen.

1
unsigned char neu[10];
2

3
while (1)
4
{
5
  if((UCSR0A & (1<<RXC)))
6
  {
7
   printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
8
   gets(neu);           //Speichert den String auf neu ab.
9
  }
10
}

Wie gesagt will ich einen String einlesen, sobald ich was auf der 
seriellen Schnittstelle empfang, sonst soll das Programm andere 
Tätigkeiten ablaufen lassen.
Persönliche Seite #932764
Lesenswert?

Ist printf schon auf STDOUT gerichtet und gets auf STDIN?

Siehe http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

"The standard streams stdin, stdout, and stderr are provided, but 
contrary to the C standard, since avr-libc has no knowledge about 
applicable devices, these streams are not already pre-initialized at 
application startup..."

Und wie man die Zuordnung mit Hilfe von FDEV_SETUP_STREAM  macht 
(http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gea2b6be92ead4673bc487b271b7227fb 
und Democode in 
http://www.nongnu.org/avr-libc/user-manual/group__stdiodemo.html)

EDIT: Siehe auch 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Nutzung_von_printf
Gast #932775
Lesenswert?

schurli wrote:
> Kann mir jemand sagen wo da der Fehler liegen könnte.
> Der Atmega bleibt in der While(1) schleife hängen.
warum eigentlich nicht über den RXC interrupt?

>
1
> unsigned char neu[10];
2
> 
3
> while (1)
4
> {
5
>   if((UCSR0A & (1<<RXC)))
                       ^^^ RXC0 muss es heißen
1
>   {
2
>    printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
3
>    gets(neu);           //Speichert den String auf neu ab.
4
>   }
5
> }
6
>
>
> Wie gesagt will ich einen String einlesen, sobald ich was auf der
> seriellen Schnittstelle empfang, sonst soll das Programm andere
> Tätigkeiten ablaufen lassen.
klingt wie gemacht für interrupts
Gast #932781
Lesenswert?

1
//Installation der Seriellen Schnittstelle
2
void Handy_Init (void){
3

4
  //Enable TXEN im Register UCR TX-Data Enable
5
  UCR=(1 << TXEN | 1<<RXEN);
6
  //Teiler wird gesetzt 
7
  UBRR=(SYSCLK / (BAUD_RATE * 16L) - 1);
8
  
9
  //öffnet einen Kanal für printf (STDOUT)
10
  fdevopen (uart_putchar, uart_getchar);
11
};
12

13

14
//Routine für die Serielle Ausgabe
15
int uart_putchar (char c){
16

17
  if (c == '\n')
18
    uart_putchar('\r');
19
  //Warten solange bis Zeichen gesendet wurde
20
  while(!(USR & (1<<UDRE)));
21
  //Ausgabe des Zeichens
22
  UDR = c;
23
  return (0);
24
};
25

26
//Routine für die Serielle Ausgabe
27
int uart_getchar (void){
28

29
  while(!(USR & (1<<RXC)));
30
  return(UDR);
31
};


Hier der Codeausschnitt.

Wie kann man es über den RXC interrupt machen?
Persönliche Seite #932782
Lesenswert?

schurli wrote:
> ist drauf gerichtet und funtkioniert auch, aber irgenwas hats mit der
> abfrage von der seriellen schnittstelle glaube ich.

Dan erläutere bitte, was genau du mit "bleibt in der While(1) schleife 
hängen" meinst.

Im Moment besteht dein Codeschnippsel nämlich aus einer Endlosschleife; 
das Programm MUSS in der while(1) Schleife bleiben.

Wenn du andere Tätigkeiten abzuarbeiten hast, könntest du die hier 
unterbringen:

unsigned char neu[10];

while (1)
{

  // Auf UART-Eingabe prüfen
  if((UCSR0A & (1<<RXC)))
  {
    printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
    gets(neu);           //Speichert den String auf neu ab.
  }

  // ggf. Eingabe auswerten und
  // sonstigen Code ausführen

}
Gast #932814
Lesenswert?

Sorry hab vergessen das die mit dem Präprozessor definiert wurden.
1
#if defined (__AVR_ATmega64__)
2
#  define USR UCSR0A
3
#  define UCR UCSR0B
4
#  define UDR UDR0
5
#  define UBRR UBRR0L
6
#  define EICR EICRB
7
#endif
Gast #932831
Lesenswert?

Hat zwar schon anstandslos mit RXC statt RXC0 funktioniert obwohl es 
definitiv falsch ist.

Trotzdem hängt das Programm beim Einlesen des Strings.
"Hallo" wird mir auf der Seriellen ausgegeben, aber dann steht alles.
Gast #932878
Lesenswert?

1
unsigned char neu;
2

3
while (1)
4
{
5
  if((UCSR0A & (1<<RXC0)))
6
  {
7
   printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
8
   neu=uart_getchar();          
9
  }
10
}

Komischerweise funktioniert das einlesen eines Zeichens wunderbar.
Wenn ich im Hyperterminal irgenwas eingebe, schickt mir der AVR "Hallo" 
zurück und das Programm läuft in der while(1) weiter.

10mal irgendwas drücken ergibt 10mal "Hallo" also funktiniert es.

Warum funktioniert gets() nicht?

mfg
Persönliche Seite #932914
Lesenswert?

Welches Zeichen ist den das Zeilenendezeichen in gets? Tipp, dies ist 
der Code von gets() aus avr-libc 1,6.2:
1
#include <stdio.h>
2

3
#include "stdio_private.h"
4

5
char *
6
gets(char *str)
7
{
8
  char *cp;
9
  int c;
10

11
  if ((stdin->flags & __SRD) == 0)
12
    return NULL;
13

14
  for (c = 0, cp = str; c != '\n'; cp++) {
15
    if ((c = getchar()) == EOF)
16
      return NULL;
17
    *cp = (char)c;
18
  }
19
  *--cp = '\0';
20

21
  return str;
22
}

Und welches Zeichen schickt dein UART-Sender (Terminalprogramm?, Handy?) 
am Ende einer Zeile?
Persönliche Seite #932927
Lesenswert?

Stefan "stefb" B. wrote:

> Wenn du andere Tätigkeiten abzuarbeiten hast, könntest du die hier
> unterbringen:
>
> unsigned char neu[10];
>
> while (1)
> {
>
>   // Auf UART-Eingabe prüfen
>   if((UCSR0A & (1<<RXC)))
>   {
>     printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
>     gets(neu);           //Speichert den String auf neu ab.
>   }
>
>   // ggf. Eingabe auswerten und
>   // sonstigen Code ausführen
>
> }

Das setzt allerdings voraus, dass der restliche Code nicht zu viel Zeit 
braucht (abh. von F_CPU und BAUDRATE). Der Hardware-UART-Puffer ist 
derzeit nur 2 Zeichen gross und es besteht grosse Gefahr, dass Zeichen 
verloren gehen.

Ein grösserer Empfangspuffer und eine vom Userprogramm unabhängig 
laufende RX-Interruptroutine wären sicher die geschicktere Lösung.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren