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
für eine Antwort, hänge den C-Code lieber an den Thread. Auf so einen ominösen Link klickt keiner gerne. Axel
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:
1 | //includes
|
2 | #ifndef F_CPU
|
3 | #define F_CPU 8000000UL
|
4 | #endif
|
5 | #include <avr/io.h> |
6 | #include <inttypes.h> |
7 | #include <util/delay.h> |
8 | #include <avr/sleep.h> |
9 | #include <avr/interrupt.h> |
10 | |
11 | |
12 | |
13 | //Methoden:
|
14 | |
15 | //Methode zur Schalterabfrage
|
16 | uint8_t CallSwitchState(const volatile uint8_t *inputreg, uint8_t inputbit) |
17 | {
|
18 | return ( *inputreg & (1<<inputbit) ); |
19 | }
|
20 | |
21 | // lange, variable Wartezeit, Einheit in Millisekunden
|
22 | void long_delay(uint8_t ms) |
23 | {
|
24 | for (; ms>0; ms--) _delay_ms(1); |
25 | }
|
26 | |
27 | |
28 | //main-Methode
|
29 | int main(void) |
30 | {
|
31 | //variables
|
32 | uint8_t switch_state = 0; |
33 | uint8_t count = 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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.