Go Down

Topic: Interrupciones internas (Read 294 times) previous topic - next topic

Stop_Me

¿Arduino puede hacer interrupciones internas con Timer de cada 400us?. Para tomar datos de un sensor.

Lucario448

No sé para qué una interrupción, pero con el timer1 es posible (y con bastante precisión). No más tener cuidado ya que existen funciones que dependen también de otras interrupciones.

Stop_Me

#2
Apr 30, 2017, 08:32 pm Last Edit: May 01, 2017, 04:41 am by surbyte Reason: Código sin etiqueta
Code: [Select]
#include <avr/io.h>
#include <avr/interrupt.h>

int LedPin=9;
int m;
volatile byte s;
int Vdata[65];
const int VPin = A0, IPin = A1;
void setup(){
 Serial.begin(115200);
 pinMode(LedPin, OUTPUT);
 
 cli();
 TCCR1A=0;
 TCCR1B=0;
 TCNT1  = 0;
 OCR1A=3.0064102564102564;//7811.5;//1.0032051282051282;
 TCCR1B |= (1<<WGM12);
 TCCR1B |= (1<<CS10);
 TCCR1B |= (1<<CS12);
 //TCCR1B |= (1 << CS12) | (1 << CS10); // Set CS12 and CS10 bits for 1:1024 prescaler

 //TCCR1B |= (1 << WGM12); // turn on CTC mode
 TIMSK1=(1<<OCIE1A);
 sei();
 
}

void loop(){

}

ISR(TIMER1_COMPA_vect){
 s++;
Vdata[s]=analogRead(VPin);
digitalWrite(LedPin, !digitalRead(LedPin));

}



tengo este cadigo pero no se como leer los datos del sensor y como denteder el timer1, quisiera el timer trabajara por un tiempo y luego se desactivaray luego leer los datos con un for en el loop pero si lo hago la velocidad de muestreo del timer1 se altera cuando la mido con un multimetro

Lucario448

Code: [Select]
OCR1A=3.0064102564102564;
¿Esto te sirve? No recuerdo que fuera posible asignar un valor con decimales a un registro que funciona con enteros.

Prescaler en 1024 imposible que se te ejecute exactamente cada 400 us.

Code: [Select]
digitalWrite(LedPin, !digitalRead(LedPin));
Definitivamente no recomendaría esto en una ISR; dos funciones que cada una tarda entre 5 y 10 microsegundos.
De todas formas, si es para visualizar la ocurrencia de una interrupción de cada 400 us (2.5 KHz) mediante un LED; solo verás una luz constante y un tanto tenue. El ojo humano a duras penas logra percibir una conmutación de luz de 60 Hz, ¿y todavía pretendes visualizar una que va a 2500 Hz?


Vamos a ver si lo capto: tienes un array, y quieres hacer mediciones a un intervalo constante; creo que la solución es convertir ese array en un "búfer circular". Al punto que quiero llegar, es en aplicar el modelo llamado "productor-consumidor": la interrupción produce mientras que el programa principal consume. El mismo concepto es aplicado en Serial, Wire o cualquier otro medio de comunicación asincrónico.


Por cada array o búfer, necesitas 3 contadores: índice del productor, índice del consumidor y cantidad de datos producidos (sin consumir); además de una constante la cual es el tamaño de ese array:

Code: [Select]
#define TAMANIO 65
volatile byte idxProd;
byte idxCons;
volatile byte disponibles;
volatile int Vdata[TAMANIO];

El productor funciona de la siguiente manera:

Code: [Select]
ISR(TIMER1_COMPA_vect){
  if (disponibles == TAMANIO) return; // Búfer lleno, no hacer nada entonces. Opcionalmente se puede deshabilitar esta interrupción para evitar el sobrecargo en caso de que esta situación se dé repetidas veces.
  if (idxProd == TAMANIO) idxProd = 0; // Por esto es que se llama "circular"
  Vdata[idxProd++] = analogRead(VPin); // Produce un dato
  disponibles++; // Y mediante esta variable es que se reporta cuánto hay para "consumir"
}


Y el consumidor así:
Code: [Select]
int recuperar() {
  if (!disponibles) return -1; // -1 significa intento de lectura con el búfer vacío
  if (idxCons == TAMANIO) idxProd = 0; // Por esto es que se llama "circular"
  byte temp = SREG;
  cli();
  disponibles--; // Esta parte se le llama "código crítico"; ya que la interrupción y el programa principal comparten esta variable, llamamos previamente a cli() para evitar inconsistencias.
  SREG = temp;
  return Vdata[idxCons++]; // Y aquí es donde recupera el dato
}

Espero y ojalá que algo como esto te sirva...

Go Up