Hallo liebes Forum
Wie man dem Titel schon entnehmen kann, versuche ich mir gerade als
erstes AVR-Projekt (erstes ohne Arduino) die Useless Machine nach zu
bauen.
Den Code habe ich der Übersichtlichkeit halber mal bei Pastebin
hochgeladen:
http://pastebin.com/w9RkGT06
Der Gedanke hinter dem Code ist:
1. Nach Reset/Stromanschluss: Initialisierung des Servo (Software-PWM an
PB1) auf Anfangsposition, wenn der Schalter (PD2) auf GND steht.
2. Nach erfolgreicher Initialisierung -> Interrupt auf INT0 (PD2)
einschalten
3. Einschlafen nach Interrupt- Aktivierung um Strom zu sparen
4. Sobald Interrupt kommt, diesen Sperren und mit Servo Schalter
ausschalten
5. Wenn Schalter auf "Aus", Interrupt wieder an
6. Servo zurück und wieder einschlafen
Im Simulator (AVRStudio 4 mit SP3) läuft die Sache (soweit ich als
Anfänger verifizieren kann) eigentlich rund.
Nach Flashen und setzen der passenden Flags (interner 8MHz-Oszi ohne
Clockdiv) läuft in der Realität aber garnichts.
Der Servo zuckt nur kurz in eine Richtung bis zum Anschlag wenn man den
uC mehrmals resetted. Und auf Interrupt (Flanke von LOW auf HIGH an
INT0) reagiert er leider auch nicht :(
Mit nem einfachen Sweep-Test für den Servo, reailisiert mit
for-Schleifen und der gleichen Software-PWN tut meine Schaltung was sie
bei nem Sweep soll.
Ich wär echt dankbar für jeden Hinweis. Versuch schon 4 Tage das Problem
in den Griff zu kriegen.
Schöne Grüße,
Basti
Hallo
wie gewünscht gibts hier meinen Code als Datei im Anhang.
Ich kann den Code auch gerne nochmal direkt in einen Post schreiben,
aber ich befürchte ich verstoße damit gegen die Foren-Etikette, da er
(auch aufgrund meiner Kommentierung und Formatierung) wohl recht lang
ist :/
Danke schonmal im Voraus für alle Hinweise und Tips.
Gruß,
Basti
No.
So
//setze Pin PB1 auf LOW
PORTB &= ( 0 << PB1 );
wird kein Pin gelöscht
> Ich kann den Code auch gerne nochmal direkt in einen Post> schreiben, aber ich befürchte ich verstoße damit gegen die> Foren-Etikette
Mach dir deswegen keine Sorgen.
Langer Code ist nur dann ein Problem, wenn du ihn direkt ins Posting
reinschreibst. Als ANhang ist das kein Problem.
> Im Simulator (AVRStudio 4 mit SP3) läuft die Sache> (soweit ich als Anfänger verifizieren kann) eigentlich rund.> Nach Flashen und setzen der passenden Flags (interner 8MHz-Oszi> ohne Clockdiv) läuft in der Realität aber garnichts.
Schwerer Fehler:
Man entwickelt niemals Code nur mit dem Simulator.
Du willst immer so schnell wie möglich auf den realen Prozessor und das
Programm, bzw. die Teile die du bereits hast testen.
Du willst immer so schnell wie möglich testen und immer so wenig wie
möglich an neuem Code testen. Sonst geht es dir nämlich genau so wie es
dir jetzt geht: Du stehst mit einem Haufen Code da, der nicht
funktioniert und weißt nicht wo du anfangen sollst. Daher willst du
immer mit so wenig Code wie möglich anfangen und den bereits testen.
Dann kommt wieder Code dazu und dann wird der getestet. Dadurch hast du
immer Programmteile, die schon getestet sind und von denen du ausgehen
kannst, dass sie zumindest einigermasen richtig sind. Kommt eine
Erweiterung dazu und nichts geht mehr, dann wird der Fehler höchst
wahrscheinlich im neu hinzugekommenen Code sein. Und da der nicht
umfangreich sondern klein ist, hast du auch weniger Möglichkeiten, wo du
den Fehler seuchen musst. Läuft dann die Erweiterung, dann kommt die
nächste Erweiterung dazu.
In diesem Sinne werden Programme stufenweise entwickelt. Aber davon
auszugehen, dass du ein Programm komplett runtertippen kannst und alles
läuft auf Anhieb - das ist ein schwerer Fehler von
Selbstüberheblichkeit. Da hilft dir auch ein Simulator nichts, denn was
du im Simulator nicht testen kannst, dass ist die Hardware.
Hallo
Danke erstmal für den Hinweis zum LOW setzen von Pins.
Ich werds dann mal damit
1
PORTB&=~(1<<PB2);
probieren.
Der Hinweis mit dem Testen von Code-Abschnitten ist wohl auch ein guter
Gedanke. Ich werd meinen Code mal in Häppchen zerlegen und einzeln
testen.
Ich wollte mit meinen Posts auf keinen Fall überheblich erscheinen.
Sorry falls das so rüberkam.
Und Danke nochmal für die Hinweise. Melde mich wieder wenn ich Erfolg
vorweisen kann (oder wenn nicht).
Gruß
Sebastian K. schrieb:> Ich wollte mit meinen Posts auf keinen Fall überheblich erscheinen.> Sorry falls das so rüberkam.
Ich muss mich entschuldigen. Da hab ich mich wohl nicht gut genug
ausgedrückt.
Worum es geht, ist das Anfänger gerne glauben man tippt ein Programm
runter, bessert ein oder zwei Tippfehler aus und dann funktioniert
alles. Die 'Selbstüberheblichkeit' (das Wort passt nicht ganz) besteht
in genau diesem Glauben, dass man das könne.
Das genaue Gegenteil ist der Fall. Auch Profis arbeiten stufenweise,
wenn auch ihre Stufen etwas größer sind.
Hallo
Dann hab ich den Hinweis auch selbst ein wenig falsch aufgefasst.
Ich bin ja sehr dankbar, dass solche Möglichkeiten wie dieses Forum und
die Tutorials hier existieren.
Um zurück zum Projekt zu kommen:
Ich habe jetzt vom Projekt erstmal die Initialisierungphase abgespalten
und wollte testen was der Tiny2313 damit macht.
Hier der Code:
// lange, variable Wartezeit, Einheit in Millisekunden
22
voidlong_delay(uint8_tms)
23
{
24
for(;ms>0;ms--)_delay_ms(1);
25
}
26
27
28
//main-Methode
29
intmain(void)
30
{
31
//variables
32
uint8_tswitch_state=0;
33
uint8_tcount=0;
34
35
//Set pins of Port D as input
36
DDRD=0b00000000;
37
//Disable internal pull ups of Port D
38
PORTD=0b00000000;
39
//Set PORT B pins as output
40
DDRB=0b11111111;
41
42
//Hauptschleife (läuft dauerhaft...)
43
while(1)
44
{
45
//frage schalterstatus ab
46
switch_state=CallSwitchState(&PIND,PD2);
47
48
//'Servo-Aus'-Schleife beginnen, wenn PD2 = LOW
49
while(switch_state==0)
50
{
51
//wenn noch keine Sekunde vorbei (Einstellphase für Servo)
52
if(count<75)
53
{
54
//counter hochzählen
55
count+=1;
56
57
//setze Pin PB1 auf LOW
58
PORTB&=~(1<<PB2);
59
60
//warte 13 ms (duty-cycle des Servo)
61
long_delay(13);
62
63
//setze Pin PB1 HIGH
64
PORTB|=(1<<PB1);
65
66
//warte 1,3 ms (Pulslänge für "Servo eingefahren"-Ausschlag)
67
_delay_us(1300);
68
}
69
//wenn servo sicher nach initialisierung auf "Eingefahren"
70
else
71
{
72
//setze counter auf 0
73
count=0;
74
75
//verlasse Servo-while-schleife, wenn Zeit um
76
break;
77
}
78
}
79
}
80
81
return(0);
82
}
Leicht ernüchtert musste ich feststellen, dass der uC nicht mal
Ansatzweise daran denkt den Servo zu bewegen. Der Aktor zuckt nur einmal
kurz beim Reset, was sich aber vermutlich auf
"Initialisierungs-Glitches" zurück führen lässt.
Ich habe gerade selbst die Vermutung, dass ich vielleicht den Pin nicht
korrekt abfrage, oder ich noch eine falsche Vorstellung vom Rückgabewert
der "switch_state"-Methode habe.
Könnte da was dran sein, oder bin ich da total auf dem Holzweg?
Gruß,
Basti
Hallo mal wieder
Mittlerweile habe ich meinen Code lauffähig bekommen.
Er ist vielleicht nicht ganz so professionell und elegant, aber immerhin
tut er was er soll :)
(Steuern des Servos und den Schlafmodus nutzen um Strom zu sparen)
Der entsprechende C-Code findet sich (recht ausführlich kommentiert) im
Anhang an diesen Post.
Zusätzlich sind dort die Schaltpläne für eine Steuerplatine der
Useless-Machine zu finden (Eagle-Files).
Habe die Platine aber dank kleiner Größe mit Lochraster aufgebaut.
Danke nochmal an alle Hinweise und die Tutorials zu AVR-GCC auf dieser
Seite.
Beste Grüße,
Basti
wo ist jetzt der Vorteil, anstelle von
_delay_ms(15)
zu schreiben
long_delay(15)
?????
das erste scheint mir besser lesbar zu sein, und spar auch noch code
(-Speicherplatz)
Guten Morgen,
Wegstaben Verbuchsler schrieb:> wo ist jetzt der Vorteil, anstelle von>> _delay_ms(15)>zu schreiben>>long_delay(15)>
Das ist ne gute Frage denk ich...
Ich meinte irgendwo gelesen zu haben, das lange Warteschleifen manchmal
Probleme verursachen können. Und gleich darunter fand ich dann den Tip
mit der "long_delay()"-Methode.
Als Anfänger hab ich das dann gleich mal aufgegriffen und wollte auf
Nummer sicher gehen. Ich lasse mich aber gerne eines Besseren belehren,
wenn mein Vorgehen da unsinnig ist :)
Ein kleiner Nachtrag noch zum Code/zu externen Interrupts:
Ich hatte anfangs sehr lange rumprobiert, bis ich den ATTiny2313 mit
externem Interrupt aus dem Schlafmodus holen konnte.
Falls jemand Anderes bei ersten Gehversuchen auch auf dieses Problem
trifft:
Im Datenblatt des uC steht (auf Seite 31 glaub ich, bei den
Sleep-Modes), dass sich der 2313 nur durch anhaltenden Low-Level an INT0
und INT1, oder aber durch die PCINTX-Eingänge aus dem Power-Down-Modus
aufwecken lässt (Bitte korrigiert, falls falsch).
Leider hatte ich sehr lange rumprobiert den uC mit einer steigender
Flanke an INT0 und INT1 zu wecken, was aber nicht sehr fruchtbar war.
Gruß,
Basti
Sorry für den Doppelpost.
Mir ist heute Nachmittag noch ein Fehler in den Eagle-Files aufgefallen.
PB4 hing bei offenem Schalter in der Luft. Der Pull-Down Widerstand war
leider falsch gesetzt.
Korrigierte Files sind im Anhang, für die die es nachbauen wollen.
Gruß,
Basti