Hallo,
ich bin gerade dabei eine Digital Steuerung für die MoBa zu
entwickeln....
Dafür muss ich aus einem einprogrammierten Wert (0 - 127) eine Funktion
im AVR machen. Also zum Beispiel:
Funktionswert = 23: dann soll der Port als Ausgang geschalten werden,
bei einem entsprechenden Befehl von der Digi-Zentrale soll dann über
diesen Port eine LED eingeschaltet werden, bei einem anderen Befehl die
LED ausgeschaltet werden. (wie ein Toggle Flip-Flop)
Funktionswert = 71: dann soll der Port als Ausgang geschalten werden,
Fu. wie oben, aber die LED soll Blinken (frequenz erst mal egal)
Funktionswert = 45: dann soll der Port als Eingang geschaltet werden,
wenn eine Taste gedrückt wurde, soll eine Message an die Zentrale
geschickt werden, wird diese noch einmal gedrückt wird eine andere
Nachricht versendet.
Funktionswert = 37: dann soll der Port als Eingang geschaltet werden,
wenn eine Taste gedrückt wurde, soll eine Message an die Zentrale
geschickt werden, wird dieser losgelassen wird eine andere Nachricht
versendet.
Von den I/O Ports hab ich insgesammt 16 Stk. also diese
Funktionssubroutine muss für alle Ports benutzbar sein. z.B:
Port1 = Funktion 23 >> Subroutine
Port2 = Funktion 71 >> Subroutine
...
Port15 = Funktion 45 >> Subroutine
Port16 = Funktion 37 >> Subroutine
Wie muss nun diese Subroutine (Funktion) aussehen?
Programmiersprache ist erst mal egal, mir geht es nur um ein möglichst
detailiertes Funktionsprinzip.
Also ich hoffe ihr versteht das Problem in etwa und könnt mir da ein
wenig helfen.
Vielen Dank und LG
Sven
16ports, hm meinst du 16 einzelne IO/s oder wirklih 16*8Bit ports ?
im prinzip ist sowas einfach..du hast 4 verschiedene funktionen 0...3
(ja gleich richtig nummerieren..) und baust dir 4 verschiedene routinen
und ein globales array in dem du die aktuelle funktion des ports
speicherst, das wars eigentlich schon.
im main loop hast du ne for-schleife, gehst damit dein array durch und
je nachdem welche funktion konfiguriert ist wird diese ausgeführt.
blinken, pin polling solltest du aber über timer machen, das empfangen
von daten über eine ISR
Naja, ganz so einfach ist es nicht.
Was er als "Funktion" bezeichnet, ist nicht unbedingt eine C-Funktion.
Zuerst müsste mal klar sein, welche "Funktionen" es alles geben muß.
Das ist offenbar:
- an als Ausgang
- aus als Ausgang
- Eingang
- blinken
- ... ?
Dann muß er sich eine sinnvolle Struktur überlegen, wie man die
ganzen Zustände für alle Ports abbilden kann (Feld von enums?).
Dann braucht es ein Programm drumrum, das diesen Zustand realisiert
und auf die Kommandos von außen (wie sollen die denn reinkommen?)
hin die Zustände ändert.
Soweit ich das verstanden habe...
Es hört sich etwas unausgegoren an.
Hallo,
erst mal danke für die Antworten. Das ganze Programm soll auf einem
Mega88 laufen, der Datenempfang/versand wird Interruptgesteuert über den
Uart gemacht. Es hat mit RS232 nichts zu tun... es ist ein Protokoll von
einem Digital-Hersteller (Digitr..), es funktioniert nur Halbduplex
usw....
@ Andi D. : es sind wirklich nur 16 I/O Ports.
Vom Port D nutze ich die Pins 4 - 7, vom Port C die Pins 0 - 5 und vom
Port B ebenfalls die Pins 0 - 5
@Klaus Wachtler: nein, neben den angegebenen Funktionen sind es noch ein
Paar mehr. Oben die Liste dient nur als Beispiel.
@ Mat : so in etwa dachte ich es mir auch schon, aber es ist sehr
Speicherfressend (hab es schon mal kurz probiert). Wir brauchen in etwa
33 verschiedene Funktionen. Gibt es dafür nicht eine einfachere Methode?
Ich hab mal die Funktionsliste angehängt... so in etwa stell ich es mir
vor..
LG
Sven
Sven schrieb:> erst mal danke für die Antworten. Das ganze Programm soll auf einem> Mega88 laufen, der Datenempfang/versand wird Interruptgesteuert über den> Uart gemacht. Es hat mit RS232 nichts zu tun... es ist ein Protokoll von> einem Digital-Hersteller (Digitr..), es funktioniert nur Halbduplex> usw....
OK
> @ Andi D. : es sind wirklich nur 16 I/O Ports.> Vom Port D nutze ich die Pins 4 - 7, vom Port C die Pins 0 - 5 und vom> Port B ebenfalls die Pins 0 - 5
Bitte benutze die richtige Nomenklatur.
Du sprichst von Port-'Pins'.
Ein Port im µC-Sprachgebrauch ist eine 'Geräteeinheit', die 8 Pins zur
Verfügung stellt.
du benutzt also 3 unterschiedliche Ports, mit zusammen 16 benutzten
Pins.
> @ Mat : so in etwa dachte ich es mir auch schon, aber es ist sehr> Speicherfressend (hab es schon mal kurz probiert). Wir brauchen in etwa> 33 verschiedene Funktionen. Gibt es dafür nicht eine einfachere Methode?
Die Methode von Mat ist nicht so clever.
Cleverer ist es, wenn du dir eine Tabelle mit Funktionspointern
aufbaust, wobei jeder Pointer auf eine Funktion zeigt, die die
gewünschte Funktionalität implementiert (oder aber ein großer
switch/case über alle Funktionsnummern, der dann die jeweilige Funktion
aufruft)
Dazu noch eine Tabelle, mit welcher du eine 'vituelle Pin-Nummer' (so
wie sie über die Schnittstelle übertragen wird) in reale
DDR/PORT/PIN/BIT Bezeichnungen ummappen kannst.
Alles in allem: in C nicht so schwer zu realisieren, wenn man sein
Handwerk versteht. Allerdings auch nichts für Anfänger.
>Alles in allem: in C nicht so schwer zu realisieren, wenn man sein>Handwerk versteht. Allerdings auch nichts für Anfänger.
@ Karl Heinz: nun hast du "A" gesagt nun musst du auch "B"
sagen(schreiben)
kannst du mir dafür einen kurzen Pseudo Code schreiben? Ein richtiger
Anfänger bin ich keiner mehr ;-)
LG, Sven
Sven schrieb:> kannst du mir dafür einen kurzen Pseudo Code schreiben?
Wenn ich dir dafür Pseudo-Code schreibe, kann ich dir auch gleich C Code
geben. Ist für mich einfacher.
Aber seis drum
1
globale Tabelle der Funktionspointer
2
3
Hauptprogramm:
4
5
mache für immer
6
hole die Funktionsnummer
7
ist die Funktionsnummer gültig?
8
ja: hole aus der Tabelle den Funktionspointer wobei du
9
die Funktionsnummer als Index benutzt
10
rufe die Funktion indirekt über den Funktionspointer auf
ist dir jetzt geholfen? :-)
> Ein richtiger> Anfänger bin ich keiner mehr ;-)
Na ja
Das was du vorhast, ist reine Tabellenarbeit (*). OK. Funktionspointer
muss man sich einmal ansehen. aber auch die sind halb so wild. Wenn du
dafür eine Idee brauchst, überschätzt du dein Kentnisse ein wenig :-)
(**)
(*) und natürlich: Arbeiten mit Pointern
(**) was ich speziellen sowieso glaube. Denn deine Beschreibungen sind
ein wenig .... konfus. Man kann zwar erraten was du meinst, aber wenn
man es genau nimmt, ist in dem was du im ersten Posting geschrieben hast
kaum ein Satz, der Sinn macht.
Mal eine andere Frage:
Wieviel Erfahrung hast du denn schon in der AVR-Programmierung?
Wenn ich dir den Auftrag gebe "Schalte den Pin 4 am Port C auf Ausgang
und schalte ihn auf 1" kriegst du das hin?
Wie sieht der Code aus?
1
intmain()
2
{
3
4
.....
5
}
Es geht mir nicht darum, dich da jetzt fertig zu machen. Ich will nur
wissen, ob du das Zusammenspiel der DDR/PORT/PIN Register und der Bits
kennst.
Noch eine Frage
> Funktionswert = 23: dann soll der Port als Ausgang geschalten> werden, bei einem entsprechenden Befehl von der Digi-Zentrale> soll dann über
In welcher Form kriegst du diese 'Portnummer'?
Ich geh davon aus, dass die Zentrale nichts darüber weiß und auch nicht
wissen soll, dass das auf dem AVR zb der PORTC und dort der Pin 0 ist.
Die Zentrale arbeitet einfach nur mit abstrakten, virtuellen Nummern.
Es sagt dem AVR: schalte den Anschluss 5 auf Ausgang, und der AVR muss
dann selbst wissen, dass das PORTC Pin0 ist.
Das kann man jetzt natürlich ganz klassisch ausprogrammieren
1
// Vom Port D nutze ich die Pins 4 - 7, vom Port C die Pins 0 - 5 und vom
2
// Port B ebenfalls die Pins 0 - 5
3
4
voidConfigureAsOutput(uint8_tConnectionNr)
5
{
6
uint8_tPinNr;
7
8
if(ConnectionNr<6){// handelt sich um den Port B
9
PinNr=ConnectionNr;// ConnectionNr: 0 bis 4
10
DDRB|=(1<<PinNr);
11
}
12
13
elseif(ConnectionNr<11){// muss am Port C sein
14
PinNr=ConnectionNr-5;// ConnectionNr: 5 bis 9
15
DDRC|=(1<<PinNr);
16
}
17
18
elseif(ConnectionNr<17){// muss am Port D sein
19
PinNr=ConnectionNr-10+4;// ConnectionNr: 10 bis 15
20
21
DDRD|=(1<<PinNr);
22
}
23
}
dasselbe für die Ausgabefunktion bzw. die restlichen Funktionen.
Für die Konfiguration auf Eingang müsste man noch Buch führen, welche
Pins auf Eingang sind und dann in der Hauptschleife diese Pins abfragen,
auf Veränderung auswerten und bei einer erkannten Veränderung die
entsprechende Message auf den Weg bringen.
@ Karl Heinz, dann ist das eben ein Sinnloses unterfangen. Gott sei
dank, kommen heute alle Menschen mit fundierten C-Kenntnissen zur Welt.
Aber dennoch danke für deine hilfe...
Ciao Sven
@ Karl Heinz, ich müsste dir dafür das ganze Loconet Prottokoll
erklären.
Die Daten vom LN kann ich empfangen, speichern und auswerten.... was mir
fehlt ist eben die Oben beschriebene Funktion.
und ja den Unterschied zwischen DDR Registern, Port und Pin kenne ich...
LG Sven
Sven schrieb:> @ Karl Heinz, ich müsste dir dafür das ganze Loconet Prottokoll> erklären.
musst du nicht.
Du musst nur sagen:
In diesen und jenen Variablen habe ich nach Empfang eines Datensatzes
diese Werte stehen (und das bedeuten sie)
> Die Daten vom LN kann ich empfangen, speichern und auswerten.... was mir> fehlt ist eben die Oben beschriebene Funktion.
Ich hab dir weiter oben eine ganz klassische Variante davon skizziert.
Ohne irgendwelche Tricks, ganz straight forward.
Sven schrieb:> Gott sei> dank, kommen heute alle Menschen mit fundierten C-Kenntnissen zur Welt.
Das nicht, aber früher (tm) war man bereit etwas zu lernen, auch wenn es
länger als 5 min dauert.
Karl heinz Buchegger schrieb:> Sven schrieb:>> @ Karl Heinz, ich müsste dir dafür das ganze Loconet Prottokoll>> erklären.>> musst du nicht.> Du musst nur sagen:> In diesen und jenen Variablen habe ich nach Empfang eines Datensatzes> diese Werte stehen (und das bedeuten sie)>>> Die Daten vom LN kann ich empfangen, speichern und auswerten.... was mir>> fehlt ist eben die Oben beschriebene Funktion.>> Ich hab dir weiter oben eine ganz klassische Variante davon skizziert.> Ohne irgendwelche Tricks, ganz straight forward.
Die beruht darauf, dass das Wissen über die Aufteilung in den Code
selber gebracht wird.
Eine andere Lösung wäre zb die hier
1
structconnectInfo{// definiert die Umsetzung der virtuellen
2
// Connect Nummern auf reale Ports
3
volatileuint8_t*ddrRegister;
4
volatileuint8_t*portRegister;
5
volatileuint8_t*pinRegister;
6
volatileuint8_tbitMask;
7
};
8
9
// und hier sind sie: die benutzen Pins in der richtigen Reihenfolge
10
//
11
// Vom Port D nutze ich die Pins 4 - 7, vom Port C die Pins 0 - 5 und vom
Das ist eine ein wenig ausgeklügeltere Variante, in der die komplette
Information, wie sich die virtuellen Anschluss Nummern auf die einzelnen
Port Bits verteilen, in einer Tabelle gesammelt werden.
Vorteil: das ist änderungsfreundlicher, wenn mal µC-Pins auf einen
anderen Port umziehen müssen. Und es erweitert sich auch besser auf noch
mehr Anschlussnummern. Die Anschlüsse können dann auch ganz einfach wild
verteilt am µC angeordnet werden.
Regelt alles die Tabelle.
Aber auch hier wieder:
Das erfordert noch immer keine fundierten Kentnisse, so leid mir das
auch für dich tut. Das ist reines Handwerk.
So, jetzt wieder ganz normal und friedlich...
Die Nachricht der Zentrale enthält 4 Bytes, daraus separiere ich die
Adresse für den Port und ein Controllbyte das mir dann sagt ob der Port
High oder Low schalten soll...
1.Byte = Opcode
2.Int = Adresse vom Port
3.Byte = Controllbyte
1 = 0xB0 > Port soll bei "Switchmeldung der Zentrale" und
2 = 0x4D2 > dieser Adresse
3 = 0x03 > den Port auf High schalten
3 = 0x01 > den Port auf Low schalten
Beim Datenversand mach ich es so, ich erechne aus der Adresse dem
Controllbyte und dem, der Funktion entsprechenden "OpCode" eine gültige
Nachricht...
1 = 0xB2 > Pin Meldet der Zentrale "belegtmeldung"
2 = 0x78 > Adresse ist
3 = 0x03 > Gleis ist frei
3 = 0x01 > Gleis ist besetzt
meinst du das so?
LG Sven
Sven schrieb:> Beim Datenversand mach ich es so, ich erechne aus der Adresse dem> Controllbyte und dem, der Funktion entsprechenden "OpCode" eine gültige> Nachricht...>> 1 = 0xB2 > Pin Meldet der Zentrale "belegtmeldung"> 2 = 0x78 > Adresse ist> 3 = 0x03 > Gleis ist frei> 3 = 0x01 > Gleis ist besetzt>> meinst du das so?
Das ist schonmal ein Anfang.
> 1.Byte = Opcode> 2.Int = Adresse vom Port> 3.Byte = Controllbyte
Die Adresse ist interessant.
Wie bildet sich die?
> 1 = 0xB0 > Port soll bei "Switchmeldung der Zentrale" und> 2 = 0x4D2 > dieser Adresse
Warum 0x4D2?
Kann man sagen, dass die Adressen der 'Ports' an einem µC aufsteigend
sind?
Jeder µC hat einen Startwert und alle 'Adressen' sind dann einfach nur
die nächsten 16 Nummern?
Karl heinz Buchegger schrieb:> Hab ich beim Tippen hier im Forum übersehen.
Du schüttelst hier immer in kürzester Zeit (fast) fehlerfreien
ausführlichsten (und lauffähigen!) Code aus dem Ärmel... wie machst Du
das? Schickst Du den Code vorher durch den AVR-gcc oder hat Andreas
speziell für Dich einen Syntax-Parser ins Forum eingebaut? ;-)
Die Frage war rhetorisch gemeint, ich bewundere immer wieder, wie weit
Du mit Deiner Hilfsbereitschaft gehst...
Karl heinz Buchegger schrieb:> Das ist eine ein wenig ausgeklügeltere Variante, in der die komplette> Information, wie sich die virtuellen Anschluss Nummern auf die einzelnen> Port Bits verteilen, in einer Tabelle gesammelt werden.
Anzumerken wäre noch, dass man sich diese ConnectionInfo natürlich noch
um weitere Informationen anreichern wird, die sich dann zur Laufzeit
ergeben. Ich denke da an ein Flag welches eine Aussage erlaubt, ob der
Pin auf Ausgang oder Eingang geschaltet ist; welchen Zustand er im
Moment hat (um Veränderungen feststellen zu können) etc.
Dieses Tabellenschema ist sehr universell und vor allen Dingen lassen
sich damit die Funktionen damit sehr universell schreiben.
Nachteil: Man verschenkt unter Umständen ein wenig Laufzeit (dürfte hier
aber keine Rolle spielen) und man braucht natürlich auch entsprechend
viel SRAM (aber auch das wird hier keine Rolle spielen)
@ Karl Heinz,
Die Adresse 1234 ist jetz mal frei erfunden... ich könnte auch 487
nehmen.
Jeder Port, von den 16 Ports, bekommt eine eigene Adresse 0 - 2047 auf
die er dann höhren soll, bzw unter welcher er dann Daten zur Zenrale
schickt. Das Controllbyte ist nun dazu da um den Port entsprechend
reagieren zu lassen( irgendetwas ein/ausschalten, blinken lassen...)
Das Programmieren der Port Adresse hab ich schon separat gelöst, die
Port Adresse ist zudem noch im EEprom hinterlegt ebenso wie der Port
Funktionswert ....
Die Adresse und das Controllbyte ist in der Ursprünglichen LN Message in
zwei Bytes (nur 0 - 127) hinterlegt, daraus separiere ich über
Schiebefunktionen die Adresse und das Controllbyte.
Zu dem Opcode Byte am anfang einer Message ist noch zu sagen:
Daten senden:
Wenn ich eine, am Port, angeschlossene Taste drücke soll das Opcode Byte
=0xB0 sein, wenn an dem Port ein Belegtmelder angeschlossen ist soll der
Opcode = 0xB2 sein...
So wie es in der "PortFunktion" eingestellt wurde!
Daten empfangen:
Wenn ich eine Message mit Opcode =0xB0 empfange soll die darin
enthaltene Adresse und Controllbyte separiert werden und der Port
entsprechend gesetzt werden (Blinken, An/aus...)
Ebenso wenn eine Message den opcode 0xB0 enthällt...
So wie es in der "PortFunktion" eingestellt wurde!
LG Sven
Ich hoffe doch. Ich werde mal alles durcharbeiten, ist doch etwas viel
auf's mal ;-)
Wenn ich dann noch fragen habe "klopf" ich wider an.
Nochmals vielen Dank an alle!!
Gruss Sven