PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 3 ATMega8 verbinden? Bus?



TobiasBlome
24.03.2009, 14:56
Hallo,
ich möchte 3 Mega8 vernetzen. Welches Bussystem ist am einfachsten für meine Zwecke zu realisieren(soft/hardware)?

-Bascom
- 3 Mega8
-Leitung zwischen den µC´s ca. 7m (also µC1 >7m Kabel> µC2 >7m Kabel> µC3)
-jeder µC soll mit jedem µC Daten austauschen können.
-Geschwindigkeit: min 4 Integerwerte / sekunde übertragen (+Start Stopbits...)

RS232 wäre schön eignet sich aber wohl nicht für 3µC bidirektional?
RS485?
I²C nicht in der Länge? Störungen?

Hat jemand eine Idee / Vorschlag oder gibt es da etwas passendes was ich mit der Suche nicht gefunden habe?

Danke - Tobias

python_rocks
24.03.2009, 15:27
-Bascom
- 3 Mega8
-Leitung zwischen den µC´s ca. 7m (also µC1 >7m Kabel> µC2 >7m Kabel> µC3)
-jeder µC soll mit jedem µC Daten austauschen können.
-Geschwindigkeit: min 4 Integerwerte / sekunde übertragen
Hallo Tobias!

RS-485 ist in diesem Fall mit Bascom das Einfachste. Einer der µC dient als Vermittler (µC1). Der Vermittler schickt der Reihe nach, zuerst an µC2 und dann an µC3 die Nachricht, dass jetzt der jeweilige µC eine Nachricht verschicken darf. Dann bekommt der jeweilige µC kurz Zeit, auf die Frage mit einer Nachricht zu antworten. Ist die Zeitspanne verstrichen, geht es mit dem nächsten µC weiter.

In der Nachricht steht, an wen die Nachricht geschickt werden soll. Alle µC hören mit. So bekommt jeder µC die Nachricht, die für ihn bestimmt ist.

Diese Einfache Zuteilung von Gesprächszeiten, funktioniert natürlich nur, so lange es sich um wenige µC handelt und genug Zeit zum Übermitteln der Nachrichten bleibt. Aber in deinem Fall ist mehr als genug Zeit vorhanden.

mfg
Gerold
:-)

TobiasBlome
24.03.2009, 15:46
Tja - mit RS485 habe ich mich noch nicht beschäftigt. Aber wenn ich mir das Prinzip so lese, dann könnte ich ja auch bei RS232 bleiben:
Genau genommen habe ich µC1 mit Tastern und LCD. Nur µC1 kommuniziert mit µC2 oder µC3. µC2&3 müssen NICHT untereinander kommunizieren.

In diesem Fall brauche ich glaub ich nur Rx und Tx von µC2&3 paralell zu schalten und µC1 gekreuzt. Vor jeder Nachricht muss ich dann schreiben ob die für µC2 oder µC3 ist richtig?
Oder habe ich da einen Denkfehler.

Tobias

Neutro
24.03.2009, 16:17
Ich würde auch sagen das das so gehen sollte. Ich habe in einem anderem
Forum schon mal was ähnliches gesehen, allerdings mit nur zwei Controllern.
Wenn du die die Software vom Sender und Empfänger genau anschaust, sollte es nicht schwer sein diesen für deine Zwecke zu modifizieren.
Hier der Link: http://bascom-forum.de/index.php/topic,2012.0.html

Gruß

Neutro

TobiasBlome
24.03.2009, 16:30
ich bau einfach mal die Hardware und probier ich das mal aus ;-)

@Neutro
in dem Forumsbetrag sendet nur der eine µC zum anderen(wenn ich mich nicht verlesen habe) und ich benötige ja in beide Richtungen. Warscheinlich werde ich dem Empfang auch über einen Interrupt laufen lassen...

Tobias

Neutro
24.03.2009, 16:44
Das mit der BI direktionalen Kommunikation hatte ich glatt überlesen.......
Aber das dürfte eigentlich nicht so ein Drama sein das in den Griff zu bekommen solange immer nur zwei Controller gleichzeitig kommunizieren und der dritte schwiegt. Mit dem Input Befehl in dem Programm bekommt man ja eine Art Adressierung.

Neutro

TobiasBlome
24.03.2009, 16:50
Mit dem Input Befehl in dem Programm bekommt man ja eine Art Adressierung.

Neutro

wie meinst du das?

Mit input bekomme ich doch alles was gesendet wurde... Ich dachte mir das das ich das empfangene vergleiche und wenn zb. slave1 empfangen wurde wird eine Variable im entsprechendem µC auf 1 gesetzt und bekommt damit die Erlaubnis zu senden. Nach dem Senden setzt der µC die Varable wieder auf 0...
War so eine Idee....

Neutro
24.03.2009, 17:02
Hmm, ich habe mir gerade noch mal das slave programm angeschaut, das mit dem Input hatte ich dann wohl falsch verstanden, es ist ja so das die Input´s hier in der Reihenfolge abgefragt werden in der auch gesendet wird. die Werte werden dann ja in die entspechende Variable geschrieben.....Sorry.....
Aber mit z.B A = Inkey () und dann einer Case Anweisung für die entspechenden Werte muss das doch eigentlich funktionieren, oder bin ich da jetzt fasch vom Verständnis her? Im Prinzip also das was du dir auch ausgedacht hattest.

TobiasBlome
24.03.2009, 17:21
weitere Idee:
Der Master sendet NUR zb. "Wert1" als Text.
Wert1 ist NUR im Slave1 hinterlegt, also kann auch nur Slave1 antworten...

Slave1 würde dann dieses Prog bekommen:



'µC
'Quarz
'Baud

'Variablen
Dim i as String*20 'besser zulang oder?
Dim Wert1 as integer 'Wert von analogeingang

On URXC OnRxD 'Interrupt-Routine setzen
Enable URXC 'Interrupt URXC einschalten
Enable Interrupts 'Interrupts global zulassen
'---------------------------------------------------


Main: 'Hauptschleife

'IRGENDETWAS
'analogeingang auslesen und in Variable Wert1 schreiben

Goto Main
'---------------------------------------------------


OnRxD:
i = UDR 'aus der UART auslesen

If i = "Wert1" Then
print Wert1 'Wobei Wert1 zb. ein vorher analogeingelesender Wert ist
End if

Return

Neutro
24.03.2009, 17:30
Ja, so hatte ich das auch überlegt. Auf Werte die der Empfänger nicht "kennt"
wird er dann ja auch nicht reagieren.
Das ist das selbe Prinzip wie mit der Case Abfrage, Werte die im Case nicht vorkommen werden ignoriert werden, bzw. es passiert einfach nichts.

TobiasBlome
24.03.2009, 20:26
Hallo,
der Testaufbau ist fertig.
Der Sender sendet nun ca alle 10 Sekunden den Text "Wert1"
Print "Wert1"

Der Empfänger soll den Text erstmal nur empfangen und auf dem LCD ausgeben. Leider tauchen alle 10 sekunden nur ein paar zahlen auf....

(Damit der µC noch etwas nebeibei tut, wird Variable Test1 und Test2 hochgezählt und die LCD Beleuchtung blinkt um zu sehen das der µC aktiv ist)

Hier mein Empfängercode:


'Autobussystem Empfänger
'basierend auf RS232

'Problem mit Taster 5??? NEIN, weil Progadapter drauf war!!!
'-------------------------------------------------------------------------------
'Konfiguration µC:

$regfile = "m8def.dat" 'AT-Mega8
$crystal = 8000000 'Quarz: 8 MHz
$baud = 9600 'Baudrate definieren
'-------------------------------------------------------------------------------
'Ein / Ausgänge definieren:
Ddrb = &B11000001 'PB7-0: 1 Ausgang, 0 Eingang = Pin PB5-1 als Eingang
Ddrc = &B0000001 'PC6-0: 1 Ausgang, 0 Eingang = Pin PC6-1 als Eingang

'PullUps setzen:
Portb = &B00111110 '1 = PullUp AKTIV ->PB 7,6,0 nicht aktiv
Portc = &B0111110 '1 = PullUp AKTIV ->PC 6,0 nicht aktiv


'-------------------------------------------------------------------------------
'LCD konfiguration
Config Lcd = 16 * 2 'LCD größe
Config Lcdpin = Pin , Db4 = Portd.5 , Db5 = Portd.6 , Db6 = Portd.7 , Db7 = Portb.0 , Rs = Portb.6 , E = Portb.7
Cursor Off Noblink

'-------------------------------------------------------------------------------
'Alias
Taster1 Alias Pinb.1
Taster2 Alias Pinb.2
Taster3 Alias Pinb.3



'-------------------------------------------------------------------------------
'Variablen
Dim Test1 As Integer
Dim Test2 As Integer

Dim Wert1 As Integer
Dim Wert2 As Integer

Dim I As integer 'Wert von RS232
'-------------------------------------------------------------------------------
'Timer
'Timer1 = 2x / sec bei 8MHz
Config Timer1 = Timer , Prescale = 256 'Teiler
Const Timervorgabe = 49910
Enable Timer1
Enable Interrupts
On Timer1 Lcd 'timer einschalten


'-------------------------------------------------------------------------------
'Für RS232:
On Urxc Onrxd 'Interrupt-Routine setzen
Enable Urxc 'Interrupt URXC einschalten
Enable Interrupts 'Interrupts global zulassen
'-------------------------------------------------------------------------------

Main: 'Hauptschleife

'analogeingang auslesen und in Variable Wert1 schreiben

'IRGENDETWAS MACHEN:
Incr Test1
If Test1 = 65000 Then
Toggle Portc.0 'LCD Beleuchtung
Incr Test2
Test1 = 0
End If


Goto Main

'-------------------------------------------------------------------------------
Onrxd:
I = Udr 'aus der UART auslesen
Lcd I

'If I = "Wert1" Then
'Print Wert1 'Wobei Wert1 zb. ein vorher analogeingelesender Wert ist
'Locate 2 , 1
'Lcd Wert1
'End If

Return


'-------------------------------------------------------------------------------
'Timer0zähler:
'Timer1 = 49910
'Incr Timer0_60
'
'If Timer0_60 > 30 Then
'Timer0_60 = 0
'Gosub Lcd 'und später das Programm hier fortführen!
'Toggle Portc.0
'End If
'Return



'-------------------------------------------------------------------------------
Lcd:
Timer1 = 49910
Cls 'Display löschen (IMMER ERST LCD LÖSCHEN UND DANN POSITION ANGEBEN!!!)
Locate 1 , 1
Lcd "Test2: " ; Test2
'Locate 2 , 1
'Lcd + Str(timer0_60)
Return


'================================================= ==============================
'Pinbelegung µC Miri Rechner
'================================================= ==============================
' AT MEGA 8
' +---U---+
' Reset PC6 +1 28+ PC5 Taster10
' RXD PD0 +2 27+ PC4 Taster9
' TXD PD1 +3 26+ PC3 Taster8
' PD2 +4 25+ PC2 Taster7
' PD3 +5 24+ PC1 Taster6
' PD4 +6 23+ PC0 LCD Beleuchtung
' Vcc +7--- 22+ GND | / Reset |
' GND +8 |-21+ AREF | / GND |
' RS PB6 +9 |-20+ AVCC | / +5V |
' E PB7 +10 19+ PB5 Taster5 | / SCK |
' / LCD / DB4 PD5 +11 18+ PB4 Taster4 | / MISO |
' / LCD / DB5 PD6 +12 17+ PB3 Taster3 | / MOSI |
' / LCD / DB6 PD7 +13 16+ PB2 Taster2 ___________
' / LCD / DB7 PB0 +14 15+ PB1 Taster1
' +-------+



'================================================= ==============================
'Pinbelegung AM LCD!!!!!!! ACHTUNG!!!!!
'================================================= ==============================
'Pin 1: GND
'Pin 2: +5V
'Pin 3: Kontrast (0-5V)
'Pin 4: RS -> AVR
'Pin 5: R/W -> GND (read/write mode, nur writen)
'Pin 6: E -> AVR
'Pin 7-10: -> GND
'Pin 11-14: -> AVR -> 11=DB4 / 12=DB5 / 13=DB6 / 14=DB7
'Pin 15-16: Beleuchtung

TobiasBlome
24.03.2009, 21:06
Also
wenn ich statt einem Wort einen Buchstaben sende:
Print "W"
dann geht es:



dim i as byte

'---

Onrxd:
I = Udr 'aus der UART auslesen

If I = "W" Then
Print Wert1 'Wobei Wert1 zb. ein vorher analogeingelesender Wert ist
Locate 2 , 1
Lcd "Wert1"
End If

Return


gibt es eine Möglichkeit ein Wort zu empfangen?

Tobias

Vitis
25.03.2009, 07:28
senden und empfangen tust Du immer Bytes ... die kannste aber
zu Word, Long, Single zusammensetzen :)

python_rocks
25.03.2009, 08:44
gibt es eine Möglichkeit ein Wort zu empfangen?
Hallo Tobias!

Die einfachste Möglichkeit: Sende die Zahl als Text und wandle den Text beim Empfänger mit VAL in eine Zahl um.

Und noch etwas: Nimm RS-485 für dein Vorhaben. RS-485 ist besser für deine Entfernungen geeignet. An jeden µC einen MAX485 dran und schon ist die Sache erledigt. In Bascom musst du nur noch mit CONFIG PRINT den Pin einstellen, der den MAX485 in den Sendemodus schaltet. Fertig!

Außerdem würde ich CONFIG SERIALIN beim Empfänger verwenden. Das vereinfacht das Programm.

- http://avrhelp.mcselec.com/index.html?val.htm
- http://avrhelp.mcselec.com/index.html?mid.htm
- http://avrhelp.mcselec.com/index.html?configprint.htm
- http://halvar.at/elektronik/kleiner_bascom_avr_kurs/uart_rs232_vom_computer_2/ (CONFIG SERIALIN)
- http://halvar.at/elektronik/rs485/

mfg
Gerold
:-)

TobiasBlome
25.03.2009, 19:12
Hallo,
ich habe einiges gelesen - darum kann ich erst nun schreiben - aber mit Erfolg - zumindes ein bisschen ;-)

Den Befehl zum senden habe ich nun aufgeteilt in: #Slave,Parameter:Wert"CR"
so kann ich genau sagen für welchen µC die Nachricht ist, um welche Daten es sich handelt (Strom, Spannung...) und natürlich den Wert, der später dafür auf das LCD soll:
Der Sender hat nun (zum testen)den Befehl: Print "#S1,Strom:1234"

Leider zeigt der Empfänger das Wort "Strom" nicht an?!

Die Anzeige auf dem LCD vom Empfänger ist nun: S1,0:1234
soweit richtig - bis auf die 0 - da sollte "Strom" stehen - kann mir das einer erklären?



'-------------------------------------------------------------------------------
'Konfiguration µC:

$regfile = "m8def.dat" 'AT-Mega8
$crystal = 8000000 'Quarz: 8 MHz
$baud = 9600 'Baudrate definieren
'-------------------------------------------------------------------------------
'Ein / Ausgänge definieren:
Ddrb = &B11000001 'PB7-0: 1 Ausgang, 0 Eingang = Pin PB5-1 als Eingang
Ddrc = &B0000001 'PC6-0: 1 Ausgang, 0 Eingang = Pin PC6-1 als Eingang

'PullUps setzen:
Portb = &B00111110 '1 = PullUp AKTIV ->PB 7,6,0 nicht aktiv
Portc = &B0111110 '1 = PullUp AKTIV ->PC 6,0 nicht aktiv


'-------------------------------------------------------------------------------
'LCD konfiguration
Config Lcd = 16 * 2 'LCD größe
Config Lcdpin = Pin , Db4 = Portd.5 , Db5 = Portd.6 , Db6 = Portd.7 , Db7 = Portb.0 , Rs = Portb.6 , E = Portb.7
Cursor Off Noblink

'-------------------------------------------------------------------------------
'Alias
Taster1 Alias Pinb.1
Taster2 Alias Pinb.2
Taster3 Alias Pinb.3



'-------------------------------------------------------------------------------
'Variablen
Dim Test1 As Integer
Dim Test2 As Integer

Dim Wert1 As Integer
Dim Wert2 As Integer


'--
Dim Slave As String * 3 , Para As String * 10 , Wert As String * 4 , Parameter As Integer
Dim E_byte As Byte , E_flag As Byte

'-------------------------------------------------------------------------------
'Timer
'Timer1 = 2x / sec bei 8MHz
Config Timer1 = Timer , Prescale = 256 'Teiler
Const Timervorgabe = 49910
Enable Timer1
Enable Interrupts
On Timer1 Lcd 'timer einschalten


'-------------------------------------------------------------------------------
'Für RS232:
On Urxc Onrxd 'Interrupt-Routine setzen
Enable Urxc 'Interrupt URXC einschalten
Enable Interrupts 'Interrupts global zulassen
'-------------------------------------------------------------------------------

Main: 'Hauptschleife

'analogeingang auslesen und in Variable Wert1 schreiben

'IRGENDETWAS MACHEN:
Incr Test1
If Test1 = 65000 Then
Toggle Portc.0 'LCD Beleuchtung
Incr Test2
Test1 = 0
End If

'--
If E_flag = 4 Then 'Empfangsstring komplett
Parameter = Val(para) 'aus String Integer machen
Cls
Locate 2 , 1
Lcd Slave ; "," ; Parameter ; ":" ; Wert 'LCD
Waitms 200
Slave = "" 'Slave löschen
Para = "" 'Parameter löschen
Wert = "" 'Wert löschen
E_flag = 0 'Empfang neu setzen
End If

Goto Main

'-------------------------------------------------------------------------------
Onrxd:
E_byte = Udr
Select Case E_byte
Case 35 : E_flag = 1 '"#" = Slave wird gesendet
Case 44 : E_flag = 2 '"," = Parameter kommt
Case 58 : E_flag = 3 '":" =
Case 13 : E_flag = 4 '"ENTER" = Empfang komplett
Case Else : If E_flag = 1 Then Slave = Slave + Chr(e_byte)
If E_flag = 2 Then Para = Para + Chr(e_byte)
If E_flag = 3 Then Wert = Wert + Chr(e_byte)

End Select






Return


'-------------------------------------------------------------------------------
'Timer0zähler:
'Timer1 = 49910
'Incr Timer0_60
'
'If Timer0_60 > 30 Then
'Timer0_60 = 0
'Gosub Lcd 'und später das Programm hier fortführen!
'Toggle Portc.0
'End If
'Return



'-------------------------------------------------------------------------------
Lcd:
Timer1 = 49910
'Cls 'Display löschen (IMMER ERST LCD LÖSCHEN UND DANN POSITION ANGEBEN!!!)
Locate 1 , 1
Lcd "Test2: " ; Test2
'Locate 2 , 1
'Lcd + Str(timer0_60)
Return




Tobias

@python_rocks:
benötige ich für RS485 wirklich nur das IC und den Pin der den MAX485 in den Sendemodus schaltet? Das wäre ja "einfach" ;-)

TobiasBlome
25.03.2009, 19:14
oh - ich muss mich korregieren
manchmal steht es auch richtig im LCD...

S1,Strom:1234

aber das ist sehr selten der Fall.....

TobiasBlome
25.03.2009, 20:29
oh oh oh...... :-b

das kommt davon wenn man andere codeschnipsel kopiert.....

Das gehört hier doch gar nicht hin: Parameter = Val(para)

und nun läuft das Programm \:D/

nun kann ich weiter programmieren


Tobias

python_rocks
25.03.2009, 20:35
@python_rocks:
benötige ich für RS485 wirklich nur das IC und den Pin der den MAX485 in den Sendemodus schaltet? Das wäre ja "einfach" ;-)
Hallo Tobias!

Ja, so einfach ist das. :D

Allerdings solltest du in einem Interrupt-Handler nicht, niemals nicht, etwas auf dem LCD anzeigen.
Schreibe lieber das was anzuzeigen ist in eine Variable und zeige es in der Hauptschleife an, wenn genug Zeit dafür ist. Der LCD-Befehl dauert einfach zu lange, als dass man ihn in einem Interrupt-Handler verwenden kann. Du musst bedenken, dass während die Daten auf das LCD geschrieben werden, kein anderer Interrupt ausgeführt werden kann. Im schlimmsten Fall, verlierst du Daten beim Empfang über die UART, da diese schneller rein kommen als du sie abrufen kannst.

mfg
Gerold
:-)

TobiasBlome
25.03.2009, 20:41
z.b. so?

...
Do
if Merker = 1 then

Cls
Locate 1 , 1
Lcd "Hallo"
Merker=0

End If
...
'___________________
ontimer1:
Merker=1
Return

python_rocks
25.03.2009, 21:01
z.b. so?
ja, genau so :-)

TobiasBlome
27.03.2009, 21:15
Juhu, die Kommunikation läuft:
Der Master fragt etwas und bekommt vom Slave eine Antwort.

Wie kann man den "Empfangscode" noch etwas optimieren?



'auf Empfang reagieren:
If E_flag = 4 Then 'Empfangsstring komplett
If Slave = "S1" Then 'wenn Daten für Slave1

Select Case Parameter

Case "Strom" : Print "#S1,Strom:" ; Strom 'Messwert für Strom senden
Locate 1 , 1
Lcd "S..." ; Slave ; "," ; Parameter ; ":" ; Strom

Case "Volt" : Print "#S1,Volt:" ; Volt
Locate 1 , 1
Lcd "S..." ; Slave ; "," ; Parameter ; ":" ; Volt

Case Else : Print "Err."

End Select


End If

Slave = "" 'Slave löschen
Parameter = "" 'Parameter löschen
Wert = "" 'Wert löschen
E_flag = 0 'Empfang neu setzen
End If