Forum: Mikrocontroller und Digitale Elektronik Timer nutzen beim ATmega16 für Stepper


von Tom (Gast)


Lesenswert?

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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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.

von Alexander L. (lippi2000)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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) {}
}

von Alexander L. (lippi2000)


Lesenswert?

Wie schnell sollen die 6400 Schritte durchlaufen werden?
Bei nem Schrittmotor muss die Frequenz langsam (mit einer Rampe) 
hochgefahren werden.

von Tom (Gast)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Sorry, C ist nicht meins, bin ASM-Freak ;-)

von Tom (Gast)


Lesenswert?

Hallo Travelrec,

trotzdem vielen Dank.

Ich bin mir sicher, dass in diesem Forum einige C-Cracks unterwegs sind.

Gruß

Tom

von Johannes M. (johnny-m)


Lesenswert?

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.

von Alexander L. (lippi2000)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
Noch kein Account? Hier anmelden.