Go Down

Topic: puerto serial lento, mas velocidad con interrupciones (Read 158 times) previous topic - next topic

encrone_90

buenos dias  chicos foreros,  tengo un  inconveniente con el puerto serie tengo este codigo que mediante interrupciones me imprime  valores en voltaje al puerto serial para graficarlo en excel, en matlab, o cualquier software.  el codigo es este:

Code: [Select]

#include <TimerOne.h>  // declarar  uso de libreria
volatile int sensor;  // declarar variable del sensor

void setup() {
  Serial.begin(230400);
Timer1.initialize(650); //1/360=.002777 calculo para interrupcion 360Hz
Timer1.attachInterrupt (timerIsr); // llama la Rutina de interrupcion Timer ISRD
 
 }

void loop() {}

//Rutina de interrupcion
void timerIsr()
{ sensor= analogRead(A0); // lee valores pin A0
 
//float voltaje= sensor+110; // imprimir en bits
float voltaje= sensor*(5.0/1023);  // imprimir en voltaje
Serial.println(voltaje);
}


todo funciona  bien,  al disminuir el tiempo de la interrupción lo máx. que soporta es 650 microsegundos,  pero al disminuir  de 650 deja de imprimir en el puerto serie,  y la velocidad máxima es 1.25KHz  me gustaría aumentarlo un poco mas.


alguna idea?? tengo entendido que al poner  sprintf o imprimir como carácter podría mejorar? pero no lo tengo bien definido como seria el código. me ayudan??  Muchas gracias de antemano

Lucario448

Ugh, aparte de que no se aconseja imprimir al puerto serial durante una interrupción; realizar cálculos con float tampoco debería ocurrir: es muy lento.

Disminuye el prescaler del ADC; o no podrás bajar de 300 microsegundos.


Lo que podrías hacer es ir acumulando las lecturas y luego consumirlas en el programa principal (con los cálculos y todo):

Code: [Select]
#include <TimerOne.h>  // declarar  uso de libreria

unsigned int buffer[256]; // Al hacerlo de 256 elementos, acortaremos un poco más la interrupción.

volatile boolean vacio = true;

byte cabeza = 0;
byte cola = 0;
// Por cuestiones de rendimiento omití la palabra volatile; muy probable no las necesite

void setup() {
Serial.begin(230400);
Timer1.initialize(650); //1/360=.002777 calculo para interrupcion 360Hz
Timer1.attachInterrupt(timerIsr); // llama la Rutina de interrupcion Timer ISRD
 
}

void loop() {  
Serial.println(sacarLectura()*(5.0/1023)); // imprimir en voltaje. Podría imprimir "0.0" por buffer vacío.
}

//Rutina de interrupcion
void timerIsr()
{
if (!vacio && cabeza == cola) return; // No guardar la lectura porque el buffer se llenó

buffer[cabeza++] = analogRead(A0); // lee valores pin A0
vacio = false; // Para indicarle al consumidor que hay lecturas para sacar
}

unsigned int sacarLectura() {

if (vacio) return 0; // El buffer estaba vacío
unsigned int r = buffer[cola++];

vacio = cola == cabeza;
return r;
}

encrone_90

hola lucario buen día,   fíjate que  ya probé  tu código, y si  realizo la escritura  muy bien  pero, es  bastante inestable con el numero de muestras, en  1 segundo captura por ejemplo 2000 al otro 1950  y a otro 2100  me da mucha variación, y con el que puse en un inicio  solo da   1999, 2000, y 2001.

algún consejo para poder lograr una exactitud como el primer código?? si, ya me puse a investigar lo que dijiste  de serial.print durante una interrupción y no se aconseja.  pero tiene  algún efecto negativo??
por que funciona bien.

ilustrame!  lo agradezco de antemano!

Lucario448

algún consejo para poder lograr una exactitud como el primer código??
¿Cómo es posible que en el primero no tuvieras ese problema?
El procesamiento y recolección de los datos es básicamente el mismo; lo cambia es que hay un búfer de por medio para acortar lo que tarda la interrupción.

¿Será que estamos yendo muy rápido como para capturar hasta las fluctuaciones?
¿Qué es lo que intentas medir? ¿Tiene la referencia a tierra bien conectada?

encrone_90

hola lucario, buen dia. 

de verdad   en el programa que te mande apesar de usar  serial print en interrupcion no tuve problemas.

pero  ya vi cual era el problema en tu codigo no es que fuera inestable es que al introducir las  interrupciones en el loop, no se controla bien la frecuencia de muestreo. 

es decir si modifico  el tiempo de la interrupcion a 200,000 micros para solo obtener  5 muestras   
sigue corriendo a tope.

tienes alguna idea de por que no funciona la ISR??


Lucario448

es decir si modifico  el tiempo de la interrupcion a 200,000 micros para solo obtener  5 muestras  
sigue corriendo a tope.
Es porque la función sacarLectura siempre retorna algo aunque el búfer de lecturas esté vacío. Puedo apostar que cuando el búfer está vacío imprime constantemente "0.0".

Por cuestiones de señalamiento, podría hacer que retorne -1 cuando está vacío; pero si retorna -1 como unsigned int, más bien sería 65535.

Go Up