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) {}
}
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.
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_tStepsLeft;
2
3
ISR(....)
4
{
5
if(StepsLeft>0){
6
...Hardwareschrittausführen
7
StepsLeft--;
8
}
9
}
10
11
intmain()
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
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.
Eine eigene Frage?
Dieser Thread ist über 19 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.