Forum: Mikrocontroller und Digitale Elektronik Funktion mit Makro "verbiegen"


von Stefan S. (sschultewolter)


Lesenswert?

Hallo,

da ich im Netz keine ordentliche Libary zu dem MCP23S17 für avr gcc 
gefunden habe, bin ich dabei, das ganze Anhand des Datenblattes 
anzufertigen.

Derzeit habe ich jedoch lediglich die Konfiguration der Register sowie 
Ausgänge getestet. Nun stellt sich aber eine Frage zum "verbiegen" einer 
Funktion mittels Makro.

Was ich gerne hätte, wäre etwas wie dieses
1
MCP_PORT0 |= 1<<bit;


Ich habe vorerst ein Array in der C-File der Lib abgelegt (uint8_t 
mcp[16]). Diese kann über ein Makro direkt angesprochen werden
1
#define MCP23S17_PORT0    mcp[0]

Nun wird das ganze in der main wie folgt aufgerufen
1
MCP23S17_PORT0 = 1<<ct;

Dieser Teil ist schon einmal so, ich mir das wünsche. Ich hätte aber 
gerne die Möglichtkeit, dass sich diese "Ports" wie die in avr-gcc 
verhalten. Soll heißen, die Wertesollen wenn möglich auch direkt 
rausgeschiftet werden.

Wie kann ich das machen, ohne eine Funktion zu verwenden!?

Derzeit verwende ich noch
mcp23s17_write_hwaddr(uint8_t hwaddr, uint8_t reg, uint8_t data);
hwaddr = Jumpereinstellung A0 - A2
reg = GPIOA/GPIOB
data = Inhalb von mcp[]

von Klaus (Gast)


Lesenswert?

Das geht leider nicht so, wie Du das möchtest.

Technisch gesehen handelt es sich darum, ob ein L-Wert (siehe ein 
C-Buch) eine Speicher- bzw. memory-mapped-IO-Adresse identifiziert - in 
die könnte einfach geschrieben werden -, oder ob ein komplexer Ablauf - 
hier also die Bedienung des SPI-Interface des IO-Expanders -, ausgelöst 
und kontrolliert werden muss.

Der einfach(st)e Fall ist eben der des memory-mapped-IO. So ist das 
Front-End des GCC geschrieben.
Das nun ein SPI-Peripheriegerät am Bus hängt und das wiederum etwas 
nachbildet, dass wie ein L-Wert behandelt werden kann, weiss der GCC 
nicht und es ist auch keine Möglichkeit vorgesehen ihm das bekannt zu 
machen.

von Klaus (Gast)


Lesenswert?

Ich meinte das GCC-Backend.

Wie auch immer: Es stecken mehr oder weniger implizite Annahmen über die 
Maschine in so einem Compiler.

von Stephan (Gast)


Lesenswert?

Stefan S. schrieb:
> Wie kann ich das machen, ohne eine Funktion zu verwenden!?

Wie Klaus schon sagte, geht das nicht.
Aber im Grunde wolltest du den Aufruf der Funktion ja nur verstecken, da 
wäre die Funktion ja.(nur von dir nicht geschrieben)

Was erhoffst du dir denn davon?

Es gibt ja noch andere Ansätze...

Einmal kannst du es ja so machen wie die SPS-Maschinen, zu Beginn der 
Main-Loop liest du die Inputs ein und am Ende der Main-Loop schreibst du 
die Ausgänge.

Aber leider...
>Soll heißen, die Wertesollen wenn möglich auch direkt rausgeschiftet werden.

Dann kannst du den Aufruf ja noch im Macro selbst verbergen..
1
#define MCP23S17_PORT0(val) mcp23s17_write_hwaddr(hwaddr, outreg, (val))
2
#define MCP23S17_PIN0()     mcp23s17_read_hwaddr(hwaddr, inreg)

von Stefan S. (sschultewolter)


Lesenswert?

Eine andere Möglichkeit wäre es, wenn ich mittels Interrupt, oder in der 
while Schleife nach einer bestimmten Zeit alle Werte der Ports 
vergleiche und dann nur rausschicke, wenn sich etwas geändert hat.

Das mag dann zwar fast so aussehen wie die ich mir das gewünscht hab, 
ist aber dann dort in meinen Augen nicht wirklich effizient.

von Ulrich F. (Gast)


Lesenswert?

Stefan S. schrieb:
> Eine andere Möglichkeit wäre es, wenn ich mittels Interrupt, oder in der
> while Schleife nach einer bestimmten Zeit alle Werte der Ports
> vergleiche und dann nur rausschicke, wenn sich etwas geändert hat.

Nee...

Stephan schrieb:
> Einmal kannst du es ja so machen wie die SPS-Maschinen, zu Beginn der
> Main-Loop liest du die Inputs ein und am Ende der Main-Loop schreibst du
> die Ausgänge.
Das halte ich für den besseren Weg.
Die SPS Hersteller sind ja nicht nur doof....
Ein seit Jahrzehnten bewährter Weg.

Stefan S. schrieb:
> ist aber dann dort in meinen Augen nicht wirklich effizient.
Wie effizient muss es denn sein?

von Stefan S. (sschultewolter)


Lesenswert?

Hallo combie,

mir sind die SPS-Systeme Bernecker&Rainer, Siemens und teilweise auch 
Möller/EATON aus dem Arbeitsalltag bekannt.

Das EVA-Prinzip ist bekannt.

Bei meiner Idee handelt es sich letzen Endes ebenfalls um das 
EVA-Prinzip mit einer kleinen Änderung.

E - irgendwelche Sensorik, Taster etc wird eingelesen (derzeit noch 
nicht mit dem MCP)
V - Bestimmte Werte im Array werden geändert oder auch nicht, je nach E.
A - Ausgabe auf die Register erfolgt nur bei einer Änderung.

Die Ausgabe erfolgt nur an die MCPs, bei denen eine Änderung erfolgte. 
Andere werden ausgelassen.

Ich will dahin hinaus, dass der komplette Code nicht blockierend wird.
Da gehören dann auch Sachen wie Display etc dazu, dass sollte aber nicht 
das Problem sein.

Ich hatte nur gehofft, dass es möglich wäre, es ähnlich wie mit der 
Portmanipulation im AVR zu machen.

Könnte aber so vermutlich gelöst werden
1
while(1)
2
{
3
// Werte laden
4
5
// Werte verarbeiten
6
MCP |= 1<<bit;
7
8
// Werte ausgeben
9
update();
10
}

Wobei update dann die Werte mit denen aus der vorherigen Runde 
vergleicht. Kommt es zu Unstimmigkeiten, wird der Wert gesendet.

von Stephan (Gast)


Lesenswert?

Stefan S. schrieb:
> Ich will dahin hinaus, dass der komplette Code nicht blockierend wird.

das ist doch gut. :-D

Da geht das EVA Prinzip aber nicht.
hier brachst du was anderes, entweder eine X-Count Loop, oder über eine 
Zeit-Basis(<- besser, glaub ich)

Wenn du mit den StateMaschines Hilfe brauchst, sag bescheid, wir 
unterstützen dich. :-P

von Bernd K. (prof7bit)


Lesenswert?

Stefan S. schrieb:
> Ich will dahin hinaus, dass der komplette Code nicht blockierend wird.
> Da gehören dann auch Sachen wie Display etc dazu, dass sollte aber nicht
> das Problem sein.

Also ich mache das immer so daß ich am Anfang genau überlege welche der 
Aufgaben zwingend ein deterministisches Timing erfordern bzw diese in 
ihrer Priorität zu ordnen. Dabei kommt dann raus dass es etliche Sachen 
gibt (die meisten bis auf ein oder 2) die dies ganz und gar nicht 
erfordern und dazu gehören dann so Sachen wie LCD-Displays die ein 
beknacktes Delay nach jedem Befehl brauchen oder Bitbanging-I²C master 
und all das kann man ganz pragmatisch blockieren lassen und sequentiell 
abarbeiten bevor man sich für nichts und wieder nichts einen Wolf 
programmiert, in der main hat man alle Zeit der Welt (sobald man die 
wirklich wichtigen Sachen daraus entfernt hat).

z.B:

Höchste: ADC anstossen (kann Timer-Hardware triggern)
Höchste: ADC auslesen und Werte wegschreiben (Interrupt, Prio 0)
Zweithöchste: Eingehende Bus-Pakete zur Kenntnis nehmen, keines 
verschlucken (Interrupt, Prio 1)
Niedrige: (main) bei Gelegenheit mal neues Messergebnis ausrechnen
Niedrige: (main) bei Gelegenheit mal das fällige Antwortpaket 
losschicken
Niedrige: (main) bei Gelegenheit mal das Display updaten
Niedrige: (main) Andere Sachen die kurz blockieren
Niedrige: (main) Schlafen

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.