Forum: Mikrocontroller und Digitale Elektronik Software Handshake mit Atmega64


von Daniel (Gast)


Lesenswert?

Hallo!

Ich habe eine serielle Verbindung mit meinem ATmega64 zu meinem PC 
aufgebaut (mit Silabs USB-Bridge).
Ich nutze die "Interrupt UART library" von Peter Fleury.
Ich möchte nun ein Software-Handshake unterbringen. Wo genau muss ich 
diese Steuerzeichen unterbringen?
Hier mal die Sende- und Empfangsroutine:
1
void uart_putc(unsigned char data)
2
{
3
    int tmphead;
4
    
5
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
6
    
7
    while ( tmphead == UART_TxTail ){
8
        ;/* wait for free space in buffer */
9
    }
10
    
11
    UART_TxBuf[tmphead] = data;
12
    UART_TxHead = tmphead;
13
14
    /* enable UDRE interrupt */
15
    UCSR0B    |= (1<<UDRIE0);
16
17
}/* uart_putc */
18
19
ISR (USART0_RX_vect) {
20
21
  // read UART status register and UART data register
22
  uart_menu_rxdata  = UCSR0A;  // Empty the Status Register
23
  uart_menu_rxdata  = UDR0;    // Read desired data
24
25
  UART_RX_OFF;                 // Kein weiterer Empfang (nur ein Zeichen)
26
 
27
  uart_menu_rxflag=1;          // Flag, dass etwas empfangen wurde
28
29
}

Nun ist die Frage wo ich den Software-Handshake einbaue. Der 
Software-Handshake macht doch auch nur Sinn, wenn der Sender dauerhaft 
sendet oder?
Dies tue ich aber nicht, ich "trigger" aus LabView heraus den Controller 
mit einem Zeichen und daraufhin wird mir der gewünschte String 
zurückgesendet.
Das Problem ist, dass ich zwei Funkmodule habe (die mein Kabel ersetzen 
sollen), die mit Software-Handshake arbeiten. PC-seitig kann man das ja 
einstellen. Nur wie mache ich das bei meinem Controller?

Ich hoffe ihr könnt mir helfen.

Viele Grüße
Daniel

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:

> Ich möchte nun ein Software-Handshake unterbringen. Wo genau muss ich
> diese Steuerzeichen unterbringen?

In möglichst tief liegenden Treiberschichten.

> Hier mal die Sende- und Empfangsroutine:
>
>
1
> void uart_putc(unsigned char data)
2
> {
3
>     int tmphead;
4
> 
5
>     tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
6
> 
7
>     while ( tmphead == UART_TxTail ){
8
>         ;/* wait for free space in buffer */
9
>     }
10
> 
11
>     UART_TxBuf[tmphead] = data;
12
>     UART_TxHead = tmphead;
13
> 
14
>     /* enable UDRE interrupt */
15
>     UCSR0B    |= (1<<UDRIE0);
16
> 
17
> }/* uart_putc */

guter Platz. Noch besser wäre es allerdings die Sendefreigabe 
unmittelbar vor Ausgabe des Zeichens ins UDR Register zu prüfen. Da das 
aber im Interrupt passiert, ist das nicht so simpel. Denn im Interrupt 
sollte man nicht warten.
Auf der anderen Seite muss die Gegenstelle nach dem Senden eins XOFF 
sowieso damit rechnen, dass noch ein paar Zeichen eintrudeln werden. Es 
ist nicht spezifiziert wieviele das sein können aber wenn dein 
UART_TxBuf nicht allzugross dimensioniert ist, sollte das eigentlich 
kein allzugroßes Problem sein. Muss man ausprobieren.

Also: Gesendet werden darf nur dann, wenn die Gegenstelle nicht mit 
einem XOFF das Senden unterbunden hat.
Also wirst du in der Empfangsroutine eine Erkennung von XOFF (und XON) 
einbauen. Wird XOFF erkannt, dann wird eine static volatile globale 
Variable SenderAllowsTransmission auf FALSE gesetzt. In der uart_putc 
fragst du ab, ob SenderAllowsTransmission auf TRUE steht und wenn nicht, 
dreht die Sendroutine ihre Runden, solange, bis sie die Freigabe über 
diese Variable bekommt.

> ISR (USART0_RX_vect) {
>
>   // read UART status register and UART data register
>   uart_menu_rxdata  = UCSR0A;  // Empty the Status Register
>   uart_menu_rxdata  = UDR0;    // Read desired data
>
>   UART_RX_OFF;                 // Kein weiterer Empfang (nur ein
> Zeichen)
>
>   uart_menu_rxflag=1;          // Flag, dass etwas empfangen wurde
>
> }
> [/c]

In dieser Funktion wird das empfangene Zeichen angeschaut.
Ist es XOFF, dann wird SenderAllowsTransmission auf FALSE gesetzt, ist 
es XON dann wird selbige Variable auf TRUE gesetzt. Ist es keinen von 
beiden, dann wird mit dem empfangenen Zeichen verfahren wie bisher auch.

> Nun ist die Frage wo ich den Software-Handshake einbaue. Der
> Software-Handshake macht doch auch nur Sinn, wenn der Sender dauerhaft
> sendet oder?

Nö.
Ein Handshake kann immer Sinn machen, wenn die Gegenstelle zeitweise 
nicht aufnahmebereit ist. Das kann viele Ursachen haben, zb. weil eine 
längere Berechnung im Gange ist, und die Gegenstelle nicht aufnahmefähig 
ist. Oder weil die Gegenstelle befürchtet, dass wenn du weitersendest 
ihr Eingangspuffer überlaufen wird.
Hint: Das ist auch das Stichwort wann dein Programm an die Gegenstelle 
ein XOFF schicken könnte. Wobei dann natürlich die paradoxe Situation 
enstehen kann, dass die Gegenstelle ihrerseits bereits mittels XOFF 
mitgeteilt hat, dass sie zur Zeit nicht belästigt zu werden wünscht :-). 
Wenn also die Gegenstelle bereits einen XOFF geschickt hat, darfst du 
ihr dann deinerseits einen XOFF schicken (denk logisch nach)

von Daniel (Gast)


Lesenswert?

Danke für die schnelle Antwort.
Funktioniert perfekt:
Quellcode:
1
#define XON 0x11
2
#define XOFF 0x13
3
4
volatile int8_t SenderAllowsTransmission
5
6
void uart_putc(unsigned char data)
7
{
8
    int tmphead;
9
    
10
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
11
    
12
    while ( tmphead == UART_TxTail ){
13
        ;/* wait for free space in buffer */
14
    }
15
    while ( SenderAllowsTransmission == -1){
16
      ; //solange hier bleiben, bis Sendefreigabe erfolgt
17
    }
18
    UART_TxBuf[tmphead] = data;
19
    UART_TxHead = tmphead;
20
21
    /* enable UDRE interrupt */
22
    UCSR0B    |= (1<<UDRIE0);
23
24
}/* uart_putc */
25
26
ISR (USART0_RX_vect) {
27
28
  // read UART status register and UART data register
29
  uart_menu_rxdata  = UCSR0A;  // Empty the Status Register
30
  uart_menu_rxdata  = UDR0;    // Read desired data
31
32
  if ( uart_menu_rxdata == XOFF ) 
33
    SenderAllowsTransmission = -1; // false, kein Senden erlaubt
34
  else if ( uart_menu_rx_data == XON)
35
    SenderAllowsTransmission = 1; // True --> Senden erlaubt
36
37
  UART_RX_OFF;                 // Kein weiterer Empfang (nur ein Zeichen)
38
 
39
  uart_menu_rxflag=1;          // Flag, dass etwas empfangen wurde
40
41
}

Das war ja wirklich einfacher als gedacht.
Vielen Dank!

von Daniel (Gast)


Lesenswert?

Hallo,

ich hab da noch ein Problem. Ich weiß nicht genau ob es mit dem 
vorherigen Problem zusammenhängt, aber es trat erst jetzt auf.

Ich habe obigen Quellecode geflasht. Via AVR-Studio (AVR-Prog). Nach dem 
Flashen lasse ich die Spannung am Controller vom USB-Port, stecke das 
Empfängermodul an den Rechner und lasse mir was schicken -> 
funktioniert.
Sobald ich den USB-Stecker ziehen und somit auch die Spannung und auf 
meine externe Spannungsquelle umstelle, funktioniert die 
Datenübertragung nicht mehr.
Abhängig von der USB-Spannung ist das Problem offenbar nicht, da ich 
meine externe Spannungsquelle parallel dran hatte und dann die 
USB-Spannung entfernt hatte. Dann klappte es auch noch. Nachdem ich dann 
aber die externe Spannungsquelle entfernt habe und wieder angeschlossen 
habe, funktionierte die Verbindung nicht mehr.
Kann das ein Pegelproblem sein?
Und AVR-Prog führt doch automatisch einen Reboot des Controllers durch, 
der doch auch durchgeführt wird, wenn die Spannungsversorgung des 
Controllers nicht mehr da ist oder?
Die andere Frage ist, ob ich dem Funkmodul controllerseitig ein XOFF 
bzw. XON schicken muss? Wenn ja, wo sollte ich das machen? Bisher 
verarbeite ich ja nur die Empfangenden Zeichen am Controller. Das wird 
aber nicht mit dem obigen Problem zusammenhängen denke ich.

von Wolfgang B. (Firma: Wolftec GmbH) (wbeppler)


Lesenswert?

ganz schoen heftig !

was funktioniert nicht mehr wenn du die spannung kappst ?
laeuft der prozessor weiter ? (blinkled zur kontrolle oder so was, 
lebensbit)

mach mal die masse irgendo gegen. das funkmodul koennte schwingen, also 
noch senden, nur eben so dass es keiner mehr versteht

wie ist das aufgebaut ?

die kapazitaet des netzteils ist ja riesig, vieleicht ist die der 
anderen versorgung zu keil ?


wegen dem xon/xoff:

welche baudrate ? womit kommunizierst du ? und wie wichtig sind die 
daten ?
wiederholende daten, z.b. messwerte, kannst auf der empfaengerseite auch 
auf plausibilitaet pruefen, also wenn werte kommen 100, 102, 101, 17, 
104 koenntest die 17 ja erkennen da die abweichung zu gross ist.

da wuerd ich kein handshake bauen, wenn es aber daten sind wie z.b. ein 
nc-programm und eine achse gesteuert wird, da wuerd ich mich nicht mal 
auf das handshake verlassen, sondern ne pruefsumme einbauen (ist 
einfacher)

generell ist handshake von 3 faktoren abhaengig damit es funktioniert
1. puffergroesse
2. baudrate
3. reaktionsgeschwindigkeit der gegenstelle

da ich selber kaum erfahrung mit atmel habe und in zukunft auch solche 
probleme bekommen werde wuerd es mich freuen wenn du mir das ergebnis 
hier wieder kund tust

gruss

w. :-)

von Daniel (Gast)


Lesenswert?

Problem gelöst.

Nach der Initialisierung des UART schicke ich an das Funkmodul ein XON.
Scheinbar ist das Flashen mit AVR-Prog was anderes als der Reboot des 
Controllers wenn man die Spannung weg nimmt.

@wolfgang
Ich muss leider den Software-Handshake nutzen, da die Funkmodule, die 
ich habe, das voraussetzen.

von T.A. (Gast)


Lesenswert?

Daniel
Kannst du mir dein ganzes UART Zeug zukommen lassen. Ich verstehe es 
nicht ganz und würde es gern da einige deiner Variablen im Quellcode den 
du gepostet hast nicht definiert sind.

Danke

von Helmut L. (helmi1)


Lesenswert?

Meinst du das er noch nach 8 Jahren dafuer eine Loesung sucht?

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.