Electronic lead screw con PIC18F2520

Sezione dedicata all'elettronica in generale.
Rispondi
mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Electronic lead screw con PIC18F2520

Messaggio da mimoletti » lunedì 29 novembre 2021, 21:35

Sperando di fare cosa gradita a quanti vogliano, realizzare una loro versione di ELS, pubblico alcuni spezzoni del mio codice (viewtopic.php?f=61&t=53115&hilit=electronic+lead+screw).
Il codice è stato compilato con il compilatore della Mikroe (https://www.mikroe.com/), MikroC PRO Pic (https://www.mikroe.com/mikroc-pic), gratuito fino a 2K di codice.
Per la simulazione del codice è stato usato Proteus.

La prima parte del codice che vi mostrerò ha il compito di dividere gli impulsi presenti sulla PORTA.4 del Pic, per una valore di divisione non intero, e di generare un impulso di Step della durata di 2us.

//Definizione delle variabili***************************************************
unsigned char Div1; //Definidco una variabile a 8bit
unsigned int Div2; Somma;//Definidco delle variabile a 16bit
//Routine di interruzione*******************************************************
void interrupt() {
if (TMR0IF_bit == 1){ //Discrimino l'interrupt del TMR0 dall'interrupt del TMR1
Somma = Somma + Div2; //Addizione la parte decimale del valora di divisione
if (Somma >= 10000) { //Se la Somma è = 0 > di 10000 continua altrimenti salta
Somma = Somma - 10000;//Sottrai al valore totale 10000
TMR0L = 256 - Div1 - 1;//Diminuisci di 1 il valore da caricare nel TMR0(Div1)
} else {
TMR0L = 256 - Div1; //Carica nel TMR0 il valore di Divisione
}
TMR1H = 255; //Carica in TMR1H 255
TMR1L = 246; //Carica in TMR1L 246
PORTC = 0; //Poni a 0 il bit 0 della porta C
TMR1ON_bit = 1; //Abilita il TMR1
TMR0IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR0
}
if (TMR1IF_bit == 1){ //Discrimino l'interrupt del TMR1 dall'interrupt del TMR0
PORTC = 1; //Poni a 1 il bit 0 della porta C
TMR1ON_bit = 0; //Spegni il TMR1
TMR1IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR1
}
}
//Routine principale************************************************************
void main() {
//Configurazione dell'oscillatore***********************************************
IRCF0_bit = 0; //Setto l'oscillatore interno a 4Mhz
IRCF1_bit = 1;
IRCF2_bit = 1;
PLLEN_bit = 1; //Moltiplico la frequenza dell'oscillatore interno per 4
//Configurazione dei registri***************************************************
INTCON = 0b11100000; //Abilito tutti gli interrupts non mascherati, tutti gli interrupt non mascherati delle periferiche e l'interrupt sull'overflow del TMR0
T0CON = 0b11101000; //Baypasso il prescaler del TMR0, seleziono come fonte del TMR0 il T0CKI, configuro il TMR0 a 8bit, abilito il TMR0
T1CON = 0b00000001; //Abilito il TMR1
PIE1 = 0b00000001; //Abilito l'interrupt sull'overflow del TMR1
TMR0IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR0
TMR1IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR1
TMR0H = 255; //Carica in TMRH 255
TMR0L = 255; //Carica in TMRL 255
//Inizializzazione delle porte**************************************************
Delay_ms(100);
PORTA = 0; //Initialize PORTA by clearing output data latches
//LATA = 0; //Alternate method to clear output data latches
ADCON1 = 15; //Configure A/D for digital inputs
CMCON = 7; //Configure comparators for digital inputs
TRISA = 0b11111111; //Set RA<7:0> as inputs
PORTB = 0; //Initialize PORTB by clearing output data latches
//LATB = 0; //Alternate method to clear output data latches
TRISB = 0b00000000; //Set RB<7:0> as output
PORTC = 0; //Initialize PORTC by clearing output data latches
//LATC = 0; //Alternate method to clear output data latches
TRISC = 0b11111110; //Set RC<7:1> as inputs and RC<0> as output
Div1 = 2;
Div2 = 5000;
//while(1) {
// PORTB = 0b00000000;
// Delay_ms(500);
// PORTB = 0b11111111;
// Delay_ms(500);
//}
//Metodo alternativo mediante l'uso degli operatori logici**********************
while(1) {
PORTB = PORTB^0b11111111; //Xor PORTB
Delay_ms(500);
}
}

Allego i rispettivi file.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

matteou
Senior
Senior
Messaggi: 1721
Iscritto il: giovedì 14 gennaio 2010, 12:30
Località: Udine

Re: Electronic lead screw con PIC18F2520

Messaggio da matteou » martedì 30 novembre 2021, 1:33

Che pic hai usato?

Avatar utente
hellfire39
God
God
Messaggi: 3414
Iscritto il: domenica 16 dicembre 2012, 9:04
Località: AN

Re: Electronic lead screw con PIC18F2520

Messaggio da hellfire39 » martedì 30 novembre 2021, 9:54

Se guardi il titolo del post, è scritto bello grosso #-o :D

matteou
Senior
Senior
Messaggi: 1721
Iscritto il: giovedì 14 gennaio 2010, 12:30
Località: Udine

Re: Electronic lead screw con PIC18F2520

Messaggio da matteou » martedì 30 novembre 2021, 13:10

ehm... ooops. Quando uno e' tonto #-o #-o #-o
A dire il vero l'avevo visto ma poi mi son perso per strada.
La domanda doveva essere:
da ignorante dei pic, perche' hai messo il codice del pic18f2520 mentre sull'ultima versione hai usato il pic 18f2331?
Se non sbaglio, il 2520 non ha il qei, hai deciso di postare la prima versione del programma (che l'avevi fatta per il 16f876)?
Giusto per capire, il mondo dei pic mi e' nuovo e devo leggere il programma col datasheet in mano altrimenti mi perdo.

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » martedì 30 novembre 2021, 14:49

Ciao Matteo,

La prima versione utilizzava il PIC16F876A, successivamente sono passato al PIC18F2520.
Il PIC18F2331, lo dovuto abbandonare perché non pienamente supportato dal mio programmatore.
Con piccole modifiche il codice può essere utilizzato indifferentemente sia sul PIC16F876A che sul PIC18F2520. Ma in linea generale una volta capito la logica di funzionamento si può replicare su qualunque micro.
Nell'ultima versione ho solo attivato le periferiche interne del PIC18F2520, eliminando tutto quello che non era strettamente necessario.
Questa e la mia ultima versione:
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » martedì 30 novembre 2021, 16:21

Il codice funziona in questo modo: Attivo interruput di overflow del timer 0, carico nel timer il valore di divisione, sommo la parte decimale del valore di divisione, quando la somma è uguale a 1 o maggiore di 1, aggiungo un unita al valore di divisione precedentemente scelto.
Per esempio, se il valore di divisione è 2,5, alla prima interruzione divido per 2, sommo, sommo 0 + 0,5=0,5, la condizione non è verificata, carico nel timeril valore di divisione scelto, alla seconda interruzione sommo 0,5 + 0,5= 1, la condizione è verificata, sottraggo 1 al risultato, e aggiungo 1 al valore di divisone che diventerà 3, e cosi via quindi dividerà prima per 2 e poi per 3 e cosi via.
Il Timer 1 invece lo uso per generare impulso di stepper della durata desiderata.
L'impulso è capovolto, per evitare che il Dir, che leggo nella routine di interruzione, sia coincidente con il fonte di salita dell'impulso di step. Quindi al momento dell'interruzione avrò un fronte di discesa, seguito da un fronte di salita. L'intervallo di tempo tra i due fronti è determinato dal valore caricato ne Timer1.

Spero di essermi spiegato.

Ho scelto di utilizzare il TIMER essenzialmente per un motivo: Avevo bisogno di una di un'encoder con una risoluzione il più elevata possibile, non volevo rinunciare per nessuna ragione al micropasso sullo stepper. Utilizzando il Timer l'intervallo di tempo tra un'interrupt e quello successivo, è in funzione oltre che alla risoluzione dell'encoder, anche al numero di divisione scelto. Nel prossimo post aggiungerò la porzione di codice che si occupa di "memorizzare" la posizione angolare.

Aggiungo un file che ho utilizzato per il calcolo dei valori di divisione.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » mercoledì 1 dicembre 2021, 17:03

//Definizione delle variabili***************************************************
unsigned char Div1; Pause; Index_Flag_bit; Selec_Mode; In_Dir;//Definidco una variabile a 8bit
unsigned int Div2; Somma; Count;//Definidco delle variabile a 16bit
//Routine di interruzione*******************************************************
void interrupt() {
if (TMR0IF_bit == 1){ //Discrimino l'interrupt del TMR0 dall'interrupt del TMR1
if ((Pause == 0)||(Index_Flag_bit == 1)){ //Se nella fase di Play o Index flag = 1
if (Selec_Mode == 0){ //Se attiva la modalita avanzamento
PSA_bit = 1; //Attiva il prescaler
TMR0L = 6; //Carica 6 nel Timer 0
}
if (Selec_Mode == 1){ //Se attiva la modalita filettatura
PSA_bit = 0; //Attiva il prescaler
TMR0L = 255; //Carica 255 nel Timer 0
if (In_Dir == 0) { //Se gira in senso antiorario
Count ++; //Incrementa la variabile Count
if (Count == 2001) {//Se Count = 2001
Count = 1; //Forza a 1
}
} else {
Count --; //Decrementa la variabile Count
if (Count == 0) { //Se Count = 0
Count = 2000; //Forza a 2000
}
if (Count == 2000) {//Se Count = 2000
Index_Flag_bit = 0;//Setta a 0 la variabile Index Flag
} else {
Index_Flag_bit = 1;//Setta a 0 la variabile Index Flag
}
}
}
} else {
Somma = Somma + Div2; //Addizione la parte decimale del valora di divisione
if (Somma >= 10000) { //Se la Somma è = 0 > di 10000 continua altrimenti salta
Somma = Somma - 10000;//Sottrai al valore totale 10000
TMR0L = 256 - Div1 - 1;//Diminuisci di 1 il valore da caricare nel TMR0(Div1)
} else {
TMR0L = 256 - Div1; //Carica nel TMR0 il valore di Divisione
}
TMR1H = 255; //Carica in TMR1H 255
TMR1L = 246; //Carica in TMR1L 246
PORTC = 0; //Poni a 0 il bit 0 della porta C
TMR1ON_bit = 1; //Abilita il TMR1
TMR0IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR0
}
}
if (TMR1IF_bit == 1){ //Discrimino l'interrupt del TMR1 dall'interrupt del TMR0
PORTC = 1; //Poni a 1 il bit 0 della porta C
TMR1ON_bit = 0; //Spegni il TMR1
TMR1IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR1
}
}
//Routine principale************************************************************
void main() {
//Configurazione dell'oscillatore***********************************************
IRCF0_bit = 0; //Setto l'oscillatore interno a 4Mhz
IRCF1_bit = 1;
IRCF2_bit = 1;
PLLEN_bit = 1; //Moltiplico la frequenza dell'oscillatore interno per 4
//Configurazione dei registri***************************************************
INTCON = 0b11100000; //Abilito tutti gli interrupts non mascherati, tutti gli interrupt non mascherati delle periferiche e l'interrupt sull'overflow del TMR0
T0CON = 0b11101010; //Baypasso il prescaler del TMR0, seleziono come fonte del TMR0 il T0CKI, configuro il TMR0 a 8bit, abilito il TMR0
T1CON = 0b00000001; //Abilito il TMR1
PIE1 = 0b00000001; //Abilito l'interrupt sull'overflow del TMR1
TMR0IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR0
TMR1IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR1
TMR0H = 255; //Carica in TMRH 255
TMR0L = 255; //Carica in TMRL 255
//Inizializzazione delle porte**************************************************
Delay_ms(100);
PORTA = 0; //Initialize PORTA by clearing output data latches
//LATA = 0; //Alternate method to clear output data latches
ADCON1 = 15; //Configure A/D for digital inputs
CMCON = 7; //Configure comparators for digital inputs
TRISA = 0b11111111; //Set RA<7:0> as inputs
PORTB = 0; //Initialize PORTB by clearing output data latches
//LATB = 0; //Alternate method to clear output data latches
TRISB = 0b00000000; //Set RB<7:0> as output
PORTC = 0; //Initialize PORTC by clearing output data latches
//LATC = 0; //Alternate method to clear output data latches
TRISC = 0b11111110; //Set RC<7:1> as inputs and RC<0> as output
Div1 = 2;
Div2 = 5000;
//while(1) {
// PORTB = 0b00000000;
// Delay_ms(500);
// PORTB = 0b11111111;
// Delay_ms(500);
//}
//Metodo alternativo mediante l'uso degli operatori logici**********************
while(1) {
PORTB = PORTB^0b11111111; //Xor PORTB
Delay_ms(500);
}
}
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » mercoledì 1 dicembre 2021, 17:12

Ho aggiunto la parte che si occupa della "memorizzazione" della posizione angolare. In realtà non memorizzo nulla, riprende semplicemente da dove aveva interrotto.
Ciclicamente passo dalla fase di Pause a quella di Play (ossia di divisione) in funzione del valore delle due variabili: Pause and Index Flag.
A sua volta la fase di Pause e divisa in due sezioni:
Mode 0, per la modalità di avanzamento, carico nel Timer 0 un valore tale che abilitando il prescaler e scegliendo un opportuno valore di divisione,
potrà uscire da questa modalità, solo dopo che il mandrino avrà compiuto esattamente un giro completo.
Mode 1, disabilito il prescaler e carico nel Timer il valore 255, ottenendo un un'interrupt, ad ogni fonte di salita, potrà uscire da questa condizione solo se la variabile Count avrà, esattamente valore 2000 e quindi, solo dopo che il mandrino avrà compiuto esattamente un giro.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

matteou
Senior
Senior
Messaggi: 1721
Iscritto il: giovedì 14 gennaio 2010, 12:30
Località: Udine

Re: Electronic lead screw con PIC18F2520

Messaggio da matteou » giovedì 2 dicembre 2021, 1:46

Mi ci vuole un po' di tempo per capire il codice.
Non mi e' chiaro come leggi la direzione dell'encoder (In_dir) e come fai il x4 sugli impulsi dell'encoder.

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » giovedì 2 dicembre 2021, 15:57

La direzione dell'encoder la leggo all'interno della routine di interrupt.
Nel riscrivere il codice ho definito In_Dir come una variabile per sbaglio, ma avrei dovuto scrivere: sbit In_Dir at PORTA.B3 (Significa durante la compilazione sostituisci In_Dir con PORTA.B0);
Utilizzando il Timer non è possibile duplicare o quadruplicare la risoluzione dell'encoder, infatti nella prima versione avevo utilizzato una porta Exor per duplicare la risoluzione ingresso.
Come tutte le scelte utilizzare il Timer ha dei Pro e dei Contro.
Il Timer consente di aumentare notevolmente la frequenza massima a cui può funzionare il sistema, perché la frequenza delle interruzioni, dipenderà dalla velocita di rotazione del mandrino e dal numero di divisione impostato.
Per esempio, se guardi la tabella in Excel, vedrai che con passo 0.2mm a giro, in avanzamento e con una velocità di rotazione di 3000 giri/minuto, l'intervallo tra una interruzione e quella successiva sarà, di circa 125us, 1/[(3000/60)X2000]X12,5
3000 sono i giri al minuto dell'encoder, 60 i secondi in 1 minuto, 2000 la risoluzione dell'encoder, 12,5 il valore di divisione.
Ora dirai, bene questo succede in avanzamento quando il valore di divisione minimo è 12,5, ma invece cosa accade quando il valore è prossimo a 1 come succede con i passi più grossi?
Succede che il tuo limite non sarà più la frequenza delle interruzioni ma più tosto la velocita di rotazione del passo passo, che anche implementando correttamente le rampe di accelerazione e decelerazione, potrà al massimo fare non più di 500-600 giri al minuto.
Facciamo due conti (vedi la tabella), con passo 2,5mm la vite farà girerà 1,25 volte più velocemente del mandrino, con una velocità di rotazione del mandrino di 500 giri al minuto, il motore stepper dovrà girare a 625 giri al minuto.
Quindi il problema e sentito soprattutto in avanzamento, ed il timer ti consente di aumentare in modo notevole la frequenza di funzionamento del tuo sistema.
Di contro non puoi duplicare o quadruplicare la risoluzione dell'encoder.
Capire il letteralmente il codice non è importante, devi capire quello che faccio, successivamente lo potrai replicare su qualunque sistema e con qualunque linguaggio.

La Routine di ISR e essenzialmente suddivisa in due blocchi:

La prima sezione "memorizza" la posizione angolare, riprendendo esattamente dalla stessa posizione angolare da dove aveva interrotto.
La seconda esegue la divisione degli impulsi.

Ti è chiaro come svolgo queste due operazioni?
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » giovedì 2 dicembre 2021, 15:58

Se preferisci lo posso riscrive anche in Basic.
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

matteou
Senior
Senior
Messaggi: 1721
Iscritto il: giovedì 14 gennaio 2010, 12:30
Località: Udine

Re: Electronic lead screw con PIC18F2520

Messaggio da matteou » domenica 5 dicembre 2021, 13:52

Vediamo se ho capito giusto (consideriamo che usi l'encoder x1, collegato direttamente al pic)
1. un canale (diciamo il canale A) lo colleghi al clock di un timer. Ogni impulso dell'encoder fara' contare il timer.
2. metti il contatore del timer0 a 255, cosi' va in overflow ogni volta che arriva l'impulso dell'encoder. Ogni volta che che va in overflow, incrementi il conteggio degli impulsi
3. arrivato a 2000 impulsi, setti il flag Index_Flag_bit, sarebbe il tuo "zero" dove partire con la filettatura
4. se devi aspettare 7.5 impulsi di encoder per fare un passo di stepper, imposti il contatore del timer0 a 255-7 oppure 255-8 (a seconda di quanto vale SOMMA)
5. se il timer0 va in overflow (quindi sono arrivati 7 o 8 impulsi di encoder) fai partire il timer1 che sparera' lo step per il motore passopasso.
Fin qua ho capito giusto?
Se si, ho un po' di domande:
1. non capisco quando chiami la funzione void interrupt(). Non ho ben capito le impostazioni dei timer (mi son perso) quindi magari mi sfugge qualcosa.
Da quello che capisco dal codice, vai a leggere TMR0IF_bit (che dovrebbe indicare l'overflow del timer0) e leggi l'encoder ecc...
Negli avr, se il timer va in overflow (o altre condizioni che puoi scegliere) puoi fargli chiamare direttamente la relativa routine di interrupt, senza dover stare a leggere (e poi resettare) il bit che indica l'overflow. Nei pic non c'e' questa funziona? Oppure hai scelto di fare cosi' per qualche motivo?
2. non mi e' chiaro perche' conti gli impulsi dell'encoder in fase di play o se hai gia' raggiunto l'index.
Non dovrebbe essere il contrario?
Fase di pause (o quando non ho ancora ripreso l'index) ---> conto gli impulsi
fase di play (e quando ho ripreso l'index) ----> conto le divisioni e sparo il segnale di step
3. perche' se imposti la funzione avanzamento non usi piu' l'impulso dell'encoder come clock? PSA_bit = 1, se ho capito bene, fa usare il clock interno come fonte per il timer. Quindi il timer contera' indipendentemente dall'encoder, come mantieni il sincronismo?
4. il codice che hai messo non e' quello "reale" ma l'hai riscritto per pubblicarlo, giusto? Quindi le mie domande 2 e 3 potrebbero essere errori nella ri-scrittura del programma?

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » lunedì 6 dicembre 2021, 22:30

Scusami se non sono abbastanza chiaro nelle spiegazioni, cercherò fare del mio meglio.

Nel PIC18F il codice dell'interrupt inizia obbligatoriamente da una locazione di memoria fissa pre definita (vettore di interrupt), con due livelli di priorità, qualunque sia la fonte che lo ha generato. Quindi che sia stato generato dal Timer0 o dal Timer1, il codice inizia sempre nello stesso punto, a parità di livello di priorità. Quindi la prima cosa che faccio è discriminare quale è stata la fonte di interrupt. Successivamente alla fine del codice di interrupt bisogna cancellare il bit di flag della relativa periferica.

La routine di interrupt è divisa in due sezioni: La prima sezione si occupa di "memorizzare" la posizione angolare (parte in rosso), la seconda esegue la divisione degli impulsi (parte in verde) e di generare l'impulso di step:

void interrupt() {
if (TMR0IF_bit == 1){ //Discrimino l'interrupt del TMR0 dall'interrupt del TMR1
if ((Pause == 0)||(Index_Flag_bit == 1)){ //Se nella fase di Play o Index flag = 1
if (Selec_Mode == 0){ //Se attiva la modalita avanzamento
PSA_bit = 1; //Attiva il prescaler
TMR0L = 6; //Carica 6 nel Timer 0
}
if (Selec_Mode == 1){ //Se attiva la modalita filettatura
PSA_bit = 0; //Attiva il prescaler
TMR0L = 255; //Carica 255 nel Timer 0
if (In_Dir == 0) { //Se gira in senso antiorario
Count ++; //Incrementa la variabile Count
if (Count == 2001) {//Se Count = 2001
Count = 1; //Forza a 1
}
} else {
Count --; //Decrementa la variabile Count
if (Count == 0) { //Se Count = 0
Count = 2000; //Forza a 2000
}
if (Count == 2000) {//Se Count = 2000
Index_Flag_bit = 0;//Setta a 0 la variabile Index Flag
} else {
Index_Flag_bit = 1;//Setta a 0 la variabile Index Flag
}
}
}

} else {
Somma = Somma + Div2; //Addizione la parte decimale del valora di divisione
if (Somma >= 10000) { //Se la Somma è = 0 > di 10000 continua altrimenti salta
Somma = Somma - 10000;//Sottrai al valore totale 10000
TMR0L = 256 - Div1 - 1;//Diminuisci di 1 il valore da caricare nel TMR0(Div1)
TMR0L = 256 - Div1; //Carica nel TMR0 il valore di Divisione
}
TMR1H = 255; //Carica in TMR1H 255
TMR1L = 246; //Carica in TMR1L 246
PORTC = 0; //Poni a 0 il bit 0 della porta C
TMR1ON_bit = 1; //Abilita il TMR1
TMR0IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR0
}
}
if (TMR1IF_bit == 1){ //Discrimino l'interrupt del TMR1 dall'interrupt del TMR0
PORTC = 1; //Poni a 1 il bit 0 della porta C
TMR1ON_bit = 0; //Spegni il TMR1
TMR1IF_bit = 0; //Resetta il bit di Flag dell'interrupt del TMR1
}
}

A sua volta la prima sezione è divisa in altre due sezione:
Avanzamento: in cui abilito il prescaler e carico nel Timer un valore tale da generare un'interrupt ogni giro completo del mandrino. Di conseguenza dopo aver premuto il pulsante di Play, potrà uscire da questa condizione solo dopo che il mandrino avrà compiuto esattamente un giro completo da dove si era interrotto.
Filettatura: disabilito il prescaler e carico nel timer un valore tale da generare un'interrupt per ogni fonte di salita dell'encoder. Ogni 2000 impulsi e quindi per ogni giro completo resetto la variabile Index Flag, di conseguenza dopo aver premuto il pulsante di Play, potrà uscire da questa condizione solo dopo che il mandrino avrà compiuto esattamente un giro completo da dove si era interrotto.

Nella routine principale quando viene premuto il Pulsante Pause, setto a 0 la variabile Pause e ad 1 la variabile Index Flag. Sospendo la fase di divisione e inizia la fase di Pause. Ora quando nella routine principale Premo Play setto la variabile Pause a 1 e da quel momento in poi riprenderà esattamente dalla stessa posizione angolare da cui si era interrotto, grazie alla variabile Index Flag. perché continuerò a rimanere bloccato in quella fase fino a quando la variabile Index Flag non sarà uguale a 0.

Il bit PSA serve solo ad abilitare il o disabilitare il prescaler. Avendolo configurato per funzionare ad 8bit, per poter generare un'interruzione ogni 2000 impulsi abilito il prescaler, con un valore di divisione di 8, e carico nel Timer valore 6 avrò un interrupt esattamente ogni 2000 impulsi (256-6)X8.

Il codice è reale, lo sto aggiungendo a spezzoni per fartene comprendere il funzionamento. Nella routine di Interrupt manca solo la sezione che conta gli step nella fase di Paly e la gestione del Dir per le inversioni durante la fase di sincronismo, che aggiungerò nei prossimi messaggi.

Nella Routine principale ci sono le tabelle che uso per caricare i valori di divisione, la lunghezza dell'avanzamento e della filettatura, la gestione dei pulsanti, del display, e del Reverse, e della rampa di accelerazione di quest'ultimo.

Ma il cuore del sistema è la Routine di interrupt, che ti permette grazie al Timer di mantenere un'elevata frequenza di funzionamento. In teoria potrebbe arrivare tranquillamente ad 1Mhz.

Ovviamente tutto ha un prezzo, nella fase di filettatura la lunghezza di quest'ultima dovrà essere necessariamente un multiplo del passo.
Lo puoi verificare anche meccanicamente con il tuo tornio. Fai in questo modo:
Azzera il nonio del carrellino longitudinale portando la vite in presa, girando il volantino in senso antiorario.
Imposta passo 2mm per esempio, innesta la vite madre, avvicina l'utensile al pezzo in modo da segnarlo, ora gira il mandrino a mano in senso antiorario di una decina di giri. Allontana l'utensile dal pezzo. Ora ti accorgerai che se sposti il carrellino longitudinale, a passi di 2mm, potrai riprenderai sempre esattamente il filetto.
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

matteou
Senior
Senior
Messaggi: 1721
Iscritto il: giovedì 14 gennaio 2010, 12:30
Località: Udine

Re: Electronic lead screw con PIC18F2520

Messaggio da matteou » martedì 7 dicembre 2021, 2:29

Porta pazienza se non capisco... gia' con gli avr sono ignorante, con i pic sono completamente analfabeta #-o
Se poi ho solo un pezzo di codice il rischio di perdermi per strada e' forte.
Non conoscevo il modo di gestire gli interrupt del pic. Ok, una cosa e' chiara.
Ok per il discorso prescaler, ho letto come funziona e mi e' chiaro. Non sapevo che anche il clock esterno passasse per il prescaler, pensavo solo il clock interno.
Chiaro anche il discorso del conteggio degli impulsi o delle divisioni. Mi aveva tratto in inganno il commento "//Se nella fase di Play o Index flag = 1".

mimoletti
Senior
Senior
Messaggi: 1098
Iscritto il: giovedì 4 dicembre 2008, 17:56
Località: Torre del Greco (NA)

Re: Electronic lead screw con PIC18F2520

Messaggio da mimoletti » mercoledì 8 dicembre 2021, 21:14

Nei prossimi giorni, ti scrivo il codice quasi completo, in modo che tu lo possa compilare, con la versione gratuita del compilatore della Mikroe.
Intanto ti allego lo scheck per arduino, realizzato dal mio amico. Lui ricorda poco o niente di quello che ha fatto, quindi ti dovrai arrangiare da solo.
Non hai i permessi necessari per visualizzare i file e le foto allegati in questo messaggio. Per visualizzare tali file devi registrarti ed effettuare il Login
Tornio Wabeco D6000; Fresa Wabeco F1210; Segatrice Nebes TM125 Inverter; Tavola a dividere Vertex HV-6,Morsa meccnica Allen MAP/78-N

https://www.youtube.com/watch?v=cobEZI8KvOk

73 IU8NNS.

Rispondi

Torna a “Elettronica”