Vai al contenuto
PLC Forum


arduino step dir


roberto8303

Messaggi consigliati

Buongiorno, sto realizzando un movimento con un motore passo passo 200 passi giro, e ho utilizzato un azionamento della rta ncd 02 che accetta in ingresso i segnali step dir.


#include <Wire.h> 
#include <PCF8574_HD44780_I2C.h>
PCF8574_HD44780_I2C lcd(0x27,16,2);
#include <AccelStepper.h>
int sensorPin = A0;    // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int sensorValue = 0; 
int sensorValue1;
int motorSpeed = 500; 
int motorAccel = 14000; 
int differenza=0;
int motorDirPin = 5; //digital pin 2
int motorStepPin = 6; //digital pin 3
int gradi;
int merker;

AccelStepper stepper(1, motorStepPin, motorDirPin); 

void setup(){

  
   lcd.init();           // LCD Initialization              
  lcd.backlight();      // Backlight ON
     lcd.setCursor(0,0);
  lcd.print("GRADI");  // Clear the display
  stepper.setMaxSpeed(motorSpeed);
  stepper.setSpeed(motorSpeed);
  stepper.setAcceleration(motorAccel);
  pinMode(ledPin, OUTPUT);  

}

void loop(){
 
lcd.setCursor(0,8);
  lcd.print(gradi);
  
  sensorValue = analogRead(sensorPin);    
  sensorValue= map(sensorValue, 0,1023, 0,4000);


gradi=differenza/11.1111;
if ((sensorValue-differenza)>=(8)){
   differenza=sensorValue;}

if ((sensorValue-differenza)<=(-8)){
  differenza=sensorValue;}   

  
   stepper.moveTo(differenza);
   stepper.run();}

 

 

il problema è che se inserisco i comandi per il pannello lcd il motore va lento e a scatti, se tolgo i comandi di lcd.print il motore va bene, quindi e come se rallentasse il programma e quindi perde gli impulsi da inviare all azionamento, come posso risolvere? utilizzando un lcd senza i2c è lo stesso? oppure devo gestire tutto sotto interrupt avete qualche esempio?

Link al commento
Condividi su altri siti


Quote

quindi e come se rallentasse il programma e quindi perde gli impulsi

 

Non è come se rallentassi, tu rallenti di parecchio il programma.

 

Purtroppo molte delle funzioni della biblioteca del pannello sono bloccanti e durano parecchio.

Le soluzioni non sono tante purtroppo.

Io ti consiglio di farti un generazione degli impulsi di comando degli stepper ad interrupt in questo modo sganci parzialmente (c'è sempre il tempo di altenza) la generazione degli impulsi dal resto della gestione. Al limite si rallenta l'aggiornamento del display.

Oppure usi 2 schede differenti: con una gestisci il controllo e con l'altra gestisci lo HMI.

Link al commento
Condividi su altri siti

grazie Livio, l idea dei due microcontrollori mi piace, però se volessi generare io un treno di impulsi ad interrupt cosa dovrei fare, a me serve per una tavola rotante da 0 a 360 gradi ho un riduttore da 1:10. Comunque per creare un treno di impulsi sul pin da dove devo partire per avere accelerazione velocità e quindi il numero totale di impulsi.

Link al commento
Condividi su altri siti

Ho ripensato un attimo al tuo programma ed assomiglia ad un che ho messo a punto (sino ad un certo punto :smile:) un po' di tempo fa: 2 motori con PWM, un sensore di distanza ed uno di luminosità. Display LCD con comando I2C.

 

A me non da problemi.

 

Ci sono alcune differenze.

Prima di tutto per il display io uso la libreria "testato" prelevata dal sito ufficiale di arduino.

 

Poi nel main loop il display  lo aggiorno a tempo, così come la lettura dei sensori. Ho un timer di sistema che mi fa leggere i sensori ed aggiornare il display ogni 100ms. In questo modo uso un PWM a 6kHz senza problemi.

Link al commento
Condividi su altri siti

Anche io ho scaricaro la libreria testato per lcd allora si devo provare a scrivere sul pannello dopo tot tempo, il timer che hai utilizzato pero' mi chiedo come faccio a separarlo dal ciclo del loop cioe il treno d impulsi non deve essere toccato dal timer ogni 100ms

Link al commento
Condividi su altri siti

Programmi il timer1 come temporizzatore e gli associ un interrupt, se vuoi ti metto il codice del mio.

Link al commento
Condividi su altri siti

Questo è l'esempio per generare un'interruzione ogni 10ms con timer1; l'istruzione che varia TCCR2B puoi ignorarla.

 

 

  void setup() 
  {
   
--------

     noInterrupts();
     TCCR1A = 0;
     TCCR1B = 0;
     TCNT1 = 6491;
     TCCR1B |= (1<<CS12);
     TIMSK1 |= (1<<TOIE1);
     TCCR2B = TCCR2B & 0b11111000 | 0b10; 
/* Si imposta il fattore di divisione del prescaler;
   in questo caso il timer usato è il timer 2 che con
   prescaler diviso per 1 genera una frequenza di 31.250 Hz
 */
     icnt = 20;
     interrupts();
}
ISR (TIMER1_OVF_vect)
 {
   TCNT1 = 64911; //ricarica timer
   //digitalWrite(imarca, digitalRead(imarca)^1); //test per misura tempo
   icnt--;
   if (icnt == 0)
     {
         icnt = 20;
         flgacq = HIGH; //flag per abilitare processi lenti; 200ms in questo caso
      }
   icmdStart = digitalRead(Start); // puoi usare questa funzione o altra simile per leggere e scrivere I/O
                                   // ogni 10ms
 }

 

Link al commento
Condividi su altri siti

grazie appena posso lo provo, quindi ogni 10ms posso inviare gli impulsi step dir? quale ritardo massimo puo darmi problemi sugli impulsi che mando all azionamento?

esempio il mio motore è un 200 passi giro, quindi  se mando 200 impulsi al secondo ho 60 rpm, se voglio andare a 120 rpm sono 400 impulsi al secondo quindi il tempo di interrput di quanto deve essere per non darmi problemi? non so se riesco a spiegarmi...il fatto che blocco il programma ad intervallo regolare anche se 10ms mi mette un po di confusione...

Link al commento
Condividi su altri siti

No.

L'uscita di direzione sarà fissa o a zero o a uno, cambia stato quando vuoi cambiare direzione.

Se ti bastsano 400 impulsi al secondo puoi inviarlo tramite interrupt usando la riga che ho ommentato "test per misura tempo" programmando il timer per ottere un interrupt, ogni 1.25 ms, quindi precaricando 65457 in luogo di 64911.

icnt lo fai pari 160, così hai sempre 200ms come tempo per leggere gli analogici e aggiornare il display.

Il timer da 1.25ms lo puoi usare anche per gestire la rampa.

 

Il programma non lo blocchi ma usi la tecnica della "divisione di tempo" come si in tutti i controlli in real time.

la funzione di servizio interrupt esegue quelle poche istruzioni necessarie, impieggando 200µs - 300µs; per il restante millisecndo circa la CPU si dedica alle altre funzioni, ma secondo me alla fin e avrai si e no un'occupazione del 70% della CPU.

Link al commento
Condividi su altri siti

Ho capito, però sul sito ufficiale,ho trovato una libreria timer.h praticamente permette di avere dei void a tempo impostabili nel setup, anche sugli ingressi di input output

Secondo te potrei risolvere anche con questo? adesso non ho il motore qui per provare, ma ho modificato un programma esempio dove svolgo tre funzioni, una led 8 lampeggio ogni 100ms dal void loop con millis, un altra funzione è richiamare il void lcd ogni 1000 sommando uno ogni secondo ad una variabile chiamata ora, ed un altra funzione è quella di avere un led sul pin 9 alto per 500ms e basso per 500ms. Adesso vorrei utilizzare questo timer per il motore lascio tutto nel loop ma aggiungo solo il print lcd nel void chiamato a tempo ogni 100ms dici che dovrei risolvere?

 

 

 

 #include "Timer.h"
 
const int ledPin=8;             //LED connesso al pin digitale 8
const int pin9 = 9;                //LED connesso al pin digitale 9
int value = LOW;                   //Valore precedente del LED
long previousMills = 0;                //Memorizza l'ultima volta che il led è stato aggiornato   
int ora;
  Timer t;  
   
    void setup()
    {
      Serial.begin(9600);
      pinMode(pin9, OUTPUT);
      pinMode(ledPin, OUTPUT);
     
      t.oscillate(pin9, 500, HIGH);               //timer on/off su I/0 ogni 500ms ripetitivo
      t.every(1000,lcd);                         //timer richiamo void lcd per scrivere ogni 1secondi
      }
     
        void loop()
    {
      t.update();    
      
     if (millis() -  previousMills > 100 ){                  // programma prova in loop con ritardo di millis
         previousMills = millis();                          //Tiene in memoria l'ultimo lampeggio

                                                        //Se il LED è spento lo accende e viceversa
         if (value == 0)
             value = 1;
         else
             value = 0;
 digitalWrite(ledPin, value); }
       }
     
     
    void lcd(){                                     // void scrivi da utilizzare come aggiornamento display
Serial.println(ora);
ora=ora+1;
}

 

 

http://playground.arduino.cc/Code/Timer#Installation

 

 

Link al commento
Condividi su altri siti

ho fatto un altra prova è corretto scrivere nel pannello lcd dal void loop e avere il programma del motore nel void lcd quello richiamato a tempo di 1ms

ho misurato il lampeggio del led con l oscilloscopio se imposto millis ad 1ms ho in realta 2ms  e una frequenza di 240hz circa, invece mettendo il lampeggio del led nel void chiamato dal timer ogni 1ms mi trovo preciso e ho una frequenza di 488,5hz

Link al commento
Condividi su altri siti

ok mi sono risposto da solo, ho provato queste due righe


#include <Wire.h>
#include <PCF8574_HD44780_I2C.h>
PCF8574_HD44780_I2C lcd(0x27,16,2);
const int led=9;
int valore=0;
void setup() {
  // put your setup code here, to run once:
pinMode(led,OUTPUT);
 lcd.init();           // LCD Initialization              
  lcd.backlight();      // Backlight ON
       lcd.setCursor(2,0);
  lcd.print("GRADI TAVOLA");  // Clear the display

}

void loop() {
  // put your main code here, to run repeatedly:

lcd.setCursor(6,1);
  lcd.print("c");


if(valore==0){
  valore=1;}
  else{
    valore=0;}
 
  digitalWrite(led,valore);
}

 

se uso in loop solo lcd.setcursor il led lampeggia ogni 1,2 ms se aggiungo lcd print ("c") quindi una sola lettera il led lampeggia ogni 3ms poi ho scritto ciaooo quindi piu caratteri ed il led lampeggia ogni 10ms :blink: altro chè se rallenta ora me ne rendo conto quanto incide

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...