Grazie Umbez per la dritta.
Pensavo di fare anch'io una cosa simile, fin'ora ho usato i delay perche' ho scopiazzato dal programma di McMax e il suo lavoro lo faceva (ma era gia' in programma di cambiare).
Ho modificato un po' il tuo codice, adattandolo alle mie esigenze.
Al solito avevo messo l'incremento di passi_effettuati nell'isr ma mi dava risultati strani (solo a McMax non crea problemi modificare una variabile in una isr e leggerla nel main
).
Il timer 2 e' impostato per mettere alto OC2B al match e metterlo basso al bottom. Il top e' OCR2A. OCR2B e' sempre uguale a OCR2A-1 cosi' ho il mio bell'impulso che resta alto per 8uS (prescaler 1/128) indipendentemente dalla frequenza del pwm.
Alla funzione StepperMoveToPosition passo il numero di step che mi servono. Se il movimento che devo fare e' piccolo, parto senza rampa, altrimenti parto in rampa.
Il ciclo while dura finche' non ho effettuato tutti i passi che mi servono. Resto in attesa dell'avvenuto match (quindi ho un impulso pwm), se sono in accelerazione vado a diminuire progressivamente OCR2A/B cosi' aumenta la frequenza del pwm. Se sono quasi arrivato al numero di passi voluto, aumento OCR2A/B in modo che la frequenza aumenti e il motore deceleri.
Alla fine reimposto il timer2 per poterlo usare nella modalita' "one shot".
Al simulatore funziona e all'oscilloscopio funziona.
Anche ne programma intero non dovrebbe avere problemi (spero).
Codice:
unsigned int passi_effettuati = 0;
bool flag_accel=false;
volatile bool flag_pwm=0;
void setup()
{
pinMode(3, OUTPUT);
clearPWM();
StepperMoveToPosition(4000); // muovo lo stepper di 4000 passi, per prova
}
void clearPWM() // pulisco i registri del timer2
{
TCCR2A=0;
TCCR2B=0;
TIMSK2=0;
OCR2A=0;
OCR2B=0;
TCNT2=0;
}
void startPWM()
{
TCCR2A = _BV(COM2B0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); //set oc2b on compare match, clear at bottom
TCCR2B = _BV(WGM22) | _BV(CS22) | _BV(CS20); // fast pwm mode 7, top ocr2a, prescaler 1/128
TIMSK2 = _BV(OCF2B); // interrupt when compare match
}
ISR ( TIMER2_COMPB_vect)
{
flag_pwm=1;
}
void StepperMoveToPosition(unsigned int passi_richiesti) //sposta il carro di "passi_richiesti" passi. Usato per il ritorno del carro e per gli stops
{
passi_effettuati=0;
if (passi_richiesti<=800)
{
OCR2A=50; // se i passi richiesti sono meno di 800, parto in bomba (2500Hz, ~187rpm @ 800steps/giro)
OCR2B=OCR2A-1;
flag_accel=false;
}
else // se i passi da fare sono >800 parto in rampa - da 550 (ocr2a=226) a 4800Hz (ocr2a=26), da 41 a 360 rpm in 200 step
{
OCR2A=226;
OCR2B=OCR2A-1;
flag_accel=true;
}
startPWM(); // il timer2 parte
while (passi_effettuati<=passi_richiesti)
{
if (flag_pwm) //
{
flag_pwm=0;
passi_effettuati++;
if (flag_accel) // se devo fare piu' di 800 passi
{
if (passi_effettuati<=200 && OCR2A>=26)
{
OCR2A--; // accelerazione
OCR2B=OCR2A-1;
}
if ((passi_richiesti-passi_effettuati)<=200 && OCR2A<=226)
{
OCR2A++; //decelerazione
OCR2B=OCR2A-1;
}
}
}
}
clearPWM();
}
void loop()
{
}