Forum: Mikrocontroller und Digitale Elektronik Software UART


von Peter (Gast)


Lesenswert?

Hallo Leute,

hab eine quick and dirty version von Software UART programmiert. Die 
senden Routine funktioniert Einwand frei. Aber die Empfangsroutine 
nicht. Ich empfange immer nur eine 0x00. Mit dem Oszi sehe ich das der 
Pegel stimmt. Auch wenn ich den Ein auf einen Ausgang einfach weitergebe 
stimmt dieser Pegel. Im AVR-Studio funktioniert es auch so wie 
gewünscht. Wenn der Pin auf Low gezogen wird, wird 1.5 Bits gewartet und 
ab dann Per Interrupt die Routine aufgerufen.
Jemand eine Idee wo der Fehler ist. Wald vor lauter Bäumen?!

1
    SRXPORT  |= (1<<SRX);  // Pullup Aktiv gesetzt
2
3
void suart_empfangen(void)
4
{
5
  if(srx_done>0)
6
  {
7
    if(srx_done<9)
8
    {
9
      if ( SRXPIN & (1<<SRX) )
10
      {
11
        srx_tmp |=( 1<< (srx_done-1) );
12
      }
13
    }
14
    srx_done++;
15
    if(srx_done>=10)
16
    {
17
      srx_data[srx_count]=srx_tmp;
18
      srx_count++;
19
      srx_tmp=0;
20
      srx_done=0;
21
    }
22
  }
23
}

von Rainer B. (katastrophenheinz)


Lesenswert?

Narbend,

Da fehlt doch die Hälfe des Quellcodes. So ist alles nur Rätselraten.
Wo ist "srx_tmp" deklariert, wo wird "srx_tmp" initialisiert?
Was ist der Startwert von "srx_done"? Wenn er denn 0 ist, wie zumindest 
der untere Teil vermuten lässt, dann ist in deinem Schnipsel keine 
Stelle zu sehen, an der "srx_done" mal auf einen Wert > 0 gesetzt wird.

von bastler (Gast)


Lesenswert?

Peter schrieb:
> void suart_empfangen(void)
> {
>   if(srx_done>0)
>   {
>     [...]
>   }
> }

Frage: Wer setzt srx_done auf einen Wert >0 ?
Wenn das sonst nirgendwo passiert, wird der äüßerste if-Block nie als 
TRUE bewertet und auch nie ausgeführt.

von nochmal bastler (Gast)


Lesenswert?

Peter schrieb:
> (srx_done-1)

Warum benutzt du keinen 0-bezogenen Index für die Bits?

von Peter (Gast)


Lesenswert?

Das läuft in meiner main. Die 1 ist im Pinzip mein Startbit und 
gleichzeitig die die Freigabe zur Abarbeitung meiner Empfangsroutine. 
Wollte mir zeit im Interrupt sparen.
1
void suart_getchar(void)
2
{
3
  if ( ( ( SRXPIN & (1<<SRX) ) ==0)& srx_done==0)
4
  {  
5
    TCNT0=SBAUD_TCNT_INIT;
6
    srx_done=1;
7
  }
8
}

von Rainer B. (katastrophenheinz)


Lesenswert?

Poste bitte den kompletten Quellcode!

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Hier der Quelltext

von Rainer B. (katastrophenheinz)


Lesenswert?

Mmn erfolgt bei dir das Abtasten der Bits nicht in der Bitmitte, sondern 
genau zum Bitwechsel, weil du den Timer mit der fallenden Flanke des 
Startbits mit einer Bitzeit +2(?) startest und nicht zunächst mal mit 
1,5 Bitzeiten, um genau zur Bitmitte abzutasten.
Weiterhin setzt du srx_tmp nie zurück. Da du nur die 1en reinschreibst, 
musst du srx_tmp mit jedem neuen Empfang auf 0 setzen, sonst stehen 
irgendwann nur noch 1en drin.

Beides erklärt aber nicht, warum du konstant 0x00 empfängst.

Ich würde folgendes tun: Wenn es dir darum geht, eine Soft-Uart 
produktiv zu nutzen, dann würde ich eine fertige, getestete 
Implementierung nehmen und deine in die Tonne kloppen.

Wenn es dir darum geht, eine Soft-Uart zu Lernzwecken selbst zu bauen, 
dann würde ich den Hardware-Uart und z.B. die Fleury-Lib nehmen, darin 
ausreichend grossen Tx-Ringbuffer konfigurieren und den Hardware-Uart 
dann für Debug-Ausgaben nutzen, um z.B. erstmal "srx_tmp" mit jedem 
empfangenen Bit anzugucken.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich teile einen Soft UART Receiver in zwei Teile auf. Das eine ist ein 
Pinchange Interrupt auf fallende Flanke, der den Bitzähler und den Timer 
auf 1,5 fache Bitlänge mit ISR initialisiert, den Status des Receivers 
auf busy setzt und dann sich selber sperrt.
Die Timer ISR setzt den Timer auf 1 Bitdauer, liest den Pin, schiebt das 
Ergebnis von links in den RX-Buffer und erhöht den Bitzähler. Wenn 
Bitzähler > 8, sperrt sich die Timer ISR, setzt den Status auf 
nicht-busy (also ready) und gibt den o.a. Pinchange Interrupt wieder 
frei.

von Georg (Gast)


Lesenswert?

Matthias S. schrieb:
> Ich teile einen Soft UART Receiver in zwei Teile auf. Das eine ist ein
> Pinchange Interrupt
...

Man kann es sich auch einfacher machen, indem man die übliche Hardware 
softwaremässig nachbaut: man nimmt einen durchlaufenden Time-Interrupt 
von 8 oder 16 mal der Baudrate und programmiert den Empfänger als State 
machine, die beim erstenmal Lo loszählt, beim Zählerstand 8 das Startbit 
verifiziert, bei 24 das erste Bit usw.

Kommt natürlich auf die Baudrate an, aber heutige Prozessoren sollten 
damit kein Problem haben, und das Senden wird im gleichen Time Interrupt 
miterledigt.

Georg

von Peter D. (peda)


Lesenswert?

Matthias S. schrieb:
> Das eine ist ein
> Pinchange Interrupt auf fallende Flanke, der den Bitzähler und den Timer
> auf 1,5 fache Bitlänge mit ISR initialisiert, den Status des Receivers
> auf busy setzt und dann sich selber sperrt.

Und wo ist der Code?
In Deinem Code ist nur ein Overflow-Interrupt.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Peter D. schrieb:
> Und wo ist der Code?
> In Deinem Code ist nur ein Overflow-Interrupt.

Ich habe dazu keinen Code hier veröffentlicht.
Man kann sich das in meinem V-USB Projekt 'Tektronix Tablet 4957 auf 
USB' auf
http://www.schoeldgen.de/avr/ anschauen.

: Bearbeitet durch User
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.