info velocità di calcolo arduino per mappatura onda

ciao
stò facendo una applicazione che credo critica per la velocità di calcolo di arduino, visti i risultati che ottengo,
mi potete indicare la velocità di calcolo, o i criteri per determinare una velocità minima

/*
versione con shiftin 1 cd74hc597
versione con shiftout 3 74hc595
codice sviluppato partendo dal lavoro dei sottoelencati autori
//  Author  : Carlyn Maw, Tom Igoe                                    
//  Notes   : Code for using a 74hc597 Shift Register input
//  Notes   : Code for using a 74hc595 Shift Register output

/*il seguente codice utilizza le funzioni shifout
 e le funzioni shiftin, viene eseguito il controllo dello stato
 dei contatti su shiftin e la memorizzazione 
 nei registri di shiftin e riprodotti sui led dalla funzione shiftout
 il led sarà in parallelo alla elettrovalvola
 */

//pin per shiftout
int latchPinOUT = 4;//Pin connected to ST_CP of 74HC595 pin 12
int clockPinOUT =3;//Pin connected to SH_CP of 74HC595 pin 11
int dataPinOUT = 2;//Pin connected to DS of 74HC595  pin 14

unsigned long durataH[6];
unsigned long durataL[6];

byte ledRossiH = B00000000;  
byte ledVerdi = B00000000; 
byte ledRossiL = B00000000; 

int i;

void setup() 
{
  //shiftout define pin modes
  pinMode(latchPinOUT, OUTPUT);
  pinMode(clockPinOUT, OUTPUT);
  pinMode(dataPinOUT, OUTPUT);
//  Serial.begin(9600);
}

void loop() 
{
ledRossiH = B00000000;  
ledVerdi = B00000000; 
ledRossiL = B00000000; 

for(i=0; i<=5; i++)
{
  durataH[i]=pulseIn(i+7,HIGH);
     durataL[i]=pulseIn(i+7,LOW);
/*     
 Serial.print(i);
 Serial.print('\t');
 Serial.println(durataL[i]);
 */
 
if(durataL[i]<=10000)
{
  bitWrite(ledVerdi,i,1);
}

if(durataH[i] > 70000 || durataH[i]==0)
{
 bitWrite(ledRossiH,i,1);
  bitWrite(ledVerdi,i,0);
}

if(durataL[i] > 100000 || durataL[i]==0)
{
  bitWrite(ledVerdi,i,0);
   bitWrite(ledRossiL,i,1);
}
     digitalWrite(latchPinOUT,1);                       //Pull latch LOW to start sending data
      shiftOut(dataPinOUT, clockPinOUT, MSBFIRST, ledRossiL);    //Send the data byte rossi
      shiftOut(dataPinOUT, clockPinOUT, MSBFIRST, ledVerdi);    //Send the data byte verdi
      shiftOut(dataPinOUT, clockPinOUT, MSBFIRST, ledRossiH);    //Send the data byte rossi
     digitalWrite(latchPinOUT,0);                      //Pull latch HIGH to stop sending data
/*     
 Serial.print(i);
 Serial.print('\t');
 Serial.println(bitRead(ledVerdi,i));    
 */
}
 
}  //parentesi di fine loop

grazie
stefano

PulseIn è una funzione bloccante. Il codice rimane fermo finché non riceve un cambio di stato sul pin.

ciao si so di questo, ma trascurando la presenza del pulsein

grazie stefano

Il clock di norma è di 20Mhz, ogni operazione può comportare più cicli di clock. Il loop di un programma leggero potrebbe essere eseguito ogni 100us (microsecondi) mentre uno più pesante ogni 1000, ovvero ogni millisecondo. Sempre se non ho sbagliato unità di misura.

Stiamo parlando di Arduino, per cui il clock di norma è 16 MHz. Se parliamo di istruzioni assembly, la metà circa è eseguita in 1 ciclo di clock, altre in 2, qualcuna in 3, poche in 4.

Dobbiamo però considerare che le funzioni di Arduino sono tutte classi: anche un semplice digitalWrite richiede diverso tempo rispetto al semplice setup dei registri fatto manualmente. Una lettura digitale richiede del tempo, una lettura analogica un tempo enormemente più lungo (per via del carico del circuito RC interno). Se poi andiamo ad interfacciarci col mondo esterno con funzioni tipo pulseIn il calcolo della velocità teorica perde di significato perché troppe sono le variabili in gioco indipendenti dall'Arduino.

A me sembra che manchino informazioni sullo scopo dello sketch e sui vincoli temporali in gioco... Non mi pare che il punto sia la velocità di elaborazione dell'arduino.

Ciao,

se vuoi maggiore velocita' di esecuzione puoi utilizzare direttamente le funzioni C di AVR, oppure direttamente ASM.

Ad esempio per il digital write http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230286016/all http://jeelabs.org/2010/01/06/pin-io-performance/

E per lo shiftout http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1254488619

Se si desidera maggior velocita' di esecuzione si deve togliere parte della facilita' di utilizzo dell'ambiente Arduino e utilizzare funzioni di piu' basso livello.

Ciao, Marco.

ciao
come da titolo modificato quello che vorrei ottenere anche in modo approssimato
è la mappatura di una onda quadra nella durata HIGH e LOW, lo sketch non lavora correttamente, la durata HIGH vale 55 msec la durata LOW vale 11 msec per una frequenza di prova di 15 Hz, quando lancio l’onda di prova lampeggiano sia il ledRossiH che il ledRossiL alla stessa frequenza ma con durate diverse, in totale alla fine le onde da mappare sono 6 svasate tra di loro in modo casuale,

avete suggerimenti o altre strade per affrontare il problema

grazie
stefano

/*
versione con shiftin cd74hc597
e shiftout 74hc595
*/

//pin per shiftout
int latchPinOUT = 4;//ST_CP di 74HC595 pin 12
int clockPinOUT =3;//SH_CP di 74HC595 pin 11
int dataPinOUT = 2;//DS di 74HC595  pin 14


//pin per shiftin
int latchPinIN = 7; //597 pin 12
int dataPinIN = 9; //597 pin 9
int clockPinIN = 8; //597 pin 11
int loadPinIN = 6;//597 pin 13

//starting with a non-zero numbers can help troubleshoot
byte switchVar1 = 78;  //01001110

byte ledRossiH = B00000000;  
byte ledVerdi = B00000000; 
byte ledRossiL = B00000000; 

int i,j;

unsigned long timeHIGH[6]={0,0,0,0,0,0};
unsigned long timeLOW[6]={0,0,0,0,0,0};

// vettore 6 colonne durata High
unsigned long timeH[6]={0,0,0,0,0,0}; 
                        
// vettore 6 colonne durata Low
unsigned long timeL[6]={0,0,0,0,0,0};

void setup() 
{
  //shiftout
  pinMode(latchPinOUT, OUTPUT);
  pinMode(clockPinOUT, OUTPUT);
  pinMode(dataPinOUT, OUTPUT);

  //shiftin
  pinMode(latchPinIN, OUTPUT);
  pinMode(clockPinIN, OUTPUT); 
  pinMode(dataPinIN, INPUT);
  pinMode(loadPinIN, OUTPUT);

  Serial.begin(9600);
}

void loop() 
{ 
  digitalWrite(latchPinIN,1);  //set it to 1 to collect parallel data, wait
  delayMicroseconds(20);     
  digitalWrite(latchPinIN,0); //set it to 0 to transmit data serially 
  
  digitalWrite(loadPinIN, 0);
  delayMicroseconds(20);
  digitalWrite(loadPinIN, 1);
 
   switchVar1 = shiftIn(dataPinIN, clockPinIN);
   
for(i=0; i<=5; i++)
{
  j=bitRead(switchVar1,i);
 /*
  Serial.print(i);
  Serial.print('\t');
  Serial.println(j);
 */
switch (j)
{
case 1:
 timeH[i]=millis()-timeLOW[i]+timeH[i];
timeHIGH[i]=millis();
/*
 Serial.print(i);
 Serial.print('\t');
 Serial.println(timeH[i]);
*/
if(timeH[i] > 1000) //verifica della durata H
 {
   timeH[i]=0;//azzera

  bitWrite(ledRossiH,i,1);
  bitWrite(ledVerdi,i,0);
  bitWrite(ledRossiL,i,0);
}
else
{
   bitWrite(ledRossiH,i,0);
  bitWrite(ledVerdi,i,1);
  bitWrite(ledRossiL,i,0); 
}
break;

 case 0:
  timeL[i]=millis()-timeHIGH[i]+timeL[i];
 timeLOW[i]=millis();
/* 
 Serial.print(i);
 Serial.print('\t');
  Serial.println(timeL[1][i]);
  */
if(timeL[i] < 50) //verifica della durata L
 {    
      bitWrite(ledRossiH,i,0);
   bitWrite(ledVerdi,i,1);
     bitWrite(ledRossiL,i,0);  
 }
 else
 {
    timeL[i]=0;//azzera
  
     bitWrite(ledRossiH,i,0);
   bitWrite(ledVerdi,i,0);
     bitWrite(ledRossiL,i,1);
 }
 
break;
}
}
     digitalWrite(latchPinOUT,1);                       //Pull latch LOW to start sending data
      shiftOut(dataPinOUT, clockPinOUT, MSBFIRST, ledRossiL);    //Send the data byte rossi
      shiftOut(dataPinOUT, clockPinOUT, MSBFIRST, ledVerdi);    //Send the data byte verdi
      shiftOut(dataPinOUT, clockPinOUT, MSBFIRST, ledRossiH);    //Send the data byte rossi
     digitalWrite(latchPinOUT,0);                      //Pull latch HIGH to stop sending data
/*     
 Serial.print(i);
 Serial.print('\t');
 Serial.println(bitRead(ledVerdi,i));    
  */   
}  //parentesi di fine loop

/*
//     shiftIn function

///// just needs the location of the data pin and the clock pin
///// it returns a byte with each bit in the byte corresponding
///// to a pin on the shift register. leftBit 7 = Pin 7 / Bit 0= Pin 0
*/
byte shiftIn(int myDataPin, int myClockPin)
{
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);
  
  //we will be holding the clock pin high 8 times (0,..,7) at the
  //end of each time through the for loop

  //at the begining of each loop when we set the clock low, it will
  //be doing the necessary low to high drop to cause the shift
  //register's DataPin to change state based on the value
  //of the next bit in its serial information flow.
  //The register transmits the information about the pins from pin 7 to pin 0
  //so that is why our function counts down
  for (i=7; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(20);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      myDataIn = myDataIn | (1 << i);
    }
    else {
       pinState = 0;
    }
    digitalWrite(myClockPin, 1);
  }
   return myDataIn;
}

20120223-0001.pdf (177 KB)

Secondo me dovresti collegare l'onda direttamente ad un pin dell'Arduino e leggere il cambio di stato con un interrupt. Usando la modalità CHANGE, l'interrupt può attivarsi sia sul passaggio da LOW ad HIGH sia sull'inverso. E saltare l'uso del registro esterno. Che poi, ti serve? O hai più di 1 segnale da monitorare?

ciao @benini grazie me le studio @leo purtroppo ho 6 segnali da monitorare, vorrei farcela con un arduino,

grazie stefano

Allora potresti usare gli interrupt di cambio di stato dei pin, i PcInt. http://arduino.cc/playground/Main/PinChangeInt

Tutti i pin dell'Arduino possono essere usati per tale scopo.

ciao
@leo
stò seguendo questo link
http://code.google.com/p/arduino-pinchangeint/wiki/Logic
ma non riesco ad andare oltre il pin 7 di arduino, inoltre c’è una sintassi che non conosco “::” mi date qualche link

grazie
stefano

// PinChangeIntExample, version 1.2 Fri Feb  3 19:41:08 CST 2012
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
//-------- define these in your sketch, if applicable ----------------------------------------------------------
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
// on any one or two of the three ports.  If only a single port remains, the handler will be declared inline
// reducing the size and latency of the handler.
//#define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
//#define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
// PCintPort::arduinoPin are set and made available to your interrupt routine.
// #define NO_PIN_STATE        // to indicate that you don't need the pinState
// #define NO_PIN_NUMBER       // to indicate that you don't need the arduinoPin
// if there is only one PCInt vector in use the code can be inlined
// reducing latency and code size
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
// #define       DISABLE_PCINT_MULTI_SERVICE
//-------- define the above in your sketch, if applicable ------------------------------------------------------
#include <PinChangeInt.h>

// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
// All interrupts are serviced immediately, but one of the pins (pin 4) will show you immediately
// on the Terminal.  The other function connected to 2 pins sets an array member that is queried in loop().
// You can then query the array at your leisure.
// This makes loop timing non-critical.

// Add more Pins at your leisure.
// For the Analog Input pins used as digital input pins, and you can use 14, 15, 16, etc.
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's
// for the Analog Input pins and will properly recognize e.g., pinMode(A0, INPUT);

#define PIN1 6
#define PIN2 7
#define PIN3 8
/*
#define PIN4 10
#define PIN5 11
#define PIN6 12
*/

uint8_t latest_interrupted_pin;
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
void quicfunc() {
  if (PCintPort::pinState) Serial.print("H"); else Serial.print("L");
  latest_interrupted_pin=PCintPort::arduinoPin;
  interrupt_count[latest_interrupted_pin]++;
};

// You can assign any number of functions to any number of pins.
// How cool is that?
void pin3func() {
  if (PCintPort::pinState) Serial.print("H"); else Serial.print("L");
  Serial.print("Pin "); Serial.print(PIN3, DEC); Serial.println("!");
}

void setup() {
  pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH);
  PCintPort::attachInterrupt(PIN1, &quicfunc, FALLING);  // add more attachInterrupt code as required
  pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH);
  PCintPort::attachInterrupt(PIN2, &quicfunc, FALLING);
  pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);
  PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE);
  Serial.begin(9600);
  Serial.println("---------------------------------------");
}

uint8_t i;
void loop() {
  uint8_t count;
  Serial.print(".");
  delay(1000);
  for (i=0; i < 20; i++) {
    if (interrupt_count[i] != 0) {
      count=interrupt_count[i];
      interrupt_count[i]=0;
      Serial.print("Count for pin ");
      if (i < 16) {
        Serial.print("D");
        Serial.print(i, DEC);
      } else {
        Serial.print("A");
        Serial.print(i-16, DEC);
      }
      Serial.print(" is ");
      Serial.println(count, DEC);
    }
  }
}

I doppi due punti indicano un modo per indicare i metodi o gli oggetti di una classe.

Non ho guardato l'esempio che hai postato però posso riassumerti un attimo come funzionano i PcInt. I pin del micro sono mappati su delle porte logiche, ognuna corrispondente ad un registro. Ad esempio, i pin PB0..PB7, corrispondenti ai pin di Arduino dal D0 al D7, sono mappati sulla porta PORTB. Le porte del 328 sono 3: PORTB, PORTC e PORTD. Ogni porta/registro è ad 8 bit, per cui può mappare 8 pin. Ne conviene che 3*8=24 bit ossia 24 porte massimo che possono essere mappate. Queste sono quasi tutte riprodotte sui pin del 328 in versione DIP28. Però, a differenza di un INTERRUPT, un PINCHANGE INTERRUPT non è monitorato singolarmente ma da un interrupt agganciato all'intero registro. Per cui esiste il PCINT0, il PCINT1 ed il PCINT2.

Se mi dici che non riesci ad attivare oltre il pin D7, mi viene da pensare che hai attivato solo l'interrupt PCINT2 agganciato alla porta PORTB.

ciao grazie per la pazienza ho fatto questo quindi dovrei avere anche il campo B disponibile

stefano

//#define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
//#define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts

ciao
@leo adesso stò provando questo codice un interrupt alla volta, se passo dal pin 2 a pin 3 mi aspetto di vedere sul serial monitor un conteggio ripartire da 1 non il proseguimento del conteggio precedente, mi sbaglio

stefano

#include <PinChangeInt.h>


#define PIN1 2
#define PIN2 3
#define PIN3 4
#define PIN4 5
#define PIN5 6
#define PIN6 7

int statosensore1=HIGH;
int statosensore2=HIGH;
int statosensore3=HIGH;
int statosensore4=HIGH;
int statosensore5=HIGH;
int statosensore6=HIGH;

int i;
int count[6]={0,0,0,0,0,0};
int tempo[6]={0,0,0,0,0,0};

void setup() 
{
    pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH);
  PCintPort::attachInterrupt(PIN1, sensore1, FALLING);  
    pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH);
  PCintPort::attachInterrupt(PIN2, sensore1, FALLING);
    pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);
  PCintPort::attachInterrupt(PIN3, sensore1, FALLING);
    pinMode(PIN4, INPUT); digitalWrite(PIN4, HIGH);
  PCintPort::attachInterrupt(PIN4, sensore1, FALLING);
    pinMode(PIN5, INPUT); digitalWrite(PIN5, HIGH);
  PCintPort::attachInterrupt(PIN5, sensore1, FALLING);
    pinMode(PIN6, INPUT); digitalWrite(PIN6, HIGH);
  PCintPort::attachInterrupt(PIN6, sensore1, FALLING);
  
  Serial.begin(9600);
 }

void loop()
{
  if (statosensore1==LOW)
{ 
  Serial.println(count[0]);  
  statosensore1=HIGH;
}
 if (statosensore2==LOW)
{
  Serial.println(count[1]);  
  statosensore2=HIGH;
}
 if (statosensore3==LOW)
{
  Serial.println(count[2]);  
  statosensore3=HIGH;
}
 if (statosensore4==LOW)
{
  Serial.println(count[3]);  
  statosensore4=HIGH;
}
 if (statosensore5==LOW)
{
  Serial.println(count[4]);  
  statosensore5=HIGH;
}
 if (statosensore6==LOW)
{
  Serial.println(count[5]);  
  statosensore6=HIGH;
}
}

//---------------------------funzioni
void sensore1()
{
  statosensore1=LOW;
 count[0]++;
}
void sensore2()
{
  statosensore2=LOW;
  count[1]++;
}
void sensore3()
{
  statosensore3=LOW;
  count[2]++;
}
void sensore4()
{
  statosensore4=LOW;
  count[3]++;
}
void sensore5()
{
  statosensore5=LOW;
   count[4]++;
}
void sensore6()
{
  statosensore6=LOW;
  count[5]++;
}

ciao ma è possibile il conteggio alla rovescia di millis()

stefano

...
void setup() 
{
    pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH);  // add more attachInterrupt code as required
  PCintPort::attachInterrupt(PIN1, sensore1, FALLING);  
    pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH);  // add more attachInterrupt code as required
  PCintPort::attachInterrupt(PIN2, sensore1, FALLING);
    pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);  // add more attachInterrupt code as required
...
...
void loop()
{
  if (statosensore1==LOW)
{ 
  Serial.println(count[0]); 
  Serial.println(tempo[0]); 
  statosensore1=HIGH;
}
 if (statosensore2==LOW)
{
  Serial.println(count[1]);
 Serial.println(tempo[1]);  
  statosensore2=HIGH;
}
...

//---------------------------funzioni
void sensore1()
{
  statosensore1=LOW;
 count[0]++;
 tempo[0]=millis();
}
void sensore2()
{
  statosensore2=LOW;
  count[1]++;
  tempo[1]=millis();
}
void sensore3()
{
  statosensore3=LOW;
  count[2]++;
  tempo[2]=millis();
}
...

output collegato sul pin 2

1
11843
2
17006
3
23538

output collegato sul pin 3

4
-32104
5
-32089
6
-22914
7
-16458
8
-11318

output ricollegato sul pin 2

9
-9628
10
-9615
11
-3641

Ma tu nel setup hai assegnato la stessa funzione sensore1 a tutte e 6 le routine di gestione degli interrupt

pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH); // add more attachInterrupt code as required PCintPort::attachInterrupt(PIN1, sensore1, FALLING); pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH); // add more attachInterrupt code as required PCintPort::attachInterrupt(PIN2, sensore1, FALLING); ecc...

PS: millis conta solo in avanti. O modifichi il contatore tu oppure usi una semplice sottrazione tipo 0-millis, così hai il conteggio alla rovescia

ciao @leo grazie per la pazienza, ho capito l'errore sul conteggio, riguardo a millis() ho capito perchè conta alla rovescia avevo assegnato

int tempo[6]={0,0,0,0,0,0};

invece di questo

unsigned long tempo[6]={0,0,0,0,0,0};

stefano