Problem mit Delay() und Attiny85

Hallo zusammen,

bei der Entwicklung einer Attiny85 Servomotor Ansteuerung bin ich leider auch ein Problem gestoßen welches ich nicht lösen kann.

Die Funktion delay() bringt den Attiny85 bei 8 Mhz immer zum Absturz…

Also bin ich auf delayMicroseconds() ausgewichen, da es sich bei dem delayMicroseconds um eine unsigned int handelt kann ich maximal 65535 (Clock 8 Mhz internal) Mikrosekunden Delay verwenden. Bevor ich im überlauf des Timers lande.

Kann mir jemand sagen wie ich es hinbekommen kann das ich für den Servomotor jeweils 2 Sekunden Zeit zum Verfahren zur Verfügung stelle zum Verfahren z.b. nach pulsOut( Sa, 30) und anschießend die Spannung wegschalte?

Zur Anforderung: Bei einem Steuersignale „LOW“ soll der Linke Anschlag des jeweiligen Servomotors angesteuert werden. In diesem Fall 30 Grad. Bei wechsel auf ein „HIGH“ Signal erfolgt die Ansteuerung des Linken Anschlages, hier 150 Grad. Ich musste leider Feststellen das die Servomotoren in den Endlagen bei gleichbleibendem Signal sporadisch anfangen zu Rattern. In so einem Fall kann zum Beispiel das Potentiometer ursächlich sein, das durch die Abtriebswelle angetrieben bzw. verstellt wird. Die häufig verwendeten sehr eng tolerierten, möglichst starren Kupplungen sind oft verantwortlich für ein rattern des Servomotors bei gleichbleibendem Signal. Zur Vermeidung dieses Problems und zur gleichzeitigen Senkung des Energieverbrauches habe ich mich dazu entschieden die Spannungsversorgung für die Servomotoren gezielt zu,- bzw. abzuschalten.

int Sa=2,Sb=3,Ea=0,Eb=1,En=4,varA,varB;
unsigned long previousMicros = 0; // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval = 500000;    // Interval zwischen zwei Änderungen  Max 0 bis 4,294,967,295 

void setup() {
pinMode(Sa, OUTPUT);  //Servomotor a  Ausgang definieren
pinMode(Sb, OUTPUT);  //Servomotor b  Ausgang definieren
pinMode(Ea, INPUT);   //Eingang Freigabe Servo a definieren 
pinMode(Eb, INPUT);   //Eingang Freigabe Servo b definieren 
pinMode(En, OUTPUT);  // Spannung für den Servo Enable definieren
}

void loop() 
{
  digitalWrite(En,LOW); // Spannung für den Servo nicht freigegeben
  
if ((digitalRead(Ea) == HIGH) &&   (digitalRead(Ea) != varA))  //Wenn Freigabe fr a erfolgt dann 
{ 
  previousMicros = 0;
  digitalWrite(En,HIGH);    // Spannung für den Servo freigeben
  delayMicroseconds (500);               // Delay Schaltvorgang
  pulsOut( Sa, 30);          // setze Puls fr Servo a auf 30 (Anschlag links)
      delayMicroseconds (500);      // Soll 2 Sekunden betragen 
  digitalWrite(En,LOW);     // Spannung für den Servo nicht freigegeben
  varA = digitalRead(Ea);
}

if ((digitalRead(Ea) == LOW) &&  (digitalRead(Ea) != varA))  //Wenn Freigabe fr a erfolgt dann 
{ 
  previousMicros = 0; 
  digitalWrite(En,HIGH);    // Spannung für den Servo freigeben
  delayMicroseconds (500);               // Delay Schaltvorgang
  pulsOut( Sa, 150);          //setze Puls fr Servo a auf 30 (Anschlag links)
  delayMicroseconds (500);      // Soll 2 Sekunden betragen 
  digitalWrite(En,LOW);     // Spannung für den Servo nicht freigegeben
  varA = digitalRead(Ea);
}

if ((digitalRead(Eb) == HIGH) &&  (digitalRead(Eb) != varB))  //Wenn Freigabe fr b erfolgt dann 
{ 
  previousMicros = 0; 
  digitalWrite(En,HIGH);    // Spannung für den Servo freigeben
  delayMicroseconds (500);               // Delay Schaltvorgang
  pulsOut( Sb, 30);          // setze Puls fr Servo b auf 30 (Anschlag links)
      delayMicroseconds (500);      // Soll 2 Sekunden betragen 
  digitalWrite(En,LOW);     // Spannung für den Servo nicht freigegeben
  varB = digitalRead(Eb);
}

if ((digitalRead(Eb) == LOW) &&  (digitalRead(Eb) != varB))  //Wenn Freigabe fr b erfolgt dann 
{ 
  previousMicros = 0; 
  digitalWrite(En,HIGH);    // Spannung für den Servo freigeben
  delayMicroseconds (500);               // Delay Schaltvorgang
  pulsOut( Sb, 150);         // setze Puls für Servo b auf 30 (Anschlag links)
      delayMicroseconds (500);      // Soll 2 Sekunden betragen 
  digitalWrite(En,LOW);     // Spannung für den Servo nicht freigegeben
  varB = digitalRead(Eb);
}
}
  
// Funktion zum Erzeugen des Steuerimpulses für den Servo 
void pulsOut( int pin, int p)
{
digitalWrite(pin,HIGH);
delayMicroseconds(300+p*(2500/180));
digitalWrite(pin,LOW);
}


[code]

Vielen Dank schon einmal für eure Bemühungen.

Gruß tweak87

Die Funktion delay() bringt den Attiny85 bei 8 Mhz immer zum Absturz…

Meines Wissens sollte der Beispiel-Blink-Sketch auch auf einem attiny85 gehen, wenn dieser überhaupt in deiner IDE unterstützt wird.

Hab selbst nur die digispark attiny85-Variante, da stört das normale delay() in der Regel die USB Funktionen, aber gehen tut es.

delayMicroseconds ist nicht für Zeiten > "wenige millisekunden" gedacht ... Die bisher unbenutzten previousMicros sind ( im Zusammenhang mit micros() ) evtl. zu brauchen.

Oder doch der einfachheit halber mit millis() arbeiten.

Reicht ein einzelner pulsOut um den Servo komplett zu fahren? Bin kein Servo-Experte, aber ich dachte da würden andauernd Pulse im 20 ms Zyklus gesendet... (selbst dafür würde ich lieber kein delayMicros verwenden)

Der servo benötigt zum verstellen eine signalflanke zwischen 1 und 2 ms deshalb das Microseconds. Der Zyklus ist 20 ms. Da ich aber nur eine Position anfahren muss (ich vorstelle nur eine restriktor) reicht mir erstmal der einmalige Steuerbefehl.

Mit den niedrigen Werten funktioniert das ganze auch einwandfrei. Nur wie ich jetz nach dem Verfahren die Spannung abschalten kann ( für beide Motoren gleichzeitig wäre auch noch eine Möglichkeit) ist mir immernoch schleierhaft :frowning:

Bei meinem attiny will er die micros einfach nicht akzeptieren. Das blink without delay habe ich schon versucht einzubauen, da die if Schleife aber nur aufgerufen würde wenn der Wert zum Beispiel 2 Sekunden erreicht ist und ansonsten immer übergangen wird habe ich da ich vier Haupt if Abfragen habe ja immer die Freigabe für die Motoren…

Wobei das kann ja tatsächlich sein das wenn ich über das delay von 20 Millisekunden komme welche der Zykluszeit des Servomotors entspricht aus diesem Grund auch keine Aktion mehr durchgeführt wird…

Mist wie mache ich jetzt bloß weiter :frowning:

Mir ist gerade noch eine Idee gekommen.

Lt. meinen Recherchen hätte die Funktion delay() für den attiny85 problemlos funktionieren müssen. Ich vermute den Fehler wie folgt.

Das Signal, das an den Servo geschickt wird, hat eine Länge von ungefähr 20ms. Diese 20ms sind nicht besonders kritisch und sind ein Überbleibsel von der Technik mit der mehrere Kanäle über die Funkstrecke einer Fernsteuerung übertragen werden. Für das Servo wichtig ist die Impulsdauer in der ersten Phase eines Servosignals. Nominell ist dieser Impuls zwischen 1ms und 2ms lang. Für die Positionsauswertung des Servos haben die 20ms Wiederholdauer keine besondere Bedeutung, sieht man einmal davon ab, dass ein Servo bei kürzeren Zeiten entsprechend öfter Positionsimpulse bekommt und daher auch öfter die Position gegebenenfalls korrigiert, was möglicherweise in einem etwas höheren Stromverbrauch resultiert.

Das bedeutet das ich durch ein delay von 2 Sekunden korrekte Signal an den Servomotor nicht mehr übertragen haben (Puls 2sek Pause Plus anstatt Puls 20 ms Pause Puls)

Ich könnte somit eine Schleife aufbauen die wie folgt aussieht…

if ((digitalRead(Ea) == HIGH) && (digitalRead(Ea) != varA)) //Wenn Freigabe fr a erfolgt dann
{
previousMicros = 0;
digitalWrite(En,HIGH); // Spannung für den Servo freigeben
delayMicroseconds (500); // Delay Schaltvorgang

for(i<200,i++)
{
pulsOut( Sa, 30); // setze Puls fr Servo a auf 30 (Anschlag links)
delay (10); // Soll 2 Sekunden betragen
}

digitalWrite(En,LOW); // Spannung für den Servo nicht freigegeben
varA = digitalRead(Ea);
}

So würde ich alle zehn Millisekunden das Signal neu erzeugen und so das Zyklussignal für den Servo beibehalten.

Hallo,

wie programmierst du den ATtiny85 überhaupt? In der Arduino IDE? Hast du den ATtiny85 mittels Boardmanager der IDE beigebracht? Dann sollten sämtliche Befehle wie gewohnt funktionieren.

ATtinyCore: http://playground.arduino.cc/Main/ArduinoOnOtherAtmelChips Der Boardtakt ist auch beim flashen 8MHz gewählt?

Servospannung abschalten ist das eine. Kraft ist weg, wäre dir in dem Fall egal. Aber das Steuersignal muß dann auch weg bzw. auf Masse. Das geht einfach mit digitalwrite Low. Die Servobetriebsspannung kann man nur mit P-Channel Mosfet oder PNP Transistor sauber trennen. Masse sollte immer erstmal verbunden bleiben.

Ich weiß nicht wie ein Servo reagiert, wenn Dauerspannung oder Masse am Steuereingang anliegen. Ob es dann sicher an der alten Position bleibt. Aber wenn ich nach einem 1,4ms Puls einen 1,7ms Puls sende, dann ändert das Servo seine Position.

Wenn ich Tweak richtig verstehe gibt er ohne Servo Lib, manuell, einen Puls raus und das wars. Das Servo reagiert scheinbar richtig. Wenn es keinen anderen Puls erkennt, müßte das so funktionieren. Hätte auch gedacht es muss immer aufgefrischt werden.

Edit: oder einfach die Servo Lib nehmen

Ja der attiny85 wurde über ISP und die arduino IDE gebrannt. Mit einem internen clock von 8mhz

Das abschalten der Spannung ist kein Problem ich habe hierzu extra ein Schaltnetzteil über welches ich saß realisiert bekomme. Deshalb ja den enable Ausgang. Das steuersignal auf Null wird auch noch möglich sein sobald ich die Zeit realisiert habe. Bei 10Nm benötigter Kraft wird das Steuersignal aber ohnehin nicht genug Energie liefern um beim Motor auch nur ein zucken zu verursachen :stuck_out_tongue:

Ich denke aber mit der for Schleife sollte das gehen. So habe ich inklusive zykluszeit des Programms denke ich nicht mehr als zwanzig Sekunden Signakzyklus für den servo Motor.

Verzeiht mir sie Fehler auf dem. Handy zu schreiben ist echt ein Graus :stuck_out_tongue: