Buongiorno a tutti,
ho un problema stranissimo in un codice. Si tratta di un Arduino Nano utilizzato per controllare un tornio che mi sono autocostruito.
In ingresso ho, tramite interrupt, un sensore di velocità costituito dalla solita rotellina che interrompe il fascio di luce. Misuro il tempo tra i "tic" (faccio la media degli ultimi 20 per avere una misura più affidabile) e così ricavo la velocità di rotazione del motore. La confronto con la velocità desiderata e, applicando una semplice operazione matematica, vado a modificare l'uscita in pwm di un pin che pilota, attraverso un mosfet, il motore. In questo modo posso mantenere costante la velocità del motore al variare del carico meccanico.
Fin quì tutto bene e tutto facile. Il problema è che lo spezzone di codice funziona bene solo se, all'interno del ciclo di verifica e controllo, metto delle istruzioni Serial.print che mi inviano sulla seriale le variabili utilizzate dal ciclo. Se tolgo i Serial.print il codice commette errori, sembra come se non riesca a leggere correttamente il valore di alcune variabili, quindi il calcolo della potenza da erogare fallisce ed il motore viene azionato alla massima velocità.
In calce c'è l'intero codice, le righe in questione sono quelle con Serial.print("Output: ");
Per completezza, vi segnalo che questo Arduino comunica via I2C con un secondo Arduino nano che gestisce l'interfaccia utente. Legge anche la corrente assorbita dal motore (per controllare che non superi i valori ammessi dal motore e dall'alimentatore) e pilota anche un motore stepper per azionare il carrello portautensili.
Il codice è sufficientemente commentato, se però qualcosa non vi è chiaro non esitate a chiedere.
La mia domanda è: perché se elimino (commento) il blocco dei Serial.print l'elaborazione produce risultati non corretti?
Grazie
Carlo
p.s. il codice è comunque incompleto, ci sono funzioni ereditate da una versione precedente e che non mi occorrono e che devo eliminare e ci sono altre cose che devo ancora implementare.
/*
* Programma per la gestione del tornio.
* Utilizza un motore stepper per il carrello ed un motore DC per il mandrino.
* Il motore del mandrino è collegato ad un encoder da 20 impulsi giro ed aziona il mandrino attraverso una riduzione 1:4.
* La velocità del motore DC viene controllata in PWM
* Lo stepper muove una vite senza fine attraverso una riduzione 1:3. Lo stepper viene azionato senza una libreria dedicata.
* Il singolo passo dello stepper corrisponde ad un avanzamento del carrello do 55,6 millesimi di mm.
* Il sistema interagisce con l'utente attraverso un secondo arduino, che gestisce un modulo display + input
* dal secondo arduino arrivano i comandi per impostare la velocità del motore DC ed i movimenti del carrello
* al secondo arduino vengono inviati i dati sulla velocità corrente del motore e sulla posizione del carrello
* la comunicazione avviene in I2C attraverso la libreria WIRE. Questo arduino è SLAVE
*
* Le connessioni sono:
* encoder del motore DC: pin 2
* PWM del motore DC: pin 3
* Stepper : pin 7,8,9,10
* Interruttori di fine corsa: 11 e 12
* Ingresso amperometro A1
* Ingresso potenziometro A2
*
* todo list. Togliere tutti i riferimenti a Potenziometro
*
*
*
*/
#include <Wire.h>
// Associazione pin di I/O
// motore mandrino
const byte PinMotore = 3; // Pin di output PWM del motore DC del mandrino
const byte encoderPin1 = 2; // Encoder del motore DC può essere solo 2 o 3, in quanto supportano l'interrupt.
const byte ampere_in = A1; // Ingresso usato per misurare la corrente assorbita dal motore del mandrino
// Ponte ad H del motore Stepper:
const byte motor_pin_1 = 8;
const byte motor_pin_2 = 9;
const byte motor_pin_3 = 10;
const byte motor_pin_4 = 11;
// fine corsa del carrello
const byte fineDx = 7;
const byte fineSx = 6;
// altri pin
const byte pot_in = A2; // imposto il pin di ingresso per il potenziometro
// variabili usate per la comunicazione I2C
volatile byte Codai2C [32]; // buffer di ingresso
volatile byte Codai2C_len = 0; // lunghezza del buffer di ingresso
byte Codai2C_tmp [64]; // buffer di lavoro, riceve dal buffer di ingresso
byte Codai2C_tmp_len = 0; // lunghezza del buffer di lavoro
byte Elem_i2C_wrk = 0; // appoggio per l'elemento del buffer in lavorazione. Più comodo che lavorare sull'array
byte Risposta[32] ; // buffer di uscita
byte Risposta_ptr ; // lunghezza del buffer di uscita.
// Imposto le variabili per la gestione del motore
int Setpoint = 0; // utilizzata per definire la velocità target effettiva. Deriva dalla MotorSpeedImpostata ed è influenzata dall'assorbimento di corrente
int MotorSpeedCorrente = 0; // velocità corrente del motore.
int Output = 0; // valore del PWM applicato al motore
int Output_tmp = 0; // temporanea di appoggio per l'output del motore
unsigned long CheckPrecedente = 0; // variabile per la temporizzazione dei cicli di verifica velocità del motore
int MotorAmpereCorrente = 0; // Assorbimento corrente in Ampere del motore.
const int MaxCorrenteMotore = 500; // Massimo assorbimento di corrente del motore, da impostare dopo prove sperimentali con l'alimentatore
const int MotorAccellMax = 20; // accelerazione massima tollerata dall'alimentatore, da impostare dopo prove sperimentali con l'alimentatore
int Passaggio = 0; // conteggia quante misurazioni di corrente sono state sopra la soglia massima e quindi sono state causa di limitazione del numero di giri del motore
int OutputPrec = 0; // memorizza il precedente valore di output per il motore, necessita alla avviolento()
double delta = 0; // differenza tra la velocità impostata e quella corrente
//Imposto le variabili da esportare nel modulo di gestione del motore e dello stepper
// Motore mandrino
int MotorSpeedImpostata = 0; // velocità attesa del mandrino, espressa in giri al minuto
bool MotoreAcceso = false; // Stato del motore del mandrino
// Stepper
int StepperSpeed = 0; // velocità del carrello, espresso in millesimi di mm per giro del mandrino
long PercorsoDaFare = 0; // Persorso che deve compiere il carrello, alla velocità impostata da StepperSpeed o dal Potenziometro
int PosizioneAttualeCarrello = 0; // posizione corrente del carrello, rispetto alla posizione di partenza
bool Potenziometro = false; // definisce se il potenziometro può azionare il carrello
//long PosizionefinaleCarrello = 0; // posizione di destinazione del carrello, rispetto alla posizione di partenza
//long EstremoSinistroCarrello = 0; // limite sinistro della corsa del carrello, rispetto alla posizione di partenza
//long EstremoDestroCarrello = 0; // limite destro della corsa del carrello, rispetto alla posizione di partenza
//static long LunghezzaCarrello = 10000; // Lunghezza fisica del carrello, da impostare bene dopo averla misurata.
// definisco le dimensioni dei singoli passi elementari
const byte NumeroSettori = 80; // numero di settori dalla ruota (20) dell'encoder del motore DC * il rapporto di trasmissione (4)
const float LunghezzaPasso = 55.6; // espressa in millesimi di millimetro
float MM_Per_Giro = 0; // quanti mm devono essere percorsi per ogni giro
float MM_Per_Settore = 0; // quanti mm devono essere percorsi per ogni settore dell'encoder
volatile float MM_DaFare = 0; // coda di mm ancora da percorrere
float MM_Temp = 0; // variabile di appoggio
long encoderValue = 0; // valore corrente dell'encoder motore. Deve essere long perché¨ richiede il segno.
long time1 ; // usata nella routine di avanzamento dello stepper per non superare la velocità massima
volatile long t[20] ; // usata nell'interrupt per calcolare la velocità del motore DC. Memorizza i tempi degli ultimi 20 passaggi.
volatile byte tic = 0 ; // usata nell'interrupt per calcolare la velocità del motore DC. Memorizza il passaggio corrente.
long t0_tmp; // usata nella giri() per calcolare la velocità del motore DC
int vel ; // usata nella giri() per calcolare la velocità del motore DC
//const volatile long TempoMinimo = 7000; // tempo minimo in microsecondi tra due step
long TempoMinimo = 7000;
//volatile long PassoCorrente =0; // passo corrente dello stepper del carrello 0,1,2,3
int PassoCorrente=0;
boolean IntEnable = false; // Gli interrupt dell'encoder del mandrino sono abilitati?
int passi = 0;
int passitotali = 0;
boolean CarrelloAutomatico = false; // il carrello si muove automaticamente con il motore, secondo il passo ed il verso impostati, oppure manualmente secondo l'impostazione del potenziometro.
int pot = 0;
int direzionePot = 0;
int i,k; // variabili di iterazione dei cicli for
byte Azione; // variabile di appoggio per la gestione delle sub-azioni all'interno della routine di gestione dei comandi provenienti da I2C
void setup() {
// inizializzo la seriale ed il led per debug.
//Serial.begin(115200);
// inizializzo il riferimento per l'ingresso analogico per la misurazione della corrente assorbita dal motore
analogReference(INTERNAL);
//inizializzo la libreria
Wire.setWireTimeout(3000, true);
//imposto l’indirizzo dello slave
Wire.begin(0x04);
//eventi per la ricezione del dato
//e per la richiesta del dato
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
//inizializzo le porte dello Stepper
pinMode(motor_pin_1, OUTPUT);
pinMode(motor_pin_2, OUTPUT);
pinMode(motor_pin_3, OUTPUT);
pinMode(motor_pin_4, OUTPUT);
digitalWrite(motor_pin_1, LOW);
digitalWrite(motor_pin_2, LOW);
digitalWrite(motor_pin_3, LOW);
digitalWrite(motor_pin_4, LOW);
// Inizializzo la parte relativa all'encoder motore
pinMode(encoderPin1, INPUT);
digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
// abilito l'interrupt per la lettura dell'encoder motore del mandrino
attachInterrupt(digitalPinToInterrupt(encoderPin1), encoderMotore, FALLING );
// inizializzo in PullUp i due switch di fine corsa
pinMode(fineDx, INPUT);
digitalWrite(fineDx,HIGH);
pinMode(fineSx, INPUT);
digitalWrite(fineSx,HIGH);
// inizializzo il pin di comando del motore
pinMode(PinMotore, OUTPUT);
setPwmFrequency(PinMotore, 1); // Imposto la frequenza del PWM a 31250Hz, in modo da eliminare il fischio del motore.
// verificare se è possibile scendere
// A codice consolidato, sostituire la funzione alla sola riga necessaria.
analogWrite(PinMotore,0);
//Serial.println("Avvio");
MotoreAcceso = true;
MotorSpeedImpostata = 500;
// impostazioni di default, necessarie per l'utilizzo del tornio senza il modulo di comando
// CarrelloAutomatico = true;
// pot = 3;
// direzionePot=-1;
}
void loop() {
// elaboro il movimento del carrello, se automatico
//EseguiCarrelloAutomatico();
// eseguo il controllo della velocità del motore ogni 200 millisecondi (5 volte al secondo) per evitare variazioni troppo brusche
MotorAmpereCorrente = Ampere();
// Serial.println(MotorAmpereCorrente);
if (millis() > CheckPrecedente + 100){
CheckPrecedente = millis();
if (MotoreAcceso){
MotorSpeedCorrente = Giri();
Serial.begin(115200);
Serial.print("MotorSpeedCorrente: ");
Serial.println(MotorSpeedCorrente);
Setpoint = MotorSpeedImpostata;
// verifico gli assorbimenti di corrente
if (MotorAmpereCorrente > MaxCorrenteMotore){ // il motore assorbe troppo, ne riduco i giri del 35% ad ogni passaggio, quindi azzero dopo 300 mS in caso di blocco meccanico.
Setpoint = MotorSpeedImpostata * (0,7 - Passaggio/3);
Setpoint = max(Setpoint, 0); // evito numeri negativi
Passaggio++;
}else{
Setpoint = MotorSpeedImpostata;
Passaggio = 0;
}
// occorre alla avviolento()
OutputPrec = Output;
// calcolo la differenza tra la velocità corrente e quella voluta, per applicare la dovuta correzione alla potenza del motore
delta = ((Setpoint - MotorSpeedCorrente)/20);
Output_tmp=Output + int(delta);
Output = constrain(Output_tmp,0,255); // mi accerto che l'output sia compreso nell'intervallo ammesso
Output = avviolento(); // eseguo un avvio lento per evitare l'impuntamento dell'alimentatore
if (MotorSpeedCorrente==0){Output=min(Output,50);} // non permette di arrivare a dare la massima potenza al motore se questo non si muove
// non rimuovere questi print, senza il motore funziona male. (da indagare)
Serial.print("Output: ");
Serial.print(int(Output));
Serial.print(" Output_tmp: ");
Serial.print(int(Output_tmp));
Serial.print(" delta: ");
// Serial.println(int(delta));
analogWrite(PinMotore, int(Output));
Serial.end();
// verifico se il motore è fermo, ovvero se l'ultimo interrupt sia stato ricevuto oltre 200 mS prima di adesso
// nel caso, imposto tutto a zero
noInterrupts(); // disabilito gli interrupt per evitare che ci siano sovrapposizioni con eventuali movimenti manuali del mandrino
if((micros()-t[0])>200000){
// azzero tutte le letture precedenti
for (i=0;i<20;i++){
t[i] =0;
}
// imposto la velocità corrente a zero
MotorSpeedCorrente =0;
}
interrupts();
}else{
Output=0; // necessario anche per effettuare un nuovo riavvio lento.
analogWrite(PinMotore, Output); // spengo il motore
MotorSpeedCorrente = 0;
}
}
//elaboro il dato letto dal bus i2C
/*
il dato è strutturato con un byte di direttiva, seguito da altri byte con i dati.
In caso di richiesta dati, questa routine prepara la risposta, che verrà inviata quando arriverà la requestEvent()
*/
if (Codai2C_len>0) { // c'è almeno un byte proveninte da I2C da aggiungere a quelli da lavorare
noInterrupts();
for (i=0;i<Codai2C_len;i++){
Codai2C_tmp[Codai2C_tmp_len+i] = Codai2C[i+1]; // trasferisco i byte ricevuti per elaborarli localmente
}
Codai2C_tmp_len = Codai2C_tmp_len + Codai2C_len ; // aggiorno la lunghezza del buffer dei byte da lavorare
Codai2C_len = 0; // azzero il buffer di ingresso, ormai integralmente copiato nel buffer di lavoro
if (Wire.available()){ // se ci sono ancora byte in coda I2c da leggere, non letti perchè il buffer era pieno, li leggo adesso e li elaboro al prossimo giro.
receiveEvent();
}
interrupts();
}
if (Codai2C_tmp_len>0) { // c'è almeno un byte da lavorare
Elem_i2C_wrk=Codai2C_tmp[0];
// estraggo da primo byte i tre sottocampi
byte Elem_1 = Elem_i2C_wrk >> 6 ;
byte Elem_2 = (Elem_i2C_wrk & 0b00110000) >> 4;
byte Elem_3 = Elem_i2C_wrk & 0b00001111;
/* Serial.begin(115200);
Serial.print("Elem_1:");
Serial.print(Elem_1);
Serial.print(" - Elem_2:");
Serial.print(Elem_2);
Serial.print(" - Elem_3:");
Serial.println(Elem_3);
Serial.end();*/
scoda(1);
switch (Elem_1 ){
case 0: // Richiesta di invio stato
// MotorSpeedCorrente = Giri();
// MotorAmpereCorrente = 700;
// PosizioneAttualeCarrello = 543;
Risposta_ptr=byte(7); // Riporto il numero di Byte valorizzati, per un invio corretto
Risposta[0]=byte(1); // rispondo con un codice 1, per verifica
Risposta[1]=lowByte(MotorSpeedCorrente); // 8 bit bassi della velocità del motore
Risposta[2]=highByte(MotorSpeedCorrente); // 8 bit alti della velocità del motore
Risposta[3]=lowByte(MotorAmpereCorrente); // 8 bit bassi della corrente del motore
Risposta[4]=highByte(MotorAmpereCorrente); // 8 bit alti della corrente del motore
Risposta[5]=lowByte(PosizioneAttualeCarrello); // 8 bit bassi della posizione attuale del carrello
Risposta[6]=highByte(PosizioneAttualeCarrello); // 8 bit alti della posizione attuale del carrello
/* Serial.begin(115200);
Serial.print(MotorSpeedCorrente);
Serial.print("-");
Serial.print(Risposta[0]);
Serial.print("-");
Serial.print(Risposta[1]);
Serial.print("-");
Serial.println(Risposta[2]);
Serial.end();*/
break;
case 1: // Carrello
// Serial.println(F("Comando 1"));
switch (Elem_2 ){
case 1: // intera corsa veloce del carrello verso il limite sinistro per impostare la posizione zero. Eseguibile solo con motore fermo.
if (!MotoreAcceso){ //
while(digitalRead(fineSx)){ // eseguo prima una corsa veloce fino allo stop,
FaiUnPasso(-1);
}
for (i=1;i<20;i++){ // poi torno indietro di 20 passi
FaiUnPasso(1);
}
while(digitalRead(fineSx)){ // e li rieseguo lentamente fino allo stop
FaiUnPasso(-1);
delay(200);
}
PosizioneAttualeCarrello = 0; // in modo da avere una lettura precisa dello zero.
}
break;
case 2:
switch(Elem_3){
case 1: //Step +1
FaiUnPasso(1);
break;
case 2: //Step -1
FaiUnPasso(-1);
break;
case 3: //Step +5
for (i=1;i<5;i++){
FaiUnPasso(1);
}
break;
case 4: //Step -5
for (i=1;i<5;i++){
FaiUnPasso(-1);
}
break;
}
break;
case 3:
break;
case 4: // intera corsa veloce del carrello verso il limite sinistro per impostare la posizione zero. Eseguibile solo con motore fermo.
if (!MotoreAcceso){ //
while(digitalRead(fineSx)){ // eseguo prima una corsa veloce fino allo stop,
FaiUnPasso(-1);
}
for (i=1;i<20;i++){ // poi torno indietro di 20 passi
FaiUnPasso(1);
}
while(digitalRead(fineSx)){ // e li rieseguo lentamente fino allo stop
FaiUnPasso(-1);
delay(200);
}
PosizioneAttualeCarrello = 0; // in modo da avere una lettura precisa dello zero.
}
break;
case 5: // carrello manuale, motore stepper spento
CarrelloAutomatico = false;
Potenziometro = false;
StepperOff();
break;
case 6: // carrello comandato dal Joystick
CarrelloAutomatico = false;
Potenziometro = true;
break;
/*
case 5: // carrello a fine corsa sinistra
case 6: // carrello a fine corsa destra
case 7: // imposta posizione corrente come fine corsa sinistro
case 8: // imposta posizione corrente come fine corsa destro
case 9: // tbd
case 10: // imposta direzione e passo del carrello: due byte: direzione e passo
break;
*/
default:
/* Serial.print(F("Codice Oggetto non valido: "));
Serial.print("Elem_1: ");
Serial.print(Elem_1);
Serial.print(" - Elem_1: ");
Serial.println(Elem_2); */
break;
}
case 2: // motore mandrino
//Serial.println(F("Comando 2"));
// Serial.println(Elem_2);
switch (Elem_2 ){
case 1:
MotoreAcceso = true;
// imposta velocità motore mandrino, usa due byte dalla coda di ingresso.
MotorSpeedImpostata = Codai2C_tmp[0] + Codai2C_tmp[1] * 256;
// Serial.print(F("MotorSpeedImpostata = "));
// Serial.println (MotorSpeedImpostata);
scoda(2); // elimino i due byte utilizzati
break;
case 2: // motore mandrino off
MotoreAcceso = false;
// Serial.println(F("Motore spento"));
break;
default:
/* Serial.print(F("Codice Oggetto non valido: "));
Serial.print("Elem_1: ");
Serial.print(Elem_1);
Serial.print(" - Elem_1: ");
Serial.println(Elem_2); */
break;
}
case 3: //impostazioni
// Serial.println(F("Comando 3"));
default:
// Serial.print(F("Codice Comando non valido: "));
// Serial.println(Elem_1);
break;
}
}
}
void scoda(byte numero){ //accorcia la coda di lavoro di "numero" byte, togliendoli dalla testa.
for (i=0;i<Codai2C_tmp_len-numero;i++){
Codai2C_tmp[i]=Codai2C_tmp[i+numero];
}
Codai2C_tmp_len = Codai2C_tmp_len - numero;
}
int Ampere(){
return analogRead(ampere_in); // ogni unità rappresenta 100 mA, da tarare con le misure effettive.
}
double avviolento(){
// accelera gradualmente per evitare il picco di assorbimento del motore
return min(Output,(OutputPrec+MotorAccellMax));
}
void EseguiCarrelloAutomatico(){
// imposto il modo di funzionamento del carrello in base all'impostazione proveniente dalla tastiera
// in Automatico segue gli interrupt del mandrino, in manuale segue il potenziometro o lascio il motore in folle per uno spostamento manuale
if(CarrelloAutomatico){
carrello();
}else{
// spengo il motore, lasciando libero il carrello
digitalWrite(motor_pin_1, LOW);
digitalWrite(motor_pin_2, LOW);
digitalWrite(motor_pin_3, LOW);
digitalWrite(motor_pin_4, LOW);
}
}
void carrello() {
pot=0;
if (Potenziometro){ // serve ancora?
pot = map(analogRead(pot_in), 0, 1023, +500, -500);
pot = pot/70;
direzionePot = (pot > 0) ? 1:-1; // per valori positivi la direzione richiesta è in avanti.
pot = pot * pot * direzionePot;
}
// se il potenziometro è al centro (tra -2 e + 2) non c'è avanzamento. La condizione è indicata dal led
if (pot > -2 && pot < 2 ) {
// spengo il motore
StepperOff();
}else{
// il potenziometro definisce quanti millesimi di millimetro per ogni giro del mandrino, variabile tra 0 e 1500
MM_Per_Giro = (abs(pot)-2)*30;
MM_Per_Settore = MM_Per_Giro/(NumeroSettori); // definisco il passo per ogni settore dell'encoder
}
if (( micros()- time1)> 10000000){ // timeout motore, lo spegne per non bruciarlo se fermo da oltre 10 secondi.
StepperOff();
}
noInterrupts();
MM_Temp=MM_DaFare;
interrupts();
if (abs(MM_Temp)>=LunghezzaPasso){
int deltapassi=int(MM_Temp/LunghezzaPasso)*direzionePot;
passi=passi+deltapassi;
passitotali=passitotali+deltapassi;
MM_Temp=MM_Temp - abs(deltapassi*LunghezzaPasso);
}
if (passi > 0){
FaiUnPasso(1);
passi--;
noInterrupts();
MM_DaFare=MM_Temp;
interrupts();
}
if (passi < 0){
FaiUnPasso(-1);
passi++;
noInterrupts();
MM_DaFare=MM_Temp;
interrupts();
}
}
void encoderMotore(){
MM_DaFare=MM_DaFare+MM_Per_Settore;
tic++;
if (tic>20){
tic=1;
}
t[0]=micros()-t[tic];
t[tic]=micros();
}
void FaiUnPasso(int p){ // riceve solo +1 o -1 in quanto il numero dei passi rimanenti viene gestito dalla routine chiamante,
// quindi è necessario solo conoscere il passo corrente ed in quale verso occorre fare il prossimo.
// inibisco il movimento se ho il fine corsa attivo (basso)e sblocco lo Stepper
if (digitalRead(fineSx)==LOW && p<0){
p=0;
StepperOff();
}
if (digitalRead(fineDx)==LOW && p>0){
p=0;
StepperOff();
}
// definisco quale è la posizione corrente e quindi qual'è quella successiva
PassoCorrente = PassoCorrente + p;
if (PassoCorrente >= 4) {
PassoCorrente-=4;
}
if (PassoCorrente < 0) {
PassoCorrente+=4;
}
long del=time1 - micros() + TempoMinimo;
if (del>0){
delayMicroseconds(del); //attendo il tempo minimo dal passo precedente per fare il passo.
}
Serial.begin(115200);
Serial.println(PassoCorrente);
Serial.end();
switch (PassoCorrente) {
case 0: // 1010
digitalWrite(motor_pin_1, HIGH);
digitalWrite(motor_pin_2, LOW);
digitalWrite(motor_pin_3, HIGH);
digitalWrite(motor_pin_4, LOW);
break;
case 1: // 0110
digitalWrite(motor_pin_1, LOW);
digitalWrite(motor_pin_2, HIGH);
digitalWrite(motor_pin_3, HIGH);
digitalWrite(motor_pin_4, LOW);
break;
case 2: //0101
digitalWrite(motor_pin_1, LOW);
digitalWrite(motor_pin_2, HIGH);
digitalWrite(motor_pin_3, LOW);
digitalWrite(motor_pin_4, HIGH);
break;
case 3: //1001
digitalWrite(motor_pin_1, HIGH);
digitalWrite(motor_pin_2, LOW);
digitalWrite(motor_pin_3, LOW);
digitalWrite(motor_pin_4, HIGH);
break;
}
time1=micros();
}
void StepperOff(){
digitalWrite(motor_pin_1, LOW);
digitalWrite(motor_pin_2, LOW);
digitalWrite(motor_pin_3, LOW);
digitalWrite(motor_pin_4, LOW);
}
int Giri(){
// prendo il tempo dei 20 passaggi registrati dall'interrupt e lo trasformo in giri al minuto.
// Ogni giro del mandrino corrisponde a 80 tic (20 dello stepper per 4 della riduzione), quindi un giro al secondo (60 giri/minuto) prevede un tic ogni 12500 microsecondi
// che devo moltiplicare per 20 perchè t[0] contiene il tempo sugli ultimi 20 tic, per fare media. Infine moltiplico per 60 per avere i giri al minuto
//12500*20*60=15.000.000
// non metto variabili per non rallentare l'esecuzione.
noInterrupts();
t0_tmp=t[0];
interrupts();
vel=15000000/t0_tmp;
return max(vel,0); // evito eventuali numeri negativi
}
void setPwmFrequency(int pin, int divisor) {
byte mode;
if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
switch(divisor) {
case 1: mode = 0x01; break;
case 8: mode = 0x02; break;
case 64: mode = 0x03; break;
case 256: mode = 0x04; break;
case 1024: mode = 0x05; break;
default: return;
}
if(pin == 5 || pin == 6) {
TCCR0B = TCCR0B & 0b11111000 | mode;
} else {
TCCR1B = TCCR1B & 0b11111000 | mode;
}
} else if(pin == 3 || pin == 11) {
switch(divisor) {
case 1: mode = 0x01; break;
case 8: mode = 0x02; break;
case 32: mode = 0x03; break;
case 64: mode = 0x04; break;
case 128: mode = 0x05; break;
case 256: mode = 0x06; break;
case 1024: mode = 0x7; break;
default: return;
}
TCCR2B = TCCR2B & 0b11111000 | mode;
}
}
// queste sono le funzioni che ricevono e trasmettono i dati I2C
void receiveEvent() //questo evento viene generato quando sul bus è presente un dato da leggere
{
while(Wire.available()){
if (Codai2C_len < 31){ // leggo il dato solo se ho spazio nell'array, altrimenti attendo l'esecuzione manuale della routine, invocata dalla loop()
Codai2C_len++;
Codai2C[Codai2C_len] = Wire.read();
}
}
}
void requestEvent(int qty)
{
//questo evento viene generato quando il master
//richiede ad uno specifico slave
//una richiesta di dati
//spedisco il dato al Master
Wire.write(Risposta,Risposta_ptr);
}