[Erledigt] Flotte Pinabfrage und Ausgangspin schalten - Attiny13

Hallo Leute,

für eine ziemlich triviale Sache habe ich einen trivialen Aufbau mit trivialem Sketch gebaut :grin:

Es geht um eine Signalerkennung- und Aufbereitung.
Schalter ist aktiv-low, prellt und die Zeit soll erfasst werden zwischen dem Drücken und Loslassen. Sieht man im Bild hoffentlich was ich meine. Da wir über Zeiten > 1 Sekunde sprechen hab ich einfach per delay entprellt.

Flankenerfassung.JPG

Sketch dazu für den Tiny13:

const byte gate = 0;    //Pin 5
const byte switchPin = 1;  //Pin 6
boolean gateState = false;  //status gate signal

void setup()
{
  DDRB |=(1<<gate);    //Pin als Ausgang definieren
  PORTB &= (1<< gate);  //Pin LOW setzen
  DDRB &= ~(1<< switchPin);   //Pin als Eingang definieren
}

void loop()
{
  if ( !(PINB & (1<<PB1)) && gateState == false)  //input LOW

  {
    PORTB |= (1<< gate);  //Pin HIGH setzen
    delay(30);
    gateState = true;
  }

  if ( PINB & (1<<PB1) && gateState == true)  //input HIGH
  {

    PORTB &= ~(1<< gate);  //Pin LOW setzen
    delay(30);
    gateState = false;
  }
}

Funktioniert, ABER: schaue ich mir die Verzögerung zwischen dem Eingangssignal und dem Gatesignal an, dann habe ich Verschiebungen der Flanken von 10 µs bis ca. 100 µs. Und das kann ich mir nicht erklären.

Wer hat eine Idee?

Ach ja, die Hardware: Attiny13 mit 9,6 MHz intern, Reset per 10 k an +5 V, Abblock- und Stützkondensator dran, Eingang mit ext. Pullup.

Hallo,

nimm mal statt setup / loop

int main(void)           // setup
{

  while(1)              // loop
  {

  {

}

Vielleicht gibt es einen Unterschied, vielleicht auch nicht.

Schreib doch mal ein einfaches Programm, das bei jedem Durchlauf von loop() einen Ausgangspin umschaltet. Dann bekommst Du die minimal mögliche Verzögerungszeit. Dann packe Deinen Code dazu, und vergleiche die Zeiten, dann hast Du den Einfluß Deines Codes auf die Reaktionsgeschwindigkeit. Das dürfte IMO die 10µs erklären. Dann kommt noch die Abarbeitung von Interrupts dazu, für millis() und was sonst noch per Interrupt gesteuert wird, die könnte dann längere Verzögerungen bewirken.

Einen kleinen Gewinn könntest Du durch Umstellung der Bedingungen erreichen, wenn Du erst getstate abfragst und verzweigst, und dann den Zustand des Eingangspins auswertest.

Wenn Dein Programm nichts anderes machen soll, kannst Du auch loop() komplett wegwerfen, und Deinen Code in main() einbauen, und den Aufruf von loop() weglassen.

Ob PCINT hilft, bliebe auszuprobieren.

Jungs, ich bin begeistert :sunglasses:

main() bringt deutliche Verbesserungen!

Es geht mir ja nicht um die eigentliche Verzögerung, sondern um deren Schwankungen.
Und die sind auf ein paar µs recht konstant runtergegangen. Durchschnittlich sind's jetzt so ca. 12 µs bei beiden Flanken, also erwische ich das Signal NOCH besser als notwendig.

Was da die IDE mit Setup und Loop anders macht verbirgt sich mir natürlich, aber zumindest hab ich dieses Konstrukt schon mal gesehen ;D

@DrDiettrich: über Interrupts habe ich schon gegrübelt, aber bin wegen des Flankenwechsels da hängengeblieben. Kann man das einfach mittendrin umbiegen? Ich hab's nicht probiert ...

Hallo,

die loop entspricht zwar der while(1), bevor die loop aber wieder von vorn beginnt werden noch paar Kleinigkeiten extra erledigt. Irgendwie hängt das mit der seriellen zusammen, wenn ich mich dunkel erinnere.

PCINT nutze ich auf einem ATtiny841. Ist eigentlich ganz einfach.
2 Funktionen bauen zum ein- und ausschalten.
Und dann die ISR.

Ein Bsp. von mir wo ich nur den Pin “PCINT2” behandel. Gehört zur Gruppe “0”.
Ob die Registernamen beim ATtiny13 gleich sind weiß ich nicht. Das nachschauen geht aber schnell.

void set_PCINT2()
{
	GIMSK = (1<<PCIE0);         // PCINT 7:0 Gruppe Trigger aktiv
	PCMSK0 = (1<<PCINT2);		// PCINT2, Pin Einzelauswahl
}


void del_PCINT2()
{
	GIMSK = 0;      // PCINT 7:0 Gruppe deaktivieren
	PCMSK0 = 0;		// PCINT2 deaktivieren
}


ISR(PCINT0_vect)  // Interrupt Handler PCINT0
{
	
	
}

Hallo,

ob das jetzt was bringt bei dir weiß ich nicht, dein ATtiny macht ja sonst nichts weiter.
Aber das kann ich dir noch auf den Weg geben. Wie man einen Eingang im ISR auf LOW abfragt. Zum Bsp.

ISR(PCINT0_vect)  // Interrupt Handler PCINT0
{
	uint8_t reg = PINA;	// Portzustand sichern
	
	if ( (~reg & 0b00000100) & (1<<PINA2) )  {  // prüft ob Pin A.2 auf Low ist 
		...
	}	
}

Klaus_ww:
Was da die IDE mit Setup und Loop anders macht verbirgt sich mir natürlich

Die Core Dateien kannst du dir alle ansehen. Für die Atmega Arduinos:

x:\Arduino\hardware\arduino\avr\cores\arduino\main.cpp

Was da zusätzlich Zeit brauchst ist dass loop() ein Funktionsaufruf innerhalb von main() ist. serialEvent() ist als weak deklariert. Das wird also nur ausgeführt wenn es definiert ist

Menno, ihr frustriert mich immer mit eurem Wissen :confused: - aber das spornt natürlich auch an :wink:

Die Pin-Change Geschichte schaue ich mir mal bei Gelegeneheit an, habe bisher nur mit den Interrupt-Basics rumgespielt.

@Serenifly
Wissen wo man schauen kann ist die eine Geschichte, den Inhalt zu verstehen dann noch eine.
Ich bin halt wirklich reiner Amateur der sich freut, wenn die Kiste macht was ich möchte. Elegant, effizient kommt erst dann, wenn's eng wird. Wie hier halt.

Also: danke euch allen für den Input.

Hallo,

keine Sorge, Serenifly überrascht mich auch immer mit seinem breit getreuten "Grundlagenwissen". :slight_smile: