Aumentar velocidad del codigo

Hola buenas,
Soy nuevo utilizando Arduino y estoy haciendo un pequeño proyecto que trata de medir el valor de dos resistencias (sensores FSR) para obtener la presión que se ejerce sobre estos y guardar estos datos en una tarjeta sd. El problema que tengo es que actualmente el código va a una frecuencia de 43Hz y necesitaría que fuese de 100Hz o mas.
Antes de nada muchas gracias por su atención

#include <SD.h>

File logFile1;

int analogPin= A0;
int analogPin1 = A1;

int raw1 =0;
int raw= 0;

float p;
float p1;

unsigned long myTime;
volatile unsigned delta=0;
volatile unsigned anterior =0;

void setup()
{
  
  Serial.begin(115200);// con estos baudios transmitimos a 110Hz 
   Serial.print(F("Iniciando SD ..."));
  if (!SD.begin(9))
  {
    Serial.println(F("Error al iniciar"));
    return;
  }
  Serial.println(F("Iniciado correctamente"));
  
}

void loop()
{
    myTime = millis();
    delta = myTime-anterior;
    Serial.println(delta);
    raw= analogRead(analogPin);
    raw1= analogRead(analogPin1);
  
    p=(1500.0*pow(2.0,466.0/767.0)*pow(3.0,233.0/767.0)*pow(5.0,699.0/767.0))/(pow((55720.0 * (4.685/((raw * 4.685)/1024.0)) -1),500.0/767.0));
   
    p1=(3000000.0*pow(3.0,17.0/233.0)*pow(10,102.0/233.0))/(pow((55950.0 * (4.685/((raw1 * 4.685)/1024.0)) -1),250.0/233.0));

    logFile1 = SD.open("muest10.txt", FILE_WRITE);//Grafica3.txt


  if (logFile1) { 
        logFile1.print(myTime);
        logFile1.print(";");
        logFile1.print(p);
        logFile1.print(";");
        logFile1.println(p1);
        
        logFile1.close();
  } 
  else {
    Serial.println("Error al abrir el archivo 2");
  }
  anterior=myTime;
}

El tipo de SD juega un papel en la velocidad.

Puede ganar un poco si no abre y cierra el archivo para cada lectura y deja que la biblioteca SD administre el búfer por usted (es decir, vacíe el búfer solo cuando esté lleno). Para eso, abra el archivo en la setup() y no lo cierre después de la escritura.

Necesitará alguna forma de decirle al Arduino que la adquisición ha finalizado (un botón pulsador, por ejemplo) para que emita el comando de cierre si se detecta una pulsación. Eso asegurará que todos los datos se guarden correctamente en la SD.

(Sin embargo, espere que de vez en cuando se vuelva más lento, ya que el búfer deberá escribirse)

Cuando buscas perfomance hay que optimizar todo. Estas cuentas son reiterativas, porque no las simplificas. Los valores que se repiten manéjalos como constantes asi el micro no debe calcularlos en cada iteracción, ganarás algo no demasiado pero algo seguramente.
Luego cuando debes trabajar en velocidad en una SD hay que crear un buffer circular.
En la librería SD hay un ejemplo llamado logger o algo parecido, no es fácil, pero tal vez puedas adaptarlo.
Comienza con lo que te he sugerido y si no resuelve el problema, avanza con esto otro.
Si defines esto

#define K1 1500.0*pow(2.0,466.0/767.0)*pow(3.0,233.0/767.0)*pow(5.0,699.0/767.0)
#define K2 55720.0*4.685*1024.0
#define K3 500.0/767.0

Resumes la primer ecuación en esto

p = K1/(pow(K2/(4.685*raw -1), K3);

Revisa a ver si obtienes lo mismo. He desarrollado la expresión

55720.0 * (4.685/((raw * 4.685)/1024.0)) -1

para poder llevar el 1024 al numerador y obtener un número muy grande. Dudo que se conserve a nivel de mantisa.
Es el K2 justamente.

Bueno, me tenté y ajusté p1 tmb, no lo describo para no aburrirte, pero te encomiendo que verifiques que las simplificaciones funcionan.
Tambien tiene la sugerencia de @J-M-L

#include <Arduino.h>
#include <SD.h>

#define K1 1500.0*pow(2.0,466.0/767.0)*pow(3.0,233.0/767.0)*pow(5.0,699.0/767.0)
#define K2 55720.0*4.685*1024.0
#define K3 500.0/767.0



#define K4 3000000.0*pow(3.0,17.0/233.0)*pow(10,102.0/233.0)
#define K5 55950.0*4.685*1024.0
#define K6 250.0/233.0


#define CSpin 9

File logFile1;

int analogPin   = A0;
int analogPin1  = A1;

int raw1        = 0;
int raw         = 0;

float p;
float p1;

unsigned long myTime;
volatile unsigned delta=0;
volatile unsigned anterior =0;

void setup() {
  Serial.begin(115200);// con estos baudios transmitimos a 110Hz 
  Serial.print(F("Iniciando SD ..."));
  
  if (!SD.begin(CSpin))   {
    Serial.println(F("Error al iniciar"));
    return;
  }
  Serial.println(F("Iniciado correctamente"));
  logFile1 = SD.open("muest10.txt", FILE_WRITE);//Grafica3.txt

}

void loop()
{
    myTime = millis();
    delta = myTime-anterior;
    Serial.println(delta);
    raw= analogRead(analogPin);
    raw1= analogRead(analogPin1);
  
    p  = K1/(pow(K2/(4.685 * raw  -1), K3);
    p1 = K4/(pow(K5/(4.685 * raw1 -1), K6));
    
    if (logFile1) { 
        logFile1.print(myTime+";"+P+";"+P1);       
    } 
    else {
        Serial.println("Error al abrir el archivo 2");
        logFile1.close();
    }
    anterior=myTime;
}

Repito no esta probado, tengo problemas con mi disco.

el optimizador notará que son constantes y hará los cálculos en tiempo de compilación, por lo que no creo que haya mucho que ganar allí. (y el #define se reemplazaría directamente en el código, por lo que sería lo mismo. un const double sería mejor)

¿Que cantidad de datos necesitas por medición?

Buenas lo que guardo en la sd son dos floats que en principio tendrian la forma xx.xx ; xx.xx
Gracias a todos por la ayuda estoy probando lo que me decis

Buenas,
El problema de que el código vaya tan lento (tarda 20ms en hacer el loop) es, como bien han dicho, que estaba abriendo y cerrando constantemente el archivo. He probado también ha simplificar el numerador de las operaciones pero el cambio era mínimo. Actualmente he hecho esta "chapuza" para probar si era ese el problema pero no se como solucionarlo.
Un saludo y muchas gracias a todos por la amabilidad, la rapidez y sobre todo por lo rápidos que habéis sido:

 #include <SD.h>
 
 File logFile1;
 
 int analogPin= A0;
 int analogPin1 = A1;
 
 int raw1 =0;
 int raw= 0;
 
 float p;
 float p1;
 
 unsigned long myTime;
 volatile unsigned delta=0;
 volatile unsigned anterior =0;
 
 void setup()
 {
   
   Serial.begin(115200);
    Serial.print(F("Iniciando SD ..."));
   if (!SD.begin(9))
   {
     Serial.println(F("Error al iniciar"));
     return;
   }
   Serial.println(F("Iniciado correctamente"));
   logFile1 = SD.open("muest2.txt", FILE_WRITE);
 
   
 }
 
 void loop()
 {
   delay(5);
     myTime = millis();
     delta = myTime-anterior;
     Serial.println(delta);
     raw= analogRead(analogPin);
     raw1= analogRead(analogPin1);
   
     //p=(1500.0*pow(2.0,466.0/767.0)*pow(3.0,233.0/767.0)*pow(5.0,699.0/767.0))/(pow((55720.0 * (4.685/((raw * 4.685)/1024.0)) -1),500.0/767.0));
     p=13833.348750/(pow((55720.0 * (4.685/((raw * 4.685)/1024.0)) -1),500.0/767.0));
    
     //p1=(3000000.0*pow(3.0,17.0/233.0)*pow(10,102.0/233.0))/(pow((55950.0 * (4.685/((raw1 * 4.685)/1024.0)) -1),250.0/233.0));
     p1=8906373.771060/(pow((55950.0 * (4.685/((raw1 * 4.685)/1024.0)) -1),250.0/233.0));
 
    
 
   if (logFile1) 
   { 
     
         logFile1.print(myTime);
         logFile1.print(";");
         logFile1.print(p);
         logFile1.print(";");
         logFile1.println(p1);
         
         //logFile1.close();
   } 
   else {
     Serial.println("Error al abrir el archivo 2");
   }
  if(myTime>=10000)
   {
     logFile1.close();
     Serial.println(F("Cerrando SD"));
  }
   anterior=myTime;
   
 }

como se puede ver lo que he hecho es cerrar el txt a los 10 segundos. seguramente haga que se cierre cuando apriete un botón o si alguien me puede decir como hacer para que se cierre cuando cierro el monitor serie también me valdría.

Hacer los calculos una vez es mejor que hacerlos varias supongo. Ese fue mi objetivo.
De todo modos luego lo pruebo a ver si tengo razón o la tienes tu.

Moderador:
Por favor, lee las Normas del foro y edita tu código usando etiquetas.
Lo habias hecho bien al comienzo, no te olvides.

Hay dos errores importantes en el código

unsigned long myTime;
volatile unsigned delta=0;
volatile unsigned anterior =0;

deben ser ambos unsigned long

unsigned long myTime;
unsigned long delta;
unsigned long anterior;

Y no hace falta ponerlos a 0, por varias razones, pero la principal es porque el compilador lo hace.
Ademas, delta y anterior se cargan con valores y nunca resuelven cuentas con valores que comienzan en 0.

Hice cuentas y las dos operaciones tal como estan insumen 4 useg asi que lo que hice es una pavada!!
He hecho las cuentas con y sin define y @J-M-L tiene razón, insumen el mismo tiempo.
Como estaba en useg = 4
Con define en useg = 4

EDITO:
Se me ocurrió hacer un loop de varias muestras y mejora muchísimo.
Tienes que tener paciencia para guardar los datos.

#include <SD.h>

#define K1 1500.0*pow(2.0,466.0/767.0)*pow(3.0,233.0/767.0)*pow(5.0,699.0/767.0)
#define K2 55720.0*4.685*1024.0
#define K3 500.0/767.0

#define K4 3000000.0*pow(3.0,17.0/233.0)*pow(10,102.0/233.0)
#define K5 55950.0*4.685*1024.0
#define K6 250.0/233.0


const byte analogPin   = A0;
const byte analogPin1  = A1;

#define N  100 // cantidad de muestras.

struct _Datos {
  unsigned long myTime;
  unsigned int raw1;
  unsigned int raw2;
  float p1;
  float p2;
};

_Datos datos[N];

unsigned long myTime;
unsigned long delta;
unsigned long anterior;

#define CSpin 9

File logFile1;

void setup() {
  Serial.begin(9600);// con estos baudios transmitimos a 110Hz 
  Serial.print(F("Iniciando SD ..."));
  
  if (!SD.begin(CSpin))   {
    Serial.println(F("Error al iniciar"));
    return;
  }
  Serial.println(F("Iniciado correctamente"));
  logFile1 = SD.open("muest10.txt", FILE_WRITE);//Grafica3.txt

}

void loop() {

    for (int i=0; i<N; i++) {
        datos[i].myTime = millis();
        delta = datos[i].myTime-anterior;
        Serial.println(delta);
        datos[i].raw1= analogRead(analogPin);
        datos[i].raw2= analogRead(analogPin1);
  
        datos[i].p1 = K1/pow(K2/(4.685 * datos[i].raw1  -1), K3);
        datos[i].p2 = K4/pow(K5/(4.685 * datos[i].raw2 - 1), K6);
    }
    
    
    if (logFile1) { 
        for (int i=0; i<N; i++) {
            logFile1.print(datos[i].myTime);
            logFile1.print(";");
            logFile1.print(datos[i].p1);
            logFile1.print(";");
            logFile1.println(datos[i].p2);  
        }
    } 
    else {
        Serial.println("Error al abrir el archivo 2");
        logFile1.close();
    }
    anterior=myTime;
}

si usa #define, esto es solo una sustitución de texto, por lo que no cambia nada, si tuviera que definir una constante, entonces el preprocesador haría los cálculos solo una vez.

const double  K1 = 1500.0*pow(2.0,466.0/767.0)*pow(3.0,233.0/767.0)*pow(5.0,699.0/767.0);
const double  K2 = 55720.0*4.685*1024.0;
const double  K3 = 500.0/767.0;

const double  K4 = 3000000.0*pow(3.0,17.0/233.0)*pow(10,102.0/233.0);
const double  K5 = 55950.0*4.685*1024.0;
const double  K6 = 250.0/233.0;

1 Like

Bueno quedo claro eso al menos para mi, tendrá que hacer los cálculos y reemplazar por constantes, de todos modos el tiempo que lleva hacerlos para un NANO es de 4 useg no es ni será significativo.

Para ver cuando se cierra el monitor serie es con if(!Serial) pero también deberías agregar en alguna parte del código if(Serial) para que cuando se abra el monitor empiece a guardar datos.

En Uno, Nano, etc. if(Serial) siempre devuelve true, esté o no conectado. Solo Leonardo/Micro y creo Due, devuelven el estado real de la conexión.

Quiero decir que según que placa use, if(Serial) puede no dar los resultados esperados

De hecho, en Nano,

void Setup(){

  byte x = 0;

  if(Serial) x++;  // atención Serial todavía no se ha inicializado
  if(!Serial) x = 127;
  Serial.begin(9600);
  Serial.println(x);  // imprime "1"
}

void Loop(){
}

a pesar que Serial no fue inicializado, x se incrementa (porque se cumple el primer condicional), y en la consola se imprime 1.
x no toma el valor 127 porque la segunda condición no se cumple, aunque se esperaría que sea la correcta.

Por otro lado, cerrar y abrir la consola puede provocar el reset del arduino.

Saludos