Forum: Mikrocontroller und Digitale Elektronik ATtiny45 mit Arduino arbeitet nicht wie erwartet


von Dominik J. (nique)


Lesenswert?

Hallo

Nachdem ich ohne uC ein PWM-Signal auswerten wollte und das nicht 
hinbekomme, habe ich mich endlich doch entschlossen, den einfachen Weg 
über ein uC zu gehen. Doch ich bin auch nicht so erfolgreich, wie ich 
mir das vorgestellt habe.

Situation:
Ein RC-Empfänger liefert mir ein PWM-Signal. Dieses muss sich 
kontinuierlich ändern, mindestens 1x pro 500ms. Wenn nicht, hat etwas zu 
geschehen (in meinem Fall bei einem Modellflugzeug den Fallschirm 
auswerfen).

Wenn ich den Code mit einem Arduino-Mini laufen lasse (kann ich einmal 
schön über die Konsole sehen, was passiert) funktioniert es. Aber an 
einem ATtiny45 habe ich "Fehler".

Das Testsetup ist wie folgt:
- An Pin5 ist ein Servotester,
- An Pin6 ist über einen Widerstand eine LED angeschlossen,
- Alles über die gleiche Source mit 5V versorgt

Der Code ist dieser hier:
int inPin = 0;
int outPin = 1;
int brightness = 10;

long lastMove = millis();
long switchDelay = 0;
long switchDelayMax = 500;

long switchState = 0;
long switchStateLast = 0;
long switchMove = 0;

void setup(){
  pinMode(outPin, OUTPUT);
  pinMode(inPin, INPUT);
}

void loop(){
  switchState = pulseIn(inPin, HIGH);
  switchMove = switchState - switchStateLast;
  switchMove = abs(switchMove);
  switchStateLast = switchState;

  if (switchMove > 5) {
    lastMove = millis();
  }

  switchDelay = millis() - lastMove;

  if (switchDelay > switchDelayMax) {
    digitalWrite(outPin, HIGH);
  } else {
    analogWrite(outPin, brightness);
  }
  delay(100);
}


Resultat:
Wenn der Servotester automatisch und kontinuierlich das Signal ändert, 
ist die LED schwach.
Wenn der Servotester manuel ist und ich ihn nicht bewege, ist meine 
Erwartung vom Code oben, dass die LED spätestens nach einer halben 
Sekunde kontinuierlich hell leuchtet. Tut sie aber nicht. Sie leuchtet 
meist schwach und in unregelmässigen Abständen blinkt sie kurz hell auf 
um gleich wieder schwach zu leuchten. Mal sind dazwischen 18s, mal auch 
nur 1s.

Mit rumprobieren habe ich die Vermutung, dass schon die 
Differenzberechnung in switchMove nicht sauber funktioniert. Die "if 
(switchMove >5)" Abfrage sollte verhindern, dass wenn der RC-Empfänger 
kaum unterscheidbare Signale liefert, hier quasi eine Minimumschwelle 
ist, die es zu überschreiten gilt. Doch auch ohne Änderung über den 
Servotester ist hier manchmal die Bedingung erfüllt.

Was mache ich falsch?

Klar, als erstes ist es nicht in Assembler und alles Andere als optimal 
- aber ich kann leider nix anderes. Und einen Arduino-Mini einbauen will 
ich vom Platz her nicht.

Danke für die Hilfen

Gruess Dominik

von Falk B. (falk)


Lesenswert?

@Dominik Jenzer (nique)

>Ein RC-Empfänger liefert mir ein PWM-Signal. Dieses muss sich
>kontinuierlich ändern, mindestens 1x pro 500ms. Wenn nicht, hat etwas zu
>geschehen (in meinem Fall bei einem Modellflugzeug den Fallschirm
>auswerfen).

Was meinst du mit ändern? Muss mindestens alle 500ms ein Puls erscheinen 
oder soll sich alle 500ms die Pulsbreite ändern?

Ersteres kann man sehr leicht mit einem retriggerbaren Monoflop 
machen, da braucht es keinen Controller.

von Michael U. (amiga)


Lesenswert?

Hallo,

wenn länger als 500ms keiner mehr am Sender wackelt soll der Pin auf 
High gehen.
Hab es mir aber noch nicht angeschaut.

Wozu eigentlich den Tiny mit der PWM beschäftigen um die LED zu dimmen?

Gruß aus Berlin
Michael

von Sascha (Gast)


Lesenswert?

Also RC-Empfänger ist PPM wenn ich mich nicht irre. Du willst also 
detektieren, wenn die Funkverbindung zwischen Sender und Empfänger 
verlorengegangen ist und dann das Komplettrettungssystem für dein 
Flugzeug auslösen. Das sagt mir zumindest meine Kristallkugel.

Zuallererst würde ich mal die Fuses prüfen. Entweder Watchdog an oder 
Takt anders als erwartet.

Und dann das komplette Projekt mit allen Dokumenten, Schaltplan, Layout, 
h und c Files sowie Makefile in ein Zip und das dann hier hochladen.
Und dann verlassen wir vielleicht das magische Kristallkugelland.

von Dominik J. (nique)


Lesenswert?

Danke erst mal

@amiga hat es erfasst. Ich will wissen, wenn keiner mehr am Sender 
"wackelt". Im Flieger wird zwischen RC-Empfänger und dem Tiny noch 
Autopilot sein, darum werte ich nicht einfach den Failsafe aus, sondern 
gehe explizit auf einen Kanal der übertragen werden muss und hier wird 
dauernd "gewackelt".

Ich dimme die LED im Moment, damit es mich nicht blendet ;-) und ich 
zwischen den Ausgaben unterscheiden kann.
Hell = Notprogramm
Dimm = Alles läuft
Aus  = hab mal wieder ein Kabel ausgerissen.

Später stosse ich dort weitere Routinen an. Im finalen Programm wird 
nicht nur der Fallschirm geschmissen, denn je nach gewackel wird die 
Beleuchtung vom Flieger noch gesteuert. Gewackel zwischen 1000 und 
1500ms = gedimmte LED am Flieger - er ist am Boden. Gewackel zwischen 
1500 und 2000 - Flieger ist in der Luft, die LED (total 60W) geben 
vollgas. Und im Notprogramm werden sie SOS blinken... und das 
hoffentlich am Fallschirm.

Ist alles auf eine Board nur gesteckt.
GND - Pin 4
+5  - Pin 8
In  - Pin 5
Out - Pin 6

Out geht an R an D und dann an GND

Servotester hängt auch an +5, GND und eben an Pin 5

Ich verwende den obigen Code mit Arduino 1.0.6, einen UNO als 
ISP-Programmer für den Tiny.

Das mit den Fuses habe ich nicht im Griff. Wie prüfe ich das und wie 
stelle ich die ein (mit dem Arduino)?

von Sascha (Gast)


Lesenswert?

Muss doch in der Arduino Doku irgendwo stehen. Oder in ner FAQ.

Mit meinem STK500 und dem Lubuntu Notebook mache ich das per AVRDUDESS 
und dem Web-Fusecalculator.
Wie die Programmierumgebung bei Arduino aussieht, kein Plan.

von Dominik J. (nique)


Lesenswert?

Ich habe den Code einmal vereinfacht:

void loop(){
  switchState = pulseIn(inPin, HIGH);
  switchMove = switchState - switchStateLast;
  switchMove = abs(switchMove);
  switchStateLast = switchState;

  if (switchMove < 10) {
    digitalWrite(outPin, HIGH);
  } else {
    analogWrite(outPin, brightness);
  }

  delay(100);
}

Und genau so auf den Tiny45 und auf ein Nano geladen.

Den Schwellwert habe ich auf 10 gesetzt, weil ich mit dem Serial Monitor 
festgestellt habe, dass der uC ohne gewackel dennoch eine Differenz bis 
zu 9 bekam.

Die Nano-Ausgabe ist wie gewünscht, auf dem Tiny habe ich bei ständigem 
gewackel (über einen Servotester) unregelmässige helle blinker drin.

In der "Neutral"-Position des Servotesters (hier ändert sich der Input 
nicht mehr), bleibt beim Nano die LED schön hell, ohne unterbrüche. Beim 
Tiny lässt sich das nicht sagen, ob mehr gedimmt ist oder mehr hell ist. 
Das flackert recht wild.

von Philipp K. (philipp_k59)


Lesenswert?

Sascha schrieb:
> Also RC-Empfänger ist PPM

Es gibt Empfänger mit einer Art PWM(standardisierter fester Breite in 
1-2ms/0%-100%)/6Adern mit denen man direkt die Servos einzeln ansteuern 
kann oder so eine Art Multiplex namens PPM mit 6 kanälen in einem 
Signal/Ader welches dann direkt auf eine FCU geht, hier sind die Kanäle 
mit Fester breite aneinandergereit. Jeder Kanal hat dabei 2ms.

Einfach mal Googeln oder bei Wikipedia reinschauen.

Der erste Googler mit "PulseIn Attiny"
ergibt ein Timingproblem durch voreingestellte 1Mhz clock, während in 
der IDE bzw im Unterprogramm mit 8Mhz gerechnet wird.

Da wäre jetzt wichtig ob Du schon Fuses gesetzt hast oder einmal in die 
Boards.txt schauen und die eingetragene "F_CLK"(oder so ähnlich, sitze 
gerad nicht am Rechner) des ausgewählten Boards überprüfen.

von Dominik J. (nique)


Lesenswert?

Danke @philipp_k59 - das dürfte ein guter Hinweis sein.

Ich hab folgende Einstellungen zur Auswahl:
1
attiny45.name=ATtiny45 (internal 1 MHz clock)
2
attiny45.bootloader.low_fuses=0x62
3
attiny45.bootloader.high_fuses=0xdf
4
attiny45.bootloader.extended_fuses=0xff
5
attiny45.upload.maximum_size=4096
6
attiny45.build.mcu=attiny45
7
attiny45.build.f_cpu=1000000L
8
attiny45.build.core=arduino:arduino
9
attiny45.build.variant=tiny8
10
11
attiny45-8.name=ATtiny45 (internal 8 MHz clock)
12
attiny45-8.bootloader.low_fuses=0xe2
13
attiny45-8.bootloader.high_fuses=0xdf
14
attiny45-8.bootloader.extended_fuses=0xff
15
attiny45-8.upload.maximum_size=4096
16
attiny45-8.build.mcu=attiny45
17
attiny45-8.build.f_cpu=8000000L
18
attiny45-8.build.core=arduino:arduino
19
attiny45-8.build.variant=tiny8
20
21
attiny45-20.name=ATtiny45 (external 20 MHz clock)
22
attiny45-20.bootloader.low_fuses=0xfe
23
attiny45-20.bootloader.high_fuses=0xdf
24
attiny45-20.bootloader.extended_fuses=0xff
25
attiny45-20.upload.maximum_size=4096
26
attiny45-20.build.mcu=attiny45
27
attiny45-20.build.f_cpu=20000000L
28
attiny45-20.build.core=arduino:arduino
29
attiny45-20.build.variant=tiny8

Bisher habe ich mit dem 1MHz gearbeitet. Werde Morgen mal mit der 
8MHz-Variante testen. Oder gibts vorher noch andere Einstellungen zu 
tätigen?

von Dominik J. (nique)


Lesenswert?

Ach was morgen.

Hat mir gleich keine Ruhe gelassen und gleich nochmals alles aufgebaut.

Schon viel besser - bis fast sehr gut.

Mit Servotester als Wackler leuchtet die LED nur noch sehr selten hell. 
Also ev. den Wert von 10 noch weiter erhöhen. Da die Wackler letzten 
endes automatisch erzeugt werden, kann ich selbst dafür sorgen, dass die 
Wertänderungen jeweils "steil" genug sind.

Es ist interessant, ich habe am gleichen Servotester den ATtiny dran, 
wie auch den Nano. Und da sehe ich perfekt, wie die sich unterscheiden. 
Der Nano reagiert schon viel schneller! Aber für das wie ich es brauche, 
genügt das Verhalten vom tiny vollends.

Danke Philipp, deins war der entscheidende Hinweis in der Form, wie ich 
etwas damit anfangen konnte. Ich wäre selbst nicht auf die Idee 
gekommen, dass es am PulseIn und dachte, dass ich mit dem Rechnen was 
nicht begreife oder die ABS-Funktion nicht geht....

Cool, Danke und gute Nacht.

von Dominik J. (nique)


Lesenswert?

Jetzt läuft es auf dem Nano genau wie ich es mir vorstelle.

Aber auf dem Tiny noch nicht ganz. Zwar die Routine an sich schon, doch 
viiiiel zu langsam.

In einem Fall gebe ich Morse-R aus. Das mache ich so, dass die 
an-aus-Folgen in einem Array in Form von ms gespeichert sind: int aFly[] 
= {mDit,mPause,mDah,mPause,mDit,mBreak};

Mit der Funktion millis prüfe ich immer die verstrichene Zeit und 
entscheide dann, ob im Array inkrementiert wird oder noch nicht und 
davon abhängig, ob die LED aus oder an soll.
1
  if (isLED) {
2
    if ((millis() - lastTime) > aFly[iFly]) {
3
      lastTime = millis();
4
      digitalWrite(outPin, LOW);
5
      isLED = false;
6
      iFly++;
7
    }
8
  } else {
9
    if ((millis() - lastTime) > aFly[iFly]) {
10
      lastTime = millis();
11
      digitalWrite(outPin, HIGH);
12
      isLED = true;
13
      iFly++;
14
    }
15
  }

Im Nano funktioniert das, auch die Zeiten stimmen. Mit dem Tiny ist das 
gefühlt 10x langsamer!!! Dazu habe ich im Array die ms mal auf einen 
Zehntel eingestellt und da war es immer noch etwas langsamer als mit dem 
Nano. Das Gleiche mit dem Nano führt zu entsprechend schnellem blinken.

Da gibts in Sachen Timing wohl noch was zu beachten. Weiss da jemand 
mehr?

von Dominik J. (nique)


Lesenswert?

Jetzt weiss ich mehr. Es genügt natürlich nicht, nur das Board mit 8MHz 
auszuwählen. Die Fuses werden erst mit dem "Bootloader installieren" 
gesetzt.

Jetzt sieht es auch auf dem Tiny besser aus.

von Philipp K. (philipp_k59)


Lesenswert?

Ja genau, wollte ich eigentlich noch Anfügen ;) War mir nur nicht sicher 
ob die Fuses mit der Bootloader Option geschrieben werden.

Das mache ich immer mit avrdude direkt.

1Mhz ist nun mal ne Auflösung von 1ns minus alles mögliche drumherum und 
du willst ja nanosekunde genau messen.

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.