Forum: Mikrocontroller und Digitale Elektronik Toggle Funktion AVR


von Phillip H. (philharmony)


Lesenswert?

Ich muß um verschiedene register anzusteuern öfters eine high->low oder 
low->high Flanke auslösen.
Dazu habe ich verschiedene bit_operationen selbst geschrieben (der 
Übersicht halber) und unter anderem eine toggle-funktion.
1
//bestimmtes bit aus einem byte lesen
2
unsigned char get_bit(unsigned char byte, unsigned char bit)
3
{
4
unsigned char result; 
5
result = (byte >> bit);
6
result = (result & 0x01);
7
return result;
8
}
9
10
11
//bestimmtes bit in einem byte setzen oder löschen
12
unsigned char set_bit(unsigned char byte, unsigned char bit, unsigned char state)
13
{
14
unsigned char result;
15
if (state == 0) result = (byte & ~(1 << bit)); else result = (byte | (1 << bit));
16
return result;
17
}

Diese benutze ich nun auch in der Toggle_Funktion:
1
//auf ab togglen
2
void toggle_bit_up_down(unsigned char byte, unsigned char bit)
3
{byte = set_bit(byte, bit, 1);
4
byte = set_bit(byte, bit, 0);
5
}
6
*/
7
8
//ab auf togglen
9
void toggle_bit_down_up(unsigned char byte, unsigned char bit)
10
{byte = set_bit(byte, bit, 0);
11
byte = set_bit(byte, bit, 1);
12
}
13
*/

Wenn ich die Funktionen allerdings im Program benutzen möchte, dann 
funktioniert diese allerdings nicht.
Also
1
toggle_bit_up_down(port_control, pin_clk);

Funktionert nicht.
Wenn ich das ganze mit
1
port_control = set_bit(port_control, pin_clk, 1);
2
port_control = set_bit(port_control, pin_clk, 0);
dann geht es.
Weiß jemand wieso?
Grüße
Phil

von NurEinGast (Gast)


Lesenswert?

Ich würde mal sagen mit der Zuweisung

   byte = set_bit(byte, bit, 1);

im toggle_bit_up_down überschreibst Du dir Deine Eingangsvariable 
"byte", die Du in der nächsten Zeile aber wieder verwenden willst.

Gruss

von Stefan E. (sternst)


Lesenswert?

Was erwartest du denn, was toggle_bit_up_down tun soll?
Es hat keinen Rückgabewert und auch der ursprünglich übergebene Wert 
wird nicht verändert.

von Peter D. (peda)


Lesenswert?

Phillip Hommel wrote:
> Wenn ich die Funktionen allerdings im Program benutzen möchte, dann
> funktioniert diese allerdings nicht.

Du übergibst die Kopie der Variable "byte", machst damit etwas und 
schmeißt das Ergebnis weg.
Daher ist der Compiler so schlau, es komplett wegzuoptimieren.
Aber selbst wenn er es macht, bewirkt es nicht das von Dir Gewünschte, 
sondern verbraucht nur Zeit.
Gehen würde es nur mit Pointern auf volatile.
Dabei wird der Code aber sehr aufwendig.


Hier mal ein Tutorial, wie man Bits übersichtlich definiert und 
verwendet:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=67368

Das hat außerdem den Vorteil, daß der Code effizient ist, d.h. die 
Bitbefehle benutzt.
Das Rumgewusele mit Pointern auf IO-Ports kostet dagegen mächtig Code 
und Zeit.


Peter

von (prx) A. K. (prx)


Lesenswert?

Geht so nicht. Denn in der toggle-Funktion wird nicht der Port 
getoggelt, sondern nur die lokale Variable.

Dü müsstest dazu die Adresse des Ports and die toggle-Funktion 
übergeben, nicht dessen Inhalt. Ist aber umständlich.

Tip nebenbei: Shifts deren Anzahl dem Compiler nicht bekannt sind werden 
bei AVRs recht ineffizient implementiert. Was hier solange kein Problem 
ist, bis der Compiler meinst, für übliche inlining wären die Funktionen 
zu gross.

von Phillip H. (philharmony)


Lesenswert?

Die funktion hat ja auch keinen Rückgabewert sondern soll in sich den 
übergebenen wert (der mit #define direkt dem port und pin enspricht) 
zweimal die funktion set_bit ausführen die ja direkt aufgerufen auch 
funktioniert.
ich fasse in toggle eigentlich ja nur zwei zeilen zusammen.

von Stefan E. (sternst)


Lesenswert?

Du willst also direkt den Pin am Port toggeln, und nicht nur ein Bit in 
einem Datenbyte?
Dann musst du einen Pointer auf den Port übergeben.
Und du musst daran denken, die Interrupts währenddessen zu sperren.

von Peter D. (peda)


Lesenswert?

Phillip Hommel wrote:
> Die funktion hat ja auch keinen Rückgabewert

Und genau das ist der Unterschied, daß sie nicht das tut, was Du gerne 
hättest.
Sie tut natürlich genau das, was Du hingeschrieben hast.


> ich fasse in toggle eigentlich ja nur zwei zeilen zusammen.

Nein, tust Du nicht.
Es ist ein großer Unterschied, ob Du einen Returnwert einer globalen 
Variable oder einer lokalen zuweist.
Die lokale ist nach dem Verlassen der Funktion ungültig und damit die 
Zuweisung ohne Effekt.
Und deshalb passiert auch nichts mit dem Port, ihm wurde ja nichts 
zugewiesen.


Peter

von Phillip H. (philharmony)


Lesenswert?

Aaaaah ok, jetzt raff ich das.
Ich übergebe der funktion den WERT des ports, der wurschtelt damit was 
und speichert es aber nirgends?
Dh ich müßte das ganze wieder mit rückgabewert machen im sinne von
1
port_control = toggle_blabla
was aber keinen sinn macht da ich ja hoch- und wieder runter-togglen 
will.
Dh die beste methode ist, zweimal set_bit auszuführen, einmal mit 1 und 
einmal mit 0.
Vielen dank

von Peter (Gast)


Lesenswert?

Mit Macros müsst es bequem gehen....

Zum Beispiel so:

1
#define SB(byte,bit) byte |= (1<<bit)
2
#define CB(byte,bit) byte &= ~(1<<bit)
3
#define TOGGLE_BIT_UP_DN(byte,bit) do{SB(byte,bit);CB(byte,bit)}while(0)
4
#define TOGGLE_BIT_DN_UP(byte,bit) do{CB(byte,bit);SB(byte,bit)}while(0)
5
 .
6
 .
7
 .
8
 TOGGLE_BIT_UP_DN(port_control, pin_clk);

von (prx) A. K. (prx)


Lesenswert?

Wobei mehr Klammern nicht schaden würden, um sich vor unerwünschten 
Priorätiten zu schützen:
  #define SB(byte,bit) byte |= (1<<(bit))

von Peter (Gast)


Lesenswert?

Die Macros sind in diesem Fall erst noch viel effizienter und schneller 
als Funktionsaufrufe. Falls die "bit"-Werte Konstanten sind, wird 
nämmlich der C-Präprozessor des Compilers die Shift-operationen 
erledigen und die CPU hat zu Runtime nichts mehr damit zu tun.

von Peter (Gast)


Lesenswert?

Ohja, die Klammern hab ich vergessen, die wären tastächlich sehr zu 
empfehlen!

von Peter (Gast)


Lesenswert?

...und es fehlt auch noch ein [;]

also...
1
#define SB(byte,bit) byte |= (1<<(bit))
2
#define CB(byte,bit) byte &= ~(1<<(bit))
3
#define TOGGLE_BIT_UP_DN(byte,bit) do{SB(byte,bit);CB(byte,bit);}while(0)
4
#define TOGGLE_BIT_DN_UP(byte,bit) do{CB(byte,bit);SB(byte,bit);}while(0)
5
 .
6
 .
7
 .
8
 TOGGLE_BIT_UP_DN(port_control, pin_clk);

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.