Forum: Mikrocontroller und Digitale Elektronik ATmega328P: 9-Bit UART


von Simon F. (saimenf)


Lesenswert?

Guten Abend,

Ich habe gerade ein kleines C-Projekt am laufen, mit dem ich 9-Bit Werte
auslesen und verarbeiten möchte.
Mit dem 9ten Bit möchte ich zwischen Adress-/ und Datenbits
unterscheiden.

Das auslesen Funktioniert ohne Probleme, bloß die Verarbeitung des 2
Byte Wertes bereitet mir bis jetzt Kopfzerbrechen.


Hier mein Code:
1
#define F_CPU 16000000UL                    
2
3
#include <avr/io.h>                        
4
#include <util/delay.h>                      
5
6
#define USART_BAUDRATE 9600UL                  
7
#define BAUD_Prescale ((F_CPU / (USART_BAUDRATE*16UL)) -1)    
8
9
10
void Extended_USART_init ()              
11
{
12
  UBRR0H = (unsigned char)(BAUD_Prescale>>8);          
13
  UBRR0L = (unsigned char)(BAUD_Prescale);          
14
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);                
15
  UCSR0C = (1<<USBS0)|(1<<UCSZ02)|(1<<UCSZ01)|(1<<UCSZ00);  
16
}
17
18
void Extended_USART_Transmit (unsigned int xdata)   
19
{
20
  while (!(UCSR0A & (1<<UDRE0)));            
21
  UCSR0B &= ~(1<<TXB80);              
22
  if (xdata & 0x0100)                
23
  {
24
    UCSR0B |= (1<<TXB80);
25
  }
26
  UDR0 = xdata;                  
27
}
28
29
unsigned int Extended_USART_Receive (void)      
30
{
31
  unsigned char status, resh, resl;        
32
  
33
  while (!(UCSR0A & (1<<RXC0)));          
34
  
35
  status = UCSR0A;                              
36
  resh = UCSR0B;                  
37
  resl = UDR0;                  
38
  
39
  if (status & ((1<<FE0) | (1<<DOR0) | (1<<UPE0)))
40
  {
41
    return 1;                  
42
  }
43
  
44
  resh = (resh >> 1) & 0x01;            
45
  return ((resh << 8) | resl);          
46
}
47
48
void Extended_EIN_AUS ()
49
{
50
  unsigned int xWert;        
51
  xWert = Extended_USART_Receive();
52
  
53
  if (xWert == 300)
54
  {
55
    PORTB = 0xff;
56
  }
57
}
58
59
60
int main(void)                    
61
{  
62
  Extended_USART_init();                
63
  DDRB = 0xff;                  
64
  
65
    while (1)                    
66
    {
67
    Extended_EIN_AUS();
68
    }
69
}
Den eingelesenen 2-Byte Wert möchte ich zu Testzwecken mit einer Zahl
(300) vergleichen. Sobald beide Werte gleich sind, sollen alle
PORTB-Pins auf High geschaltet werden.

Dadurch, dass in "Extended_USART_Receive" die Bits im return schon
verknüpft werden, müsste doch ein 2-Byte Wert an "xWert" zurückgegeben
werden.
Oder liege ich falsch?

Hat vielleicht jemand von euch einen Lösungsansatz?

Gruß

von STK500-Besitzer (Gast)


Lesenswert?

Simon F. schrieb:
> resh = (resh >> 1) & 0x01;
>   return ((resh << 8) | resl);

Caste das mal nach int

von Simon F. (saimenf)


Lesenswert?

Wäre dies eine Möglichkeit zu Casten?
1
resh = (resh >> 1) & 0x01;             
2
return Test = (int)(((resh << 8) | resl));
Habe jetzt verschiedene Arten von Typenumwandlungen versucht, keine hat 
so richtig Funktioniert.

von Dirk B. (Gast)


Lesenswert?

vom Prinzip würde bit0 in einem
>  unsigned char status, resh, resl;
nach  <<8 im status landen und wird deswegen nicht so gerne 
implementiert.
Eigentlich ist da eher die Frage wie der Code in das Datenblatt kommen 
konnte spannend (durch einen Compilerfehler UND return -1 statt return 1 
könnte es zufällig klappen)

evtl. eine Kurzversion:
1
  
2
unsigned int Extended_USART_Receive (void)      
3
{ while (!(UCSR0A & (1<<RXC0)));          
4
  if UCSR0A & ((1<<FE0) | (1<<DOR0) | (1<<UPE0)))
5
     return -1; 
6
  if UCSR0B & (1<<RXB8)
7
     return (0x100 + UDR0)
8
  return (UDR0)
9
}

von Simon F. (saimenf)


Lesenswert?

Dirk B. schrieb:
> unsigned int Extended_USART_Receive (void)
> { while (!(UCSR0A & (1<<RXC0)));
>   if UCSR0A & ((1<<FE0) | (1<<DOR0) | (1<<UPE0)))
>      return -1;
>   if UCSR0B & (1<<RXB8)
>      return (0x100 + UDR0)
>   return (UDR0)
> }

Klingt einleuchtend! Ist sicherlich einfacher als das Beispiel im 
Datenblatt beschrieben.
Habe ich jetzt gerade noch in meinem Projekt korrigiert....

Habe nochmals die Initialisierung des 9-Bit UART auf Richtigkeit 
überprüft, und noch wirklich einen Fehler gefunden.
Ich habe:
1
(1<<UCSZ02)
nicht im richtigen Register initialisiert. Sollte in "UCSR0B" und nicht 
in "UCSR0C" initialisiert werden.

Zum Test schicke ich die eingelesenen Daten gleich wieder über meinen 
FTDI auf meinen PC und lese die Daten mit HTERM ein.
Komischerweise empfange ich jetzt plötzlich 3 Byte. Jetzt bin ich 
vollkommen verwirrt :'‑)

von H.Joachim S. (crazyhorse)


Lesenswert?

Kann denn der FTDI überhaupt 9bit? Ich glaube nicht, zumindest nicht der 
meist verwendete FT232RL.

von Dirk (Gast)


Lesenswert?

H.Joachim S. schrieb:
> Kann denn der FTDI überhaupt 9bit?
Windows behauptet zu 9bit:"The number of data bits must be 5 to 8 bits"
- hTerm: 5..8bit
dazu das C-Beispiel das eigentlich nicht funktionieren 'darf' und der µC 
bei dem 9-bit nicht eingestellt wurde ...
... nur:
>Das auslesen Funktioniert ohne Probleme,[..]
dürfte dann das Hauptproblem sein.

Für µC<->µC könnte 9bit praktisch sein, aber sonst wohl schwierig.

von Simon F. (saimenf)


Lesenswert?

Danke für eure Antworten!

Langsam aber doch bin ich mir nicht mehr so sicher, ob die 9-Bit 
Variante das richtige für das Projekt ist, da dies auch mit der 8-bit 
Variante funktionieren sollte.
Habe mich nur mal aus Interesse an das 9-Bit UART gestürzt ;)

Dirk schrieb:
> dazu das C-Beispiel das eigentlich nicht funktionieren 'darf' und der µC
> bei dem 9-bit nicht eingestellt wurde ...

Es würde mich trotzdem noch Interessieren, was an der Initialisierung in 
meinem Programm falsch gelaufen ist. Habe mich da schon ein Paar mal 
durch das Datenblatt gelesen und nichts markantes mehr gefunden.


Gruß

von Jim M. (turboj)


Lesenswert?

Simon F. schrieb:
> return Test = (int)(((resh << 8) | resl));
> Habe jetzt verschiedene Arten von Typenumwandlungen versucht, keine hat
> so richtig Funktioniert.

Typ int reicht nicht. Man darf nicht ins Vorzeichen shiften.

return (((uinsigned int) resh) << 8)|res1;

von c-hater (Gast)


Lesenswert?

Dirk schrieb:

> Windows behauptet zu 9bit:"The number of data bits must be 5 to 8 bits"

> Für µC<->µC könnte 9bit praktisch sein, aber sonst wohl schwierig.

Nicht wirklich, jedenfalls nicht für Windows. Das unterstützt zwar nur 8 
Datenbits, aber zusätzlich ein Paritätsbit und zwar in den Ausprägungen 
even, odd, mark und space. Also ist es trivial, das Wordformat auf 8M1 
oder 8S1 festzulegen und die Information des 9. Datenbits eben als 
Parity-Error zu empfangen. Kinderkram, das habe ich schon vor >30 Jahren 
erstmals machen müssen...

Allerdings: für hohe Datenraten ist das Konzept eher nicht geeignet. Da 
fehlt dann doch zunehmend die Hardwarunterstützung...

von Dirk (Gast)


Lesenswert?

Simon F. schrieb:
> Habe mich nur mal aus Interesse an das 9-Bit UART gestürzt ;)
vom Prinzip ist 9-bit für 8-bit Daten + 1-bit meta/out-of-band/(andere 
Bezeichnung je nach Betrachtung oder Verwendung) Datum ja auch eine u.U. 
praktische Idee. Im letzten Jahrtausend wurden allerdings Kinder mit der 
Idee malträtiert, da für die damaligen BWL-ler Kinderarbeit praktisch 
kostenlos kalkuliert wurde und µC in der Leistungsklasse eines C0,64 als 
Transciver/Proxy etc. ein (umgerechnet) Pullover gekostet hätten.
Den jungen Menschen denen damals erzählt wurde Bit/Byte-Banging sei 
trivial, da Bits nur in den Ausprägungen Mark/Space 0/1 low/high ../.. 
vorkommen und die erst bei hohen Modemgeschwindigkeiten die 
Schwierigkeiten von 9/10/.. oder auch 4-bit Übertragungen bemerkt haben 
(bzw. teilweise wohl nicht) ging es da nicht so gut.
Rein praktisch ist 9-bit auch eher für synchrone Übertragung geeignet, 
da leichte Gangunterschiede sich bei der Asynchronen summieren. Also 
9-bit als 2*6-bit (inkl. Meta information)mit doppelter Baudrate dürfte 
schneller und zuverlässiger als 1*9 bit sein.
So ein Kinderkram kann ja auch durchaus Spass machen und ich fände es 
auch spannend was da genau schief gelaufen ist. Ich hab zumindest 
herausgefunden, dass ich wohl nächstes WE 8-bit mit 6-bit getestet hätte 
(einige Atmel µC benötigen das UMSEL-bit für USCRC) und manchmal 
passieren die unbeschreiblichsten Fehler gerade wenn ein Teil ohne 
Probleme läuft und bspw. zur Fehlersuche noch kurz die Kontroll-Led 
initialisiert wird und der µC daraufhin komplett abstürzt. Kurzer Blick 
ins Handbuch: VCC gehört doch direkt mit einer Spannungsquelle verbunden 
und die Notstromversorgung über einen versehentlich als Eingang 
geschalteten Pin ist gar nicht dokumentiert (und funktioniert wohl auch 
nur mit falsch angeschlossener LED). Kurz: es gibt bei dem 
Versuchsaufbau zu viele Möglichkeiten von einfachst bis kompliziert 
Fehlerchen, als dass es im Forum wirklich konsequent gecheckt werden 
könnte und wenn du so einen µC ohne Spannungsversorgung, leicht 
unterschiedliches Modell, falscher Takt,.... hast, dann passieren 
schnell die zwei Meinungen:
a) der µC hat eine Stromversorgung, da er eigentlich funktioniert und
b) der µC hat keine Stromversorgung, da der Pin nicht angeschlossen ist 
und
c) die Frage: "benötigt der µC eine Stromversorgung an VCC ?" im Forum 
passt auch nicht.
Solche Fehler sind dann schwer zu finden.
(ganz genau bekomme ich den Fehler nicht rekonstruiert, aber +5V an VCC 
hat in dem Fall geholfen)

Hier wäre spannend ob der falsche Atmel-Code mit einem nicht ganz 
korrekt arbeitenden Compiler evtl. das gewünschte Ergebnis bringen 
könnte, ansonsten ob und wie die anderen Bits ankommen.

c-hater schrieb:
> even, odd, mark und space. Also ist es trivial, das Wordformat auf 8M1
> oder 8S1 festzulegen und die Information des 9. Datenbits eben als
> Parity-Error zu empfangen. Kinderkram, das habe ich schon vor >30 Jahren
> erstmals machen müssen...
häufig sollen bei bei einer Datenübertragung mehrere Daten übertragen 
werden und dann erschließt sich sich die Schwierigkeit von solchem 
Byte-Banging, auch wenn diu als junger Mensch dazu gezwungen wurdest ...

NB.: triviales Bit empfangen von IR-FB mit einem PC kann auch 
interessante Fehler verursachen: mir ist damals der PC bei Sonnenschein 
abgestürzt, da da der IR-Detektor wohl bei Überdosis angefangen hast zu 
schwingen und so eine hohe Datenrate geliefert hat. Dadurch dass 
damalige Mäuse tw. ähnliche Effekte hatten ging die Fehlersuche noch 
einigermaßen schnell und Strahlenschutzmaßnahmen haben geholfen, aber 
ein PC der beim ersten Sonnenstrahl der ihn trifft abgestürzt hat schon 
einen gewissen Charme ;-)

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.