Hey..
hier der richtige code..
hoffe der hilft bei der lösung
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)|(1<<DDB1); //Output DDD2 setzen für Send/Receive- Wechsel
//DDD3 für ne LED und DDB1 für PowerMOSFet
warte(5000);
rs485_puts('a',"Melde mich zum Dienst ! Meine Adresse: b");
sei(); //Interrupts enablen
PORTD &= ~(1 << 3); //LED ausschalten
PORTB &= ~(1 << 1);
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
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', "led11");
};
if(strcmp(buffer,"bled10")==0)
{
PORTD &= ~(1 << 3);
rs485_puts('a',"bled10");
};
if(strcmp(buffer,"bpwm11")==0)
{
PORTB |= (1 << 1);
};
if(strcmp(buffer,"bpwm10")==0)
{
PORTB &= ~(1 << 1);
};
befehl_fertig = 0; //Befehl abgearbeitet - Status zurücksetzen
}
};
}
und die 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
}
und die 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_ */
vielen dank für alle vorschläge im voraus !
MfG
ngb
Lesezeichen