Hallo zusammen, Ich hoffe, Ihr könnt mir weiterhelfen. Ich brauche einen sinnvollen Ansatz für mein Projekt: Ich will den ATmega16 nutzen, um einen Stepper-Motor in ziemlich einfacher Betriebsart zu betreiben. Ich brauche eigentlich "nur" eine Timer-Funktion, die folgende Features aufweist/zulässt: - Ich drücke eine Taste, somit wird an einen Ausgang 6400 mal ein Rechtecksignal (ton/toff=1) ausgegeben und diese Schleife dann sofort beendet. - Bei Betätigung einer anderen Taste wird der Puls am selben ausgang z. b. nur 1000 mal ausgegeben usw. Ich habe nun das Datenblatt, das Tutorial usw. durchgearbeitet, anscheinend bin ich aber zu blöd. Vielen Dank im Voraus. Gruß Tom
Schaffe Dir eine 16-Bit Zählvariable, die Du mit einem Wert Deiner Wahl lädst und in jedem Timerinterrupt um 1 verminderst, während Du den betreffenden Portpin umschaltest. Ist die Zählvariable bei 0 angekommen, stoppst Du die Zählerei.
Na das klingt doch erst einmal recht einfach. Ich nehme an du meinst einen Schrittmotor. Da solltest du dir als erstes einen Treiber bauen, der den entsprechenden Strom zur Verfügung stellt. Anschließend brauchst du 4 Signalleitungen, die für die spezielle Ansteuerung der Phasen benötigt werden. Soweit die Hardware. Software: Du kannst mit deinem Taster einen beliebigen Port nehmen und diesen mit einer Endlosschleife abfragen lassen. Sinnvoller wäre den ext.Int. zu verwenden. In den Speicher musst du nun die benötigten Ansteuerwerte für Halb-,Viertel-Schritt,... hintereinander ablegen, die dann entsprechen oft durchlaufen und Ausgegeben werden. Gruß Alexander
Hallo Travel Rec. erstmals vielen Dank für Deine schnelle Antwort. Anbei siehst Du einen kleinen Code. Kannst Du mir hierzu kurz Hilfestellung bieten, wie ich diesen abändern muss, um meinem Ziel näher zu kommen? Danke und Gruß Tom #include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> #define TAKT 8000000UL #define TEILER 65535UL-(TAKT/4096UL) typedef unsigned int uint16; typedef signed int sint16; typedef unsigned short uint8; typedef signed short sint8; uint16 step=0; SIGNAL(SIG_OVERFLOW1) { TCNT1 = TEILER; step++; PORTB = step; } int main (void) { DDRB = 0x01; PORTB = step; TCNT1 = TEILER; TCCR1B = 0x05; TIMSK |= (1<<TOIE1); sei(); while(1) {} }
Wie schnell sollen die 6400 Schritte durchlaufen werden? Bei nem Schrittmotor muss die Frequenz langsam (mit einer Rampe) hochgefahren werden.
Hallo Alexander, Danke auch Dir für Deine Antwort. Hardwareprobleme habe ich zum Glück keinerlei. Ich benötige nur einen Code, der mir weiterhilft, bzw. auf den ich aufbauen kann. Ich brauche nur einen kurzen Anstoß, damit ich die Timer-Sache kapiere, dann kanns vermutlich losgehen. Betreffend der Taster: Ich will keine ext. Interrupts verwenden, sondern nur die Ports pollen. Danke Tom
Nochmals an Alexander: Die Geschwindigkeit ist sehr sehr langsam (eine Umdrehung > 5sec.). Das Haltemoment reicht völlig aus, somit ist auch keine Rampe nötig.
Hallo Travelrec, trotzdem vielen Dank. Ich bin mir sicher, dass in diesem Forum einige C-Cracks unterwegs sind. Gruß Tom
Tom wrote: > #include <avr/signal.h> signal.h ist veraltet. Wenn noch nicht geschehen, installier am besten erstmal ne aktuelle Version von WINAVR/AVR-GCC+AVR-libc. > typedef unsigned int uint16; > typedef signed int sint16; > typedef unsigned short uint8; > typedef signed short sint8; Und sowas sollte man auch nicht machen. Dafür gibts typedefs in der stdint.h. Die heißen dann uint16_t, uint8_t, int16_t und int8_t. Und das ist dann auch portierbar... > SIGNAL(SIG_OVERFLOW1) Zum Thema "SIGNAL" siehe oben. > { > TCNT1 = TEILER; > step++; > PORTB = step; > } > > int main (void) > { > DDRB = 0x01; > PORTB = step; > TCNT1 = TEILER; > TCCR1B = 0x05; > TIMSK |= (1<<TOIE1); > sei(); > while(1) {} > } Timer-Zählregister vorladen ist Murks. Sowas macht man beim AVR mit einer Compare-Einheit z.B. im CTC-Modus. Schau Dir Datenblatt und AVR-GCC-Tutorial daraufhin mal an.
OK. Bin auch bei ASM zu Haus. Aber logisch kann man ja mal rangehen. Für den Timer-Int. benötigst du folgende Angaben: TCCR1B --> Register für Taktvorteiler TCNT1 --> Zählwert des Counters bis zum Überlauf TIMSK --> Interrupt Maske (Overflow_Int freigeben) Also diese Register müssen zuerst beschrieben werden. Die Interrupt-Routine existiert ja schon. Du schaltest zu beginn den Overflow-Int. inaktiv und pollst deinen PORT. Wird ein Wert (also Tastendruck) am PORT registriert, beschreibst du ein Register mit dem Zählwert(Anzahl von Ausgangsimpulsen) und löscht den aktuellen Schritt ("step") . Dann wird die der Overflow_Int. aktiviert. Die Schleife dafür ist vorhanden. Du vergleichst nun im Hauptprogramm ständig Ist und Soll, bis beide gleich sind. Anschließend wird der Overflow_Int deaktiviert und an den programmstart gesprungen. Vielleicht hilf der grobe Ablauf ja weiter.
Ich würde die Sache trotzdem immer noch umdrehen, wie es weiter oben schon mal angesprochen wurde. Anstatt den Zähler hochzählen zu lassen, würde ich ihn von einem Startwert bis auf 0 herunterzählen lassen. Auf lange Sicht gesehen funktioniert das meist besser unter anderem auch deshalb, weil dann Änderungen im Zielwert leichter (mit weniger Code) durchführbar sind, wenn im Zähler immer die Anzahl der noch ausständigen Schritte enthalten ist. Auch ist das Beenden der ganzen Zählerei (Notstop) einfacher möglich: Einfach den Zähler auf 0 setzen und gut ists (Alles klar: Ein Notaus sollte immer mit Hardware realisiert werden, es schadet aber nichts, wenn die Software dafür auch eine einfache Möglichkeit hat).
1 | uint16_t StepsLeft; |
2 | |
3 | ISR( .... ) |
4 | {
|
5 | if( StepsLeft > 0 ) { |
6 | ... Hardwareschritt ausführen |
7 | StepsLeft--; |
8 | }
|
9 | }
|
10 | |
11 | int main() |
12 | {
|
13 | ....
|
14 | |
15 | while( 1 ) { |
16 | if( PINxx & ( 1 << irgendwas ) ) { // das Polling der Taste |
17 | cli(); |
18 | StepsLeft = 10000; |
19 | sei(); |
20 | }
|
21 | |
22 | if( PINxx & ( 1 << irgendwasanderes ) ) { // Polling der 2.ten Taste |
23 | cli(); |
24 | StepsLeft = 3000; |
25 | sei(); |
26 | }
|
27 | |
28 | if( PINxx & ( 1 << nochwasanderes ) ) { // sofort abschalten |
29 | cli(); |
30 | StepsLeft = 0; |
31 | sei(); |
32 | }
|
33 | }
|
34 | }
|
Zum Thema Tasten-polling: Keine gute Idee. Taster sind notorische Preller. Die Entprellroutine von PeDa (Artikelsuche benutzen) ist die Ideallösung für die Auswertung von Tasten. Was anderes braucht man nicht um eine 100% funktionierende, zufriedenstellende, problemlose Lösung zu bekommen.
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.