PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Schrittmotoren



amal
26.07.2011, 14:25
hallo,
ich steure einen Schrittmotor mit einem CTC Modus, und der Motor soll nur 100 Schritte machen,
ich habe das so realisiert:

ISR(TIMER1_OVF_vect)
{
zx++;
}

ISR(PCINT1_vect)
{
if(!(PINC&(1<<PC0)))
{
if(zx<<100)
{ OCR1A= xxxxxx;
PORTB|=(1<<PB0); EN
PORTB|=(1<<PB1);RICHT
}
else
PORTB&=~(1<<PB0);
}


}

wird das so funktionieren? übrigens ich starte das Prog mit einem Taster, der mit einem PCINT verbunden ist

markusj
26.07.2011, 17:48
Nein. Zuerst solltest du deinen Code aber Mal mit Code-Tags versehen und vernünftig Einrücken, so bekommt man davon ja Augenkrebs.

Dann stell dir Mal die Frage, was du alles machen musst.

Den Zähler zurücksetzen
Den Timer starten
Nach 100 Schritten den Timer wieder ausschalten (sonst läuft dein Motor weiter)

Die letzten beiden Punkte betreffen den Timer-Interrupt, der erste das Ereignis "Knopf gedrückt".
Außerdem solltest du noch eine Entprellung einbauen, sonst gibt es möglicherweise eine unangenehme Überraschung wenn du den Taster drückst.

Was machst du momentan?

Zähler im Interrupt inkrementieren (und sonst gar nix!)
Auf einen Knopfdruck reagieren und dabei in irgend einer omniösen Fallunterscheidung entweder den Timer starten oder einen Port bis auf einen Ausgang auf 0 setzen.


Was Fehlt? Irgendwas was sich um den Ablauf der 100 Schritte kümmert!

mfG
Markus

amal
27.07.2011, 12:19
hallo,
ich brauche bitte Eure Hilfe, ich weiß nicht in welche Stelle soll ich den Timer einschalten, und in welche Stelle solle ich den ausschalten, was ich weiß dass mein Timer geht in die fct ISR(OVF), wenn er den Wert von OCR1A erreicht hat. hier mein Code bitte um Korrektur danke

#include <avr/io.h>
#include <avr/interrupt.h>





unsigned int zx=0,zy=0;
void motorxR(unsigned int schr);
void motorxL(unsigned int schr);





int main()
{


DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5); // PIN0-5 als Ausgang für die Motoren definieren // PortB als Ausgang definieren
DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren


// Timer 1 einstellen
//
// Modus 4:
// CTC , Top von OCR1A
//
// WGM13 WGM12 WGM11 WGM10
// 0 1 0 0
//
// Timer Vorteiler: 1
// CS12 CS11 CS10
// 0 0 1
//
// Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
// COM1A1 COM1A0
// 0 1
// OCR1A=(fclk/2*N)-1 N: Vorteiler
TCCR1A = (1<<COM1A0) | (0<<WGM11);
TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
OCR1A=18432;


//****************** Interrupt initialisieren *************************************
PCMSK1 = (1 << PCINT8)|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 setzen
PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30

//*********** TIMER1 OVF *****************

TIMSK1|=(1<<TOIE1);
TCNT1=30;
zx=0;


sei();






while (1) {}
}



ISR(TIMER1_OVF_vect)
{
zx++;

if(zx>100)
{
PORTB&=~(1<<PB0);}

TCNT1=0;
zx=0;
}
ISR(PCINT1_vect) //Interrupt Service Routine
{

if(!(PINC&(1<<PC0)))
{
motorxR(zx);
}

if(!(PINC&(1<<PC1)))
{
motorxL(zx);
}


}


void motorxR(unsigned int schr)
{
PORTB|=(1<<PB3);
PORTB|=(1<<PB0);
}
void motorxL(unsigned int schr)
{
PORTB&=~(1<<PB3);
PORTB|=(1<<PB0);
}


danke

amal
27.07.2011, 13:37
also laut datenblatt wenn der Timer ausschalten muss dann muss ich den Vorteiler auf null setzen, richtig?

amal
27.07.2011, 15:20
kann bitte jemand einen Typ geben, wie ich meinen Motor nach 100 Schritte ausschalten kann


#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int zx=0,zy=0;
void motorxR(unsigned int schr);
void motorxL(unsigned int schr);

int main()
{
DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5); // PIN0-5 als Ausgang für die Motoren definieren // PortB als Ausgang definieren
DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren



TCCR1A = (1<<COM1A0) | (0<<WGM11);
TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
OCR1A=18432;


//****************** Interrupt initialisieren *************************************
PCMSK1 = (1 << PCINT8)|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 setzen
PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30

//*********** TIMER1 OVF *****************

TIMSK1|=(1<<TOIE1);
sei();

while (1) {}
}

ISR(TIMER1_OVF_vect)
{
zx++;
if(zx>100)
{
PORTB&=~(1<<PB0);
TCCR1B&=~(1<<CS10);
}
zx=0;
}

ISR(PCINT1_vect) //Interrupt Service Routine
{
if(!(PINC&(1<<PC0)))
{motorxR(zx);
}
if(!(PINC&(1<<PC1)))
{motorxL(zx);
}
}

void motorxR(unsigned int schr)
{
PORTB|=(1<<PB4);
PORTB|=(1<<PB0);
}
void motorxL(unsigned int schr)
{
PORTB&=~(1<<PB4);
PORTB|=(1<<PB0);
}

ich glaube der geht gar nicht in ISR(OVF) rein

markusj
27.07.2011, 16:22
OVF steht ja Overflow (Überlauf), und durch den CTC-Betriebsmodus läuft dein Zähler im Regelfall NICHT bis zum Überlauf, es überrascht daher nicht, dass der Interrupt auftritt. Bei einem Compare-Match dürfte einer der Output-Compare-Interrupts ausgelöst werden, also OCsonstwas.

mfG
Markus

amal
28.07.2011, 09:22
OVF steht ja Overflow (Überlauf), und durch den CTC-Betriebsmodus läuft dein Zähler im Regelfall NICHT bis zum Überlauf, es überrascht daher nicht, dass der Interrupt auftritt. Bei einem Compare-Match dürfte einer der Output-Compare-Interrupts ausgelöst werden, also OCsonstwas.

mfG
Markus
danke ich werde das tun, stimmt in CTC Mode man erreicht OVF nur bei MAX=ffff.

amal
28.07.2011, 13:47
ich habe jetzt den COMP Interrupt benutzt, ich möchte jetzt zum beispiel
100schritte machen dann auf einem PIN eine PWM signal ausgeben, dann
nochmal 100 Schritte, das ganze 10mal,das heißt der Motor soll sich 1000
Schritte machen und 10 mal pwm signal ausgeben. und das habe ich so
realisiert, ich bitte um Korrektur.

#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint16_t zx=0,zy=0;
void motorxR(void);

void sleep_ms(unsigned int ms);

int main()
{


DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5); // PIN0-5 als Ausgang für die Motoren definieren // PortB als Ausgang definieren
DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren


// Timer 1 einstellen
//
// Modus 15:
// Fast PWM, Top von OCR1A
//
// WGM13 WGM12 WGM11 WGM10
// 0 1 0 0
//
// Timer Vorteiler: 1
// CS12 CS11 CS10
// 0 0 1
//
// Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
// COM1A1 COM1A0
// 0 1
// OCR1A=(fclk/2*N)-1 N: Vorteiler
TCCR1A = (1<<COM1A0) | (0<<WGM11)| (0<<WGM10);
TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
OCR1A=18432;


//****************** Interrupt initialisieren *************************************
PCMSK1 = (1 << PCINT8)|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 setzen
PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30

//*********** TIMER1 COMP *****************

TIMSK1|=(1<<OCIE1A);
TCNT1=0;



sei();






while (1) {}
}



ISR(TIMER1_COMPA_vect)
{
if(zx>100)
{
PORTB&=~(1<<PB0);
}
zx++;

}

ISR(PCINT1_vect) //Interrupt Service Routine
{

sei();
//******************************* MESSUNG STARTEN ********************************************
//************************************************** ************************************************** *

if(!(PINC&(1<<PC0)))
{

for(unsigned int j=0;j<10;j++)
{
motorxR();
PORTB|=(1<<PB5); //
sleep_ms(5); // TRIGGERN
PORTB&=~(1<<PB5); //
sleep_ms(2);*/
zx=0; // WARTEN 2ms
}
}

void motorxR(void)
{
PORTB|=(1<<PB3);
PORTB|=(1<<PB0);
//PORTB&=~(1<<PB2);

}



void sleep_ms(unsigned int ms)
{
for (unsigned int s=0; s<ms; s++)
{
for (long int i=0; i<461; i++)
{
asm volatile("nop");
}
}
}

markusj
28.07.2011, 15:26
Hey Amal,

warum probierst du es nicht einfach Mal aus? Es hilft dir wenig, deinen Code ständig hier abzuladen und darauf zu warten, dass jemand nach Fehlern sucht. Zum Programmieren gehört auch das (gezielte) Testen und die darauf unweigerlich folgende Fehlersuche. Und alle drei Disziplinen profitieren von der Erfahrung die du dabei sammeln kannst.

mfG
Markus

PS: Warum hast du sleep_ms reimplementiert, es gibt bereits eine entsprechende Funktion in der avr-libc (util/delay.h).

amal
28.07.2011, 15:30
[QUOTE=markusj;519616]Hey Amal,

warum probierst du es nicht einfach Mal aus?

das habe ich gemacht, aber leider der Motor dreht sich nur 100 Schritte statt 1000?

markusj
28.07.2011, 17:17
a) Das hattest du nicht geschrieben
b) Sieh dir Mal die Interruptroutine des Timers genau an, und dann such Mal, wo denn da 10x100 Schritte gemacht werden. Nirgends!
c) Ich kann auch nicht erkennen, wo da PWM gemacht werden soll ...

Du solltest dir Mal angewöhnen, etwas strukturierter zu Arbeiten. Plane vorher auf dem Papier, was in welcher Reihenfolge ablaufen soll, und wie du diese Funktionalität verteilst. So durcheinander geht das nicht gut.

mfG
Markus