PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zahlen > 8bit über UART senden und enpfangen?



Karl Napf
03.04.2007, 11:31
Hallo zusammen!

Hab schon einige Beträge hier zu UART gelesen, mein Problem hab ich aber noch nicht gefunden:
Ich habe zwei Atmegas über UART verbunden was auch funktioniert, wenn ich Zahlen <255 verschicke.
Wie kann ich jetzt am geschicktesten eine 16 oder 32 bit Zahl senden und vom anderen Contoller empfangen?
Die UDR Register können nur 8bit aufnehmen, oder? und erwarten als Variablentyp ein unsigned char.

Grüße

bluebrother
03.04.2007, 11:35
du musst halt die Zahl in einzelne Bytes zerlegen. Wie du das dann genau aufbaust bleibt dir überlassen -- es muss schließlich nur auf beiden Seiten die gleiche Form haben.

Karl Napf
03.04.2007, 11:39
kannst du mir nen kleinen Einstieg / Beispiel geben wie man das in C macht?

Und wie kann ich beim Empfangen unterscheiden welches Byte wohin gehört?

p_mork
03.04.2007, 12:56
Und wie kann ich beim Empfangen unterscheiden welches Byte wohin gehört?

In dem Du ein Übertragungsprotokoll festlegst. Am einfachste geht das so:
zuerst schickst Du ein bestimmtes byte, an dem der Empfänger erkennt, dass gleich eine Zahl übertragen wird. Das byte kann z.b. eine 0x02 sein. Danach überträgst Du die Variable als ein Hex-Wert mit ASCI-Zeichen. Da die einzelnen Zeichen alle einen Wert über 0x02 haben, ist eine Verwechselung mit dem Startbyte 0x02 ausgeschlossen. Danach sendest Du ein Abschlussbyte, z.b. 0x04, was das Ende der Übertragung signalisiert. Letzteres kann aber auch wegfallen. Der Empfänger muss jetzt warten, bis das Startbyte bei ihm ankommt. Dann weiss er, dass die nächsten 4 bzw 8 Bytes eine Zahl sind, empfängt diese und wandelt sie in einen 16/32bit wert um.

MfG Mark

Karl Napf
03.04.2007, 15:36
Ich will z.B eine Zahl wie 43692 übertragen.
Das mit dem Zerlegen in Bytes hab ich hingekriegt
könnte so ausehen:

int16_t Value
((Value >> 8) & 0xFF);
((Value >> 0) & 0xFF);

Aber wie kann ich die 2 Bytes beim Empfangen wieder zu ordnen. Muss ich ein Bit von dem jeweiligen Byte für die Zuordnung reservieren und das dann abfragen?
Geht's nicht irgendwie einfacher oder gibt's was fertiges?

bluebrother
03.04.2007, 17:40
du hast eine serielle Verbindung die auf 8 bit Werten basiert. Du wirst also immer irgendein Protokoll machen müssen -- z.b. könnstest du über eine GPIO-Verbindung ein Handshaking machen und dann einfach n Werte in festgelegter Reihenfolge und Form übertragen. Oder du nimmst 7 bit und das 8. bit also Statusbit (z.b. um die Zahl als solche zu markieren, oder in einen Kommandomodus umzuschalten).

Was du jetzt genau mit dem "zuordnen" am Empfänger meinst ist mir aber nicht wirklich klar ... du musst halt dein Protokoll dekodieren.

Karl Napf
04.04.2007, 13:28
mit zuordnen mein ich wenn mein uart zwei 8bit Werte nacheinader empfängt und ich sie danach zu einer 16bit Zahl zusammen fügen will muss ich doch wissen welches das high Byte und welches das low Byte ist.
Kannst du mir die zweite Möglichkeit ein bißchen genauer erklären, hab von "Bussystemen" leider wenig Ahnung und wie man das in C implementiert ist mir auch nicht.

bluebrother
04.04.2007, 21:10
na ja, du kannst z.b. zwei GPIOs miteinander verbinden. Auf dem Sender ist das dann ein Ausgang, beim Empfänger ein Eingang. Wenn du jetzt beispielsweise eben den Pin auf 1 ziehst bedeutet das "jetzt kommt ein 16bit Wert" und hast vorher verbindlich festgelegt dass das MSB zuerst kommt. Dann sendest du die zwei Bytes und macht den Pin wieder aus.

Wenn du ohne sowas auskommen willst kannst du eben einfach erst 7 bit schicken und verbindlihc vereinbaren dass wenn das 8. bit aus ist dass das MSB ist. Dann schickst du das LSB und machst das 8. bit an. Allerdings verlierst du damit 2 bit aus deiner 16bit Zahl, d.h. du kannst so nur 14 bit übertragen.

Aber ich versteh dein Problem sowieso nicht ganz: du musst einfach nur _vorher_ verbindlich für _beide_ Seiten festlegen wie die Reihenfolge ist. Du musst halt darauf achten dass beide Controller synchronisiert sind. Wie z.b. mit der GPIO-Methode, oder du musst das über eine Startup condition machen. Oder du schickst nach dem Einschalten einfach mal 20 Nullbytes und vereinbarst dass nach mehr 20 Nullbytes mit einem darauffolgenden 0xff die Synchronisation anfängt.

Es gibt da quasi beliebig viele Möglichkeiten.

Karl Napf
05.04.2007, 16:37
ich hab's jetzt mal so probiert:
hab außer RXD und TXD noch eine Verbindung zwischen den beiden Contoller hergestellt.
Jetzt setze ich den einen Pin high und der Sender soll das erste Byte schicken. Danach wieder low und beim 2. high soll er das 2. Byte schicken (der Sender zählt die Anzahl der highs/ Impulse mit).
Das funktioniert so aber nicht, mein Display zeigt die beiden Werte abwechseln an.

Code vom Sender:



void uart_putc(unsigned char zahl)
{
while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
{
}
UDR = zahl; /* sende Zeichen */
}
int main(void)
{
//Steuerleitung
DDRA &= ~(1<<DDA6); //Eingang

//init UART
UBRRH = 0; // Highbyte ist 0
UBRRL = 3; // Lowbyte ist 51
UCSRB |= (1<<TXEN); //auf senden gestellt
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

unsigned char Bsp1 = 43;
unsigned char Bsp2 = 78;
int i = 0;

for( ; ; )
{
if(i==0)
{
if (PINA & (1<<PINA6))
{
uart_putc(Bsp1);
i=1;
}
}
else if (i==1)
{
if (PINA & (1<<PINA6))
{
uart_putc(Bsp2);
i=0;
}
}
}
return 0;
}


hier der Code vom Empfänger:



unsigned char uart_getc(void)
{
while (!(UCSRA & (1<<RXC)))
{
} // warten bis Zeichen verfügbar
return UDR; // Zeichen aus UDR zurueckgeben
}
int main(void)
{
lcd_init(LCD_DISP_ON); //Display
lcd_clrscr();

//init UART
UBRRH = 0; // Highbyte ist 0
UBRRL = 3; // Lowbyte ist 51
UCSRB |= (1<<RXEN); //auf empfangen gestellt
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

//Steuerleitung
DDRD |= (1<<PD2); //Ausgang


char buffer1[6];
char buffer2[6];
int a;
int b;

while(1)
{

PORTD |= (1<<PD2);
a = uart_getc();
PORTD &= ~(1<<PD2);


PORTD |= (1<<PD2);
b = uart_getc();
PORTD &= ~(1<<PD2);

itoa( a, buffer1, 10 );
lcd_gotoxy(0, 0);
lcd_puts(buffer1);

itoa( b, buffer2, 10 );
lcd_gotoxy(0, 1);
lcd_puts(buffer2);


}
return 0;
}

bluebrother
05.04.2007, 17:03
Das funktioniert so aber nicht, mein Display zeigt die beiden Werte abwechseln an.

Ähm ... das sieht doch so richtig aus. Wenn der Wert 16 bit sein soll musst du auf Empfängerseite beide Werte natürlich noch zusammensetzen. Also val = byte1 | (byte2<<8)

Oder überseh ich gerade was?

Karl Napf
05.04.2007, 18:53
Also das Prinzip könnte funktionieren? ein Pin als Auslöser für das put_uart().
Dann muss ich mir meinen Code nochmal genauer anschauen.
Hab das Gefühl, dass das ganze immer noch nicht synchron abläuft, so dass in z.B a = get_uart() beide Werte abwechselnd reinkommen.

Wie synchronisier ich denn am besten die Controller?
Mit dem UMSEL bit im UCSRC Register an dann die XCK Pins verbinden, so wie's im Datenblatt steht?

bluebrother
06.04.2007, 14:19
Hab das Gefühl, dass das ganze immer noch nicht synchron abläuft, so dass in z.B a = get_uart() beide Werte abwechselnd reinkommen.

Das ist doch genau *richtig* so: du sendest erst das 1. Byte und dann das 2., also beide Werte abwechselnd (weil du das ja in einer Endlosschleife machst). Die beiden Bytes müssen dann eben LSB und MSB von einer 16bit-Zahl sein. Und das musst du dann entsprechend wieder auf Empfängerseite zusammenbasteln.

Ich weiß echt nicht wo das Problem liegt, oder ich verstehe nicht was dein Problem ist. Ist doch einfach nur ne simple serielle Übertragung.

Karl Napf
10.04.2007, 15:19
Das funktioniert soweit ja, aber wenn ich beim Sender ein Reset mach, dann kommt es vor das er manchmal den Inhalt von "Bsp1" beim Empfänger in "a" und beim nächsten Reset in "b" ablegt. Genauso mit "Bsp2".
Das heißt jedesmal wenn ich die Controller einschalte kann es sein, dass die Werte beim Empfänger (auf dem Display) vertauscht sind.

bluebrother
11.04.2007, 18:48
nun ja, da musst du halt die Controller synchronisieren. Z.b. indem du mit einem zusätzlichen Pin eben signalisierst wann der Wert losgeht -- also Signal erzeugen, dann 1. Byte schicken, danach 2. Byte schicken. Der UART is asynchron, also brauchst du nicht jedes einzelne Byte zu signalisieren ...