-

+ Antworten
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 15

Thema: RS485-Protokoll

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    17.02.2004
    Beiträge
    23

    RS485-Protokoll

    Guten Morgen !

    ich habe für meinen ROV namens ROUVus (www.hardegser-sv.de/rov) versucht, ein Protokoll für den RS485-Bus zu schaffen. Ich will zum Verständnis der Frage kurz beschreiben wie es funktioniert:
    | ! | Adresse | Data1 | Data2 | Data3 | Data4 | Data5 | ist der Aufbau eines Packets. Nun habe ich den Empfangsinterrupt soweit, dass er in ein Array of Char (char buffer[6]) dann Adresse + Datenbytes speichert wenn die adresse seine ist. das scheint auch einwandfrei zu funktionieren..
    nun muss ich das angekommene Kommando noch weiter verarbeiten..
    also setzt der interrupt bei vollständigem empfang eine variable auf eins..
    im hauptprogramm läuft eine schleife, die diese variable prüft..
    bei wert == 1 tritt sie in aktion.. und zwar einfach den ganzen buffer zurückzusenden...
    fürs senden habe ich mir zwei funktionen geschrieben, die einzelne chars und ganze "strings" senden kann..
    wenn ich der stringfunktionen den buffer übergebe, kommt der auch im terminalprogramm (HTerm) an...
    problem: da kommt noch viel mehr danach an.. statt der 6 bytes die er empfangen hat kommen ungefähr 20 bytes an und nur am anfang stehen die richtigen... danach kommt kauderwelsch..
    übergebe ich der stringsende funktion einen string direkt, kommt dieser vollständig und ausschließlich an..
    um das problem weiter einzugrenzen habe ich versucht den buffer in einer schleife als char zu senden:
    UDR = buffer[i]; in etwa.. das hat dazu geführt, dass er nichts gesendet hat (nur die standards die drumherum gelegt werden von der sende funktion (| ! | Adresse |). kann man mit buffer[i] auf einzelne zeichen zugreifen oder nicht ? und die nächste frage wo kommen diese ominösen zeichen her..
    wenn ich nur ein zeichen sende und das direkt im interrupt verarbeite, gibt es keine probleme, was für mich bedeutet, das die schnittstelle nicht noch nachfolgende signale sendet, da im testprogramm in allen fällen außer "a" die led ausgeschaltet wird. wenn ich ein "a" senden, die LED auch angeht und an bleibt.

    Ich hoffe , ihr versteht was ich meine und könnt mir ein wenig unter die arme greifen..

    MfG
    ngb

    P.S.: quellcode poste ich heute nachmittag... vielleicht gibt es ja eine nicht software-bedingte lösung

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    20.08.2006
    Beiträge
    339
    Hallo,

    ich arbeite gerade auch ein einem RS485 Bus...
    Ich hänge aber noch an der Hardware..
    Kannst du mir da eventuell mal einen Schaltplan schicken?

    Viele Grüße,
    Johannes

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    17.02.2004
    Beiträge
    23

    Codes und links

    Hallo..
    ich habe mir einen RS485-RS232-Konverter gebaut und an den µC kann man MAX485 direkt dranhängen (beim ATMega8 einfach Pin2 an Pin1 vom MAX485 und Pin3 vom ATMega8 an Pin4 vom MAX485, Pin2 und Pin3 vom MAX485 mit Pin4 vom ATMega8 verbinden [kann jeder Output-Pin sein, da hier zwischen Senden und Empfangen umgeschaltet wird], Pin 6 und 7 einfach identisch parallel an alle anderen MAX485er anschließen..)
    Für den Konverter hab eich den von aquaticus.info genommen...
    http://aquaticus.info/rs485_to_rs232 WICHTIG: in dem Layout fehlt die Spannungsversorgung den Pins des Max232.. das scheint normal zu sein hat mich aber ziemlich irritiert ...
    Was auch gut geht, ist den RS232-TTL-Wandler von Pollin zu nehmen und dann einfach daran noch ne kleine Platine mit dem rest (MAX485 und ne Diode samt widerstand anzusetzen..) (wenn man keine platinen ätzt/ätzen kann..)
    Wenn du nen oszi hast, kannst du nach dem Bau einfach ne Differentialmessung machen und dann sehen, wenn du ein signal dauerhaft sendest (dann hast du ne chance was zu sehen), dass die schaltung funktioniert..
    hab leider kein programm für nen schaltplan, sonst hätte ich dir meine schaltung aufgezeichnet (mache einfach ne paint skizze)
    am besten mit HTerm machen da gibts den "ASend" button. dann wird ein zeichen folge du eingibst dauerhaft gesendet..
    Wichtig: zum umschalten zwischen senden und empfangen am PC gilt es leider wegen der umsetzung mit RTS umgekehrt..
    wenn du RTS angeklickt hast (in HTerm) dann empfängst du daten und wenn du den button nicht geklickt hast empfängst du..
    (hoffe, dass ist noch verständlich - man siehts auch auf dem hterm bild, da ist der button geklickt für empfang.. - bei dem aquaticus konverter geht dann die LED aus.. ) bei längeren strecken sei auf die terminierung hingewiesen... ich denke auf der RS485 seite sollte was zu dem thema stehen mit den widerstandswerten..

    Spannungsversorgung Kondensatoren und so hab ich weggelassen..

    hier sieht man den kauderwelsch der noch so übertragen wird ohne, dass ich weiß wo der her kommt.. und hier der Code (Kommunikationsfunktionen ausgelagert..)
    Motor-treiber.c
    Code:
    //-----------------------------------------------------------------------------------------//
    //-----------------------------------------------------------------------------------------//
    //                         RS485- Implementierung mit MAX 485                              //
    //                      Autor: Niels Göran Blume 2007 für ROUVus                           //
    //                               www.hardegser-sv.de/rov                                   //
    //-----------------------------------------------------------------------------------------//
    //-----------------------------------------------------------------------------------------//
    /*
    	Hardware- Konzessionen:
    	Atmega8 mit UART an PORTD0 und PORTD1 und Switch Receive/Send für MAX 485 an PORTD2
    	Halb-Duplex
    */
    
    /* 	Protokoll- Definition:
    	Das Protokoll ist auf den One-Master-Multi-Slave-Betrieb ausgelegt.
    	Bei entsprechender Programmierung ist auch ein eingeschränkter 
    	Multi-Master-Betrieb möglich.
    	
    	Standard: Jede Nachricht startet mit "!".
    	Es folgt die Adresse des Ziels in einem Byte.
    	Nun folgen 5 Datenbytes, die beliebig gefüllt werden können (Erweiterung einfach möglich).
    	Am Ende steht in der Zielmaschine ein char- Array bereit, dass alle Bytes seit dem "!" 
    	(sprich Adresse und 5 Datenbytes) enthält.
    	
    	| ! | a | L | E | D | 1 | 1 | als Beispiel...
    	
    	An Adresse "a" ergeht die Nachricht "LED11", was vielleicht als "LED1 auf Status 1 setzen"
    	interpretiert werden könnte.
    */
    
    #define F_CPU       16000000UL
    
    #include <avr/io.h>
    #include <inttypes.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <string.h>
    #include "rs485.c"
    
    int main(void)
    {
    	int i = 0;
    	// USART initialisieren (8n1 - 19200)
        rs485_init();
    	
    	//Output DDD2 setzen für Send/Receive- Wechsel / DDD3 für ne LED
    	DDRD = (1<<DDD2)|(1<<DDD3);
    	
    	warte(5000);
    	
    	rs485_puts('a',"Melde mich zum Dienst ! Meine Adresse: b");
    	
    	sei();
    	
    	PORTD |= (1 << 3);
    	
    	while(1)								//Reaktion in Schleife
    	{
    		if (befehl_fertig == 1)
    		{
    			warte(5000);
    			rs485_puts('a',buffer);
    			befehl_fertig = 0;
    		}
    	}
    	;
    }
    rs485.c
    Code:
    #include "rs485.h"
    #define BAUD        19200UL
    #define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)
    
    char buffer[6];
    char kommando[6];
    int buffer_pos = 0;
    int befehl = 0;
    int address = 0;
    int befehl_fertig = 0;
    
    void warte (uint16_t loop) //loop: wartezeit in ms
    {
    	uint16_t i;
    	for(i=0;i<loop;i++) _delay_ms(1); 
    }
    
    // Empfangene Zeichen werden im Buffer gespeichert und warten dort 
    SIGNAL (SIG_UART_RECV)
    {
    	char data;
    	int i;
    	
    	data = UDR;
    	if (data == '!')
    	{
    		befehl = 1;
    		address = 0;
    		return;
    	}
    	else
    	{
    		if(befehl == 1 && address == 0)
    		{
    			if (data == 'b')							//Unsere Adresse ?
    			{
    				buffer[buffer_pos] = data;
    				buffer_pos++;
    				address = 1;
    				return;
    			}
    			else
    			{
    				befehl = 0;
    				address = 0;
    				return;
    			};
    		};	
    		
    		if(befehl == 1 && address == 1)
    		{
    			buffer[buffer_pos] = data;
    			if (buffer_pos < 5)							//Noch ein Platz frei im Buffer ?
    			{
    				buffer_pos++;							//Dann Zeiger erhöhen
    				return;
    			}
    			else
    			{
    				buffer_pos = 0;							//Wenn Buffer voll, reset an Anfang 
    				befehl = 0;								//Befehl fertig...
    				address = 0;
    				//Interrupt starten -> Befehl fertig !!
    				//for (i=0; i<6; i++)
    				//{
    				//	kommando[i] = buffer[i];
    				//};
    				befehl_fertig = 1;
    				return;
    			};
    		};
    	};
    }
    
    void rs485_init()
    {
    	// Baudrate einstellen (Normaler Modus)
        UBRRH = (unsigned char) (UBRR_BAUD>>8);
        UBRRL = (unsigned char) (UBRR_BAUD & 0x0ff);
    
        // Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts
        UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
    
        // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
        UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
    }
    
    // Um das Problem bei RS485 zu umgehen, dass nicht gleichzeitig gesendet und empfangen werden kann (2 Adern),
    // nur "direktes" Senden möglich
    
    // Einzelnes Zeichen senden
    void rs485_putc (unsigned char address, unsigned char buffer)
    {
    	while ( !(UCSRA & (1<<UDRE)));				//Warten bis UDR leer ist für Senden
    	PORTD |= (1 << 2);								//Max485 auf Senden
    	UDR = '!';										//Sendungsanfang
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten bis Senden abgeschlossen
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	UDR = address;									//Adresse senden
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten bis Senden abgeschlossen
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	UDR = buffer;									//Daten senden
    	
    	warte(100);										//MAX485-Buffer leeren lassen
    	PORTD &= ~(1 << 2);							//Max485 auf Empfang
    }
    
    // String senden
    void rs485_puts (unsigned char address, const char *s)
    {
    	while ( !(UCSRA & (1<<UDRE)));				//Warten bis UDR leer ist für Senden				
    	PORTD |= (1 << 2);								//Max485 auf Senden
    	UDR ='!';
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten, bis Senden abgeschlossen wurde
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	UDR = address;									//Adresse senden
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten bis Senden abgeschlossen
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	
    	while (*s != 0)
    	{
    		loop_until_bit_is_set(UCSRA,UDRE);			//warte bis Datenregister frei
    		UDR = *s;									//Zeichen nach Sendedatenregister
    		s++;										//Adresse erhöhen
    	}	
    	
    	while (*s++);
    	warte(100);										//MAX485-Buffer leeren lassen
    	PORTD &= ~(1 << 2);							//Max485 auf Emfang
    }
    rs485.h:
    Code:
    #ifndef _RS485_H_
    #define _RS485_H_
    
    extern void rs485_init();
    extern void rs485_putc(unsigned char address, unsigned char buffer);
    extern void rs485_puts(unsigned char address, const char *s);
    extern void warte(uint16_t loop);
    
    static inline void rs485_flush()
    {
    	while (UCSRB & (1 << UDRIE));
    }
    
    #endif /* _RS485_H_ */

  4. #4
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    brauchst du nicht einen null-terminierten string (und damit 7 bytes), damit deine sende-routine funktioniert? ohne \0 wird er fröhlich weitersenden, was den zeichenmüll erklären würde.

    gruesse

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    17.02.2004
    Beiträge
    23

    null-terminierten string

    Hallo..

    probier ich gleich mal aus.
    ich glaube es aber eher nicht denn ich hab noch ein paar test durchgeführt undfolgendes festgestellt:
    Code:
    //-----------------------------------------------------------------------------------------//
    //-----------------------------------------------------------------------------------------//
    //                         RS485- Implementierung mit MAX 485                              //
    //                      Autor: Niels Göran Blume 2007 für ROUVus                           //
    //                               www.hardegser-sv.de/rov                                   //
    //-----------------------------------------------------------------------------------------//
    //-----------------------------------------------------------------------------------------//
    /*
    	Hardware- Konzessionen:
    	Atmega8 mit UART an PORTD0 und PORTD1 und Switch Receive/Send für MAX 485 an PORTD2
    	Halb-Duplex
    */
    
    /* 	Protokoll- Definition:
    	Das Protokoll ist auf den One-Master-Multi-Slave-Betrieb ausgelegt.
    	Bei entsprechender Programmierung ist auch ein eingeschränkter 
    	Multi-Master-Betrieb möglich.
    	
    	Standard: Jede Nachricht startet mit "!".
    	Es folgt die Adresse des Ziels in einem Byte.
    	Nun folgen 5 Datenbytes, die beliebig gefüllt werden können (Erweiterung einfach möglich).
    	Am Ende steht in der Zielmaschine ein char- Array bereit, dass alle Bytes seit dem "!" 
    	(sprich Adresse und 5 Datenbytes) enthält.
    	
    	| ! | a | L | E | D | 1 | 1 | als Beispiel...
    	
    	An Adresse "a" ergeht die Nachricht "LED11", was vielleicht als "LED1 auf Status 1 setzen"
    	interpretiert werden könnte.
    */
    
    #define F_CPU       16000000UL
    
    #include <avr/io.h>
    #include <inttypes.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <string.h>
    #include "rs485.c"
    
    int main(void)
    {
    	int i = 0;
    	char *test = "Test!";
    	// USART initialisieren (8n1 - 19200)
        rs485_init();
    	
    	//Output DDD2 setzen für Send/Receive- Wechsel / DDD3 für ne LED
    	DDRD = (1<<DDD2)|(1<<DDD3);
    	
    	warte(5000);
    	
    	rs485_puts('a',"Melde mich zum Dienst ! Meine Adresse: b");
    	
    	rs485_puts('a', test);
    	
    	sei();
    	
    	PORTD |= (1 << 3);
    	
    	while(1)								//Reaktion in Schleife
    	{
    		if (befehl_fertig == 1)
    		{
    			warte(5000);
    			rs485_puts('a',buffer);
    			befehl_fertig = 0;
    		}
    	}
    	;
    }
    Da wird ja eine art string initialisiert (was ist das eigentlich wirklich ??) un ihm der inhalt "Test!" zugewiesen und dann wird das ganze gesendet.. Funktioniert perfekt kein datenmüll hinterher...
    ich habe den verdacht, dass das an dem array liegt in dem ich die datenbytes speichere.. ich habs mal mit:

    char *data;
    char *buffer;
    und dann buffer = buffer + data;

    versucht..
    aber da wollte er dann nicht so wirklich, weil er "+" nicht auf binary anwenden wollte..
    ich denke irgendwo liegt der sprichtwörtliche hund begraben..

    MfG
    ngb

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    17.02.2004
    Beiträge
    23

    Einfall - nachträglich

    hey..
    außerdem ist mir noch eingefallen, dass das ja bedeuten würde, dass mein test automatisch null-terminierd wird, oder ?
    und rs485_puts an dieser stelle auf die terminierung wartet:
    Code:
    while (*s != '\0')
    	{
    		loop_until_bit_is_set(UCSRA,UDRE);			//warte bis Datenregister frei
    		UDR = *s;									//Zeichen nach Sendedatenregister
    		s++;										//Adresse erhöhen
    	}
    daraus resultiert eine andere frage:
    kann man das nicht irgerndwie abändern, dass er am ende einfach aufhört..?
    ich würde gerne ohne null-terminierte string-chars arbeiten..

    MfG
    ngb

  7. #7
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    strings sind char arrays, deren letztes byte 0 ist.
    wenn du mit char test[]="test"; einen string erzeugst, hat dieser nicht 4 sondern 5 bytes. strings ohne \0 kannst du notfalls verwenden, wenn du ihre exakte länge (bei dir 6 zeichen) kennst, und nicht überschreitest.
    for(i=0;i<6;i++)send(test[i]);
    sobald du aber "while(...!=0){}" verwendest, musst du mit 0 terminieren, sonst weiss der µC/prozessor nicht, wie lang der string ist.

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    17.02.2004
    Beiträge
    23

    Vergleiche

    Danke..
    das klärt einiges..
    ich hab den code angepasst an die idee mit terminierung und jetzt sieht das result wie gewünscht aus..
    ein problem stellt sich noch und das ist der vergleich mit terminierten strings..
    Code:
    	while(1)								//Reaktion in Schleife
    	{
    		if (befehl_fertig == 1)
    		{
    			warte(5000);
    			rs485_puts('a',buffer);
    			if(buffer == "bled11")
    			{
    				PORTD |= (1 << 3);
    				rs485_puts('a', "Kommando erhalten...");
    				warte(2000);
    				PORTD &= ~(1 << 3);
    			};
    			befehl_fertig = 0;
    		}
    	};
    das problem ist das die LED nie leuchtet und er sich auch nicht zu wort meldet wie gewünscht, wenn ich ihm das kommando sende..
    wie kann ich am einfachsten den vergleich für das kommando durchführen und kann ich später wenn ich kommandos mit parameter habe (motorgeschwindigkeiten) noch per string[i] auf einzelne zeichen zugreifen ?
    wenn du mir das noch auch beantworten könntest, wäre mir sehr geholfen !
    Vielen dank !

    MfG
    ngb

  9. #9
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    42
    Beiträge
    2.234
    Hallo,
    schau mal, was Du da vergleichst
    if(buffer == "bled11")
    buffer könnte man auch so ausschreiben
    &buffer[0]
    Du vergleichst dann wohl eine Adresse mit string.
    Schau dir mal Funktionen von string.h und vor allem strcmp
    http://www.nongnu.org/avr-libc/user-...r__string.html

    Ich hoffe, daß ich helfen konnte.

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    17.02.2004
    Beiträge
    23

    Protokoll funzt..

    vielen dank ! =D>
    ich dachte nicht, dass man das so ohne weiteres mit strcmp machen kann..
    und das mit dem &-Zeichen kommt mir auch wieder dunkel in den sinn aus den C++ zeiten...
    jetzt funktioniert das einwandfrei..
    fertig..
    werden den code mal posten falls jemand etwas ähnliches braucht vielleicht als inspiration oder relativ fertige funktionen zum senden und empfangen.. (wobei die qualität noch etwas zu wünschen übrig lässt, auch was das protokoll angeht..)
    motor-treiber.c
    Code:
    //-----------------------------------------------------------------------------------------//
    //-----------------------------------------------------------------------------------------//
    //                         RS485- Implementierung mit MAX 485                              //
    //                      Autor: Niels Göran Blume 2007 für ROUVus                           //
    //                               www.hardegser-sv.de/rov                                   //
    //-----------------------------------------------------------------------------------------//
    //-----------------------------------------------------------------------------------------//
    /*
    	Hardware- Konzessionen:
    	Atmega8 mit UART an PORTD0 und PORTD1 und Switch Receive/Send für MAX 485 an PORTD2
    	Halb-Duplex
    */
    
    /* 	Protokoll- Definition:
    	Das Protokoll ist auf den One-Master-Multi-Slave-Betrieb ausgelegt.
    	Bei entsprechender Programmierung ist auch ein eingeschränkter 
    	Multi-Master-Betrieb möglich.
    	
    	Standard: Jede Nachricht startet mit "!".
    	Es folgt die Adresse des Ziels in einem Byte.
    	Nun folgen 5 Datenbytes, die beliebig gefüllt werden können (Erweiterung einfach möglich).
    	Am Ende steht in der Zielmaschine ein char- Array bereit, dass alle Bytes seit dem "!" 
    	(sprich Adresse und 5 Datenbytes) enthält.
    	
    	| ! | a | L | E | D | 1 | 1 | als Beispiel...
    	
    	An Adresse "a" ergeht die Nachricht "LED11", was vielleicht als "LED1 auf Status 1 setzen"
    	interpretiert werden könnte.
    */
    
    #define F_CPU       16000000UL
    
    #include <avr/io.h>
    #include <inttypes.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <string.h>
    #include "rs485.c"
    
    int main(void)
    {
        rs485_init();											//USART initialisieren (8 Datenbits, no Parity, 1 Stopbit)
    															//Baud: 19200 
    	DDRD = (1<<DDD2)|(1<<DDD3);							//Output DDD2 setzen für Send/Receive- Wechsel
    															//DDD3 für ne LED
    	warte(5000);
    	
    	rs485_puts('a',"Melde mich zum Dienst ! Meine Adresse: b");
    	
    	sei();													//Interrupts enablen
    	
    	PORTD &= ~(1 << 3);									//LED ausschalten
    	
    	while(1)												//Reaktion in Schleife
    	{
    		if (befehl_fertig == 1)							//Befehl vorhanden
    		{
    			warte(5000);									//Zeit damit ich den Sende-Mode am PC mit der Maus beenden kann
    			rs485_puts('a',buffer);							//Einfach empfangenes Kommando zurücksenden
    			if(strcmp(buffer, "bled11") == 0)				//Beispielkommando als Vergleichsgrundlage
    			{												//später weitere zum Beispiel als Switch 
    				PORTD |= (1 << 3);							//mit einzelnem Byte (&buffer[i]) | LED an
    				rs485_puts('a', "Kommando erhalten...");	//If-Routine erreicht-Bestätigung
    				warte(2000);								//Damit man die LED überhaupt leuchten sieht
    				PORTD &= ~(1 << 3);						//LED aus
    			};
    			befehl_fertig = 0;								//Befehl abgearbeitet - Status zurücksetzen
    		}
    	};
    }
    rs485.c:
    Code:
    #include "rs485.h"
    #define BAUD        19200UL
    #define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)
    
    char buffer[7];
    int buffer_pos = 0;
    int befehl = 0;
    int address = 0;
    int befehl_fertig = 0;
    
    void warte (uint16_t loop) //loop: wartezeit in ms
    {
    	uint16_t i;
    	for(i=0;i<loop;i++) _delay_ms(1); 
    }
    
    // Empfangene Zeichen werden im Buffer gespeichert und warten dort 
    SIGNAL (SIG_UART_RECV)
    {
    	char data;
    	int i;
    	
    	data = UDR;
    	if (data == '!')
    	{
    		befehl = 1;
    		address = 0;
    		return;
    	}
    	else
    	{
    		if(befehl == 1 && address == 0)
    		{
    			if (data == 'b')							//Unsere Adresse ?
    			{
    				buffer[buffer_pos] = data;
    				buffer_pos++;
    				address = 1;
    				return;
    			}
    			else
    			{
    				befehl = 0;
    				address = 0;
    				return;
    			};
    		};	
    		
    		if(befehl == 1 && address == 1)
    		{
    			buffer[buffer_pos] = data;
    			if (buffer_pos < 5)							//Noch ein Platz frei im Buffer ?
    			{
    				buffer_pos++;							//Dann Zeiger erhöhen
    				return;
    			}
    			else
    			{
    				buffer_pos = 0;							//Wenn Buffer voll, reset an Anfang 
    				befehl = 0;								//Befehl fertig...
    				address = 0;
    				buffer[6] = '\0';
    				
    				befehl_fertig = 1;
    				return;
    			};
    		};
    	};
    }
    
    void rs485_init()
    {
    	// Baudrate einstellen (Normaler Modus)
        UBRRH = (unsigned char) (UBRR_BAUD>>8);
        UBRRL = (unsigned char) (UBRR_BAUD & 0x0ff);
    
        // Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts
        UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
    
        // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
        UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
    }
    
    // Um das Problem bei RS485 zu umgehen, dass nicht gleichzeitig gesendet und empfangen werden kann (2 Adern),
    // nur "direktes" Senden möglich
    
    // Einzelnes Zeichen senden
    void rs485_putc (unsigned char address, unsigned char buffer)
    {
    	while ( !(UCSRA & (1<<UDRE)));				//Warten bis UDR leer ist für Senden
    	PORTD |= (1 << 2);								//Max485 auf Senden
    	UDR = '!';										//Sendungsanfang
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten bis Senden abgeschlossen
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	UDR = address;									//Adresse senden
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten bis Senden abgeschlossen
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	UDR = buffer;									//Daten senden
    	
    	warte(100);										//MAX485-Buffer leeren lassen
    	PORTD &= ~(1 << 2);							//Max485 auf Empfang
    }
    
    // String senden
    void rs485_puts (unsigned char address, const char *s)
    {
    	while ( !(UCSRA & (1<<UDRE)));				//Warten bis UDR leer ist für Senden				
    	PORTD |= (1 << 2);								//Max485 auf Senden
    	UDR ='!';
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten, bis Senden abgeschlossen wurde
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	UDR = address;									//Adresse senden
    	
    	while ( !(UCSRA & (1<<TXC)));					//Warten bis Senden abgeschlossen
    	UCSRA &= ~(1<<TXC);							//Gesendet-Bit löschen
    	
    	while (*s != '\0')
    	{
    		loop_until_bit_is_set(UCSRA,UDRE);			//warte bis Datenregister frei
    		UDR = *s;									//Zeichen nach Sendedatenregister
    		s++;										//Adresse erhöhen
    	}	
    	
    	warte(100);										//MAX485-Buffer leeren lassen
    	PORTD &= ~(1 << 2);							//Max485 auf Emfang
    }
    rs485.h:
    Code:
    #ifndef _RS485_H_
    #define _RS485_H_
    
    extern void rs485_init();
    extern void rs485_putc(unsigned char address, unsigned char buffer);
    extern void rs485_puts(unsigned char address, const char *s);
    extern void warte(uint16_t loop);
    
    static inline void rs485_flush()
    {
    	while (UCSRB & (1 << UDRIE));
    }
    
    #endif /* _RS485_H_ */
    Schönes Wochenende !
    MfG
    ngb

+ Antworten
Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Ja
  • Themen beantworten: Ja
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •