Port und Pin an Funktion übergeben

Das Thema ist nicht neu, hierzu gibt es auch bereits einen Beitrag, den ich durgelesen habe, der mir aber nicht weiterhilft.

Zum Thema:

für einen Standalone ATmega328P mit internem Takt versuche ich gerade die Software zu schreiben. Dabei werden u. a. bistabile Relais über Ausgangspin per kurzem Pulse angesteuert. Da ich auch die Pins PB6 und PB7 verwende, die bei UNO für den Quarz vorgesehen und denen zumindest in der IDE-Umgebung keinen Pin-Nummern zugeordnet sind, will ich die Ausgänge direkt über die Ports B, C und D steuern. Soweit erst einmal kein Problem.

Mein Problem taucht bei der Übergabe des Ports und der zugehörigen Pin-Nr. an eine Funktion auf in der ich den entsprechen Pin für eine gewisse Zeit setze (z. B. 500 ms), um die Spule eines bistabilen Relais anzusteuern. Hierzu habe ich eine einfache Funktion pulse_Relais, in die ich den Port, die Pin-Nr. und die Pulse-Dauer übergebe.

Den Port gebe ich als Zeiger auf das entsprechende Register an. In der Funktion habe ich testhalber eine Maske gesetzt die ich auf den Port anwende. Später soll das entsprechende Bit über eine Portmanipulation gesetzt und nach der Pulsdauer auch wieder gelöscht werden. Aus mir nicht verständlichen Gründen funktioniert das nicht so wie ich mir das vorstelle.

Mein kleines Testprogramm:

#include <inttypes.h>
#include <avr/io.h>

#define t_pulse       1000     // Zeit in ms für Anregung Relaisspule

// -------------------------------- setup --------------------------------------
// Setup routine with pre definitions
// -----------------------------------------------------------------------------
void setup() 
{

  // Definition der Data-Direction-Register, 0 = Input, 1 = output
  DDRB = DDRB | B11000100;  // PB0 - nicht benutzt
                            // PB1 - nicht benutzt
                            // PB2 - nicht benutzt
                            // PB3 - nicht benutzt
                            // PB4 - nicht benutzt
                            // PB5 - nicht benutzt
                            // PB6 - Relais K3, Spule 1, ABC Gleis 1 und Gleis 2 zusammen, ABC1 a. B. 
                            // PB7 - Ausgang BLM Gleis 1, Bremsbschnitt, 0 = belegt, 1 = frei

  DDRC = DDRC | B00000000;  // PC0 - nicht benutzt
                            // PC1 - nicht benutzt
                            // PC2 - Eingang BLM Gleis 1, Fahrabschnitt, 0 = belegt, 1 = frei
                            // PC3 - Eingang BLM Gleis 1, Bremsbschnitt, 0 = belegt, 1 = frei
                            // PC4 - Eingang BLM Gleis 2, Fahrabschnitt, 0 = belegt, 1 = frei
                            // PC5 - Eingang BLM Gleis 21, Bremsbschnitt, 0 = belegt, 1 = frei

  PORTC = B10000001;
                            

//  DDRD = DDRD | B00111111;  // PD0 - Relais K1, Spule 2, ABC Gleis 1 = on 
  DDRD = DDRD | B11111110;  // PD0 - Relais K1, Spule 2, ABC Gleis 1 = on 
                            // PD1 - Relais K1, Spule 1, ABC Gleis 1 = off
                            // PD2 - Relais K2, Spule 2, ABC Gleis 2 = on
                            // PD3 - Relais K2, Spule 1, ABC Gleis 2 = off
                            // PD4 - Relais K3, Spule 2, ABC Gleis 1 und Gleis 2 getrennt
                            // PD5 - Ausgang BLM Gleis 2, Bremsbschnitt, 0 = belegt, 1 = frei
                            // PD6 - Eingabe Zuglänge, 0 = kurze Züge, 1 = langer Zug
                            // PD7 - Freigabe Ausfahrtsignal 0 = HP0, 1 = HP1


  Serial.begin(57600);

}


// ---------------------------- loop -----------------------------------------
// -----------------------------------------------------------------------------
void loop() 
{

  // Beispiel Funktionsaufruf pulse, Übergabe PORTx, PINy, Pulsedauer
  PORTD |= B00000000;
  pulse_Relais(PORTB, PB4, t_pulse);
  delay (1000);          

}

// ------------- pulse (uint8_t pin, long duration) -------------------
// Puls mit Dauer duration in ms an Ausgang pin L->H->L 
// dient zur Pulsansteuerung des bistabilen Relais           
// --------------------------------------------------------------------
void pulse_Relais (volatile uint8_t *port, uint8_t pin, long duration)
{
      uint8_t mask;

     mask |= B00100000;
     Serial.print("Maske: ");Serial.print(mask, DEC); Serial.print(" ");Serial.println(mask, BIN);  

      *port |= mask;
     Serial.print("Port: ");Serial.print(*port, DEC); Serial.print(" ");Serial.println(*port, BIN);  


}

Gebe ich die Werte in der Funktion aus, so hat das absolut nichts mit dem zu tun was ich eigentlich beabsichtige:

Maske: 32 100000
Port: 255 11111111

Was mache ich falsch?

Grüße Thomas

Sie sollten versuchen, anstelle des Registerwerts dessen Adresse zu übergeben. Schreiben Sie also pulse_Relais(&PORTB, PB4, t_pulse), damit die Funktion tatsächlich einen Zeiger auf den Port erhält. Außerdem sollten Sie versuchen, die Variable mask korrekt zu initialisieren, um undefiniertes Verhalten zu vermeiden. Schreiben Sie dafür uint8_t mask = (1 << pin);. Die angepasste Funktion wäre:

void pulse_Relais(volatile uint8_t *port, uint8_t pin, long duration) {
  uint8_t mask = (1 << pin);
  *port |= mask;
  delay(duration);
  *port &= ~mask;
}

Danke, das hatte ich ursprünglich auch gemacht. Bei den zahlreichen Änderungen flog das wieder unbemerkt raus. Das war hier jetzt ein Fehler. Ich ändere es und probiere es auch.

Ja jetzt geht es. Auch mit setzen und löschen einzelner bits.

Ein wirklich dummer Fehler den Adressoperator nicht anzugeben.

Jetzt schalte ich das ganze mal scharf und teste das auch mit meiner Schaltung, ob der tatsächlich auch die richtigen Pins ansteuert.

Yippie yeah, es funktioniert.

Thema geklärt.

Danke nochmal.

Freut mich, dass ich das lösen konnte!

Es ist eigentlich üblich, den Beitrag als Lösung zu markieren, der am Besten zu selbiger beigetragen hat. Das wäre also Post #2 - du solltest erwägen, das Häkchen umzusetzen.

Das ist ja normal bei @tm57.

Das ist mittlerweile - Ausnahmen gibt es - zum Normal geworden.
Grad mal durch gescrollt. Die letzten 16 Tage ist ein gelöster bei, der nicht durch den TO gelöst ist - und das ist ausgerechnet meine Lösung, aber die ist auch schon aus dem April und der Thread ist nur weiter geführt...
Von mir aus kann das sowieso weg.
Da sind soviele gelöste bei, die nicht markiert sind. Da machen die drei markierten den Kohl auch nicht fett.