Interrupcion por Usart

Queria saber como se hace una interrupcion por recepcion en el protocolo Usart. Por lo que vi, hay que acceder a los registros y no hay libreria disponible.

Si no me equivoco, se supone que serialEvent() hace exactamente eso; sin embargo, si la idea es redefinir cómo los datos son recibidos, sí tendrás que manipular registros ya que ni siquiera podrás hacer uso de la clase Serial.

SerialEvent es una subrutina que se ejecuta al principio del loop. Lo probe al poner un bucle while(1) dentro del loop, y nunca se ejecuto la subrutina del serialevent ya que nunca volvia al prinicipio del loop. Si fuera una interrupcion tendria que atender la rutina.

Y para que pones un while(1) dentro del loop si loop es un while(1).

Si miras cuando compila el IDE veras que lo transforma en una forma int main() donde primero se ejecuta un procedimiento setup() y luego queda en un void loop() que es un while(1) de modo que no cambia nada

Ahora lo que te dijo lucario es lo que necesitas. Ve a los ejemplos del IDE y busca Communication y ahi tienes ejemplos usando SerialEvent() debidamente utilizados y verás que si funcionan.

lo que dije del while(1) adentro del loop es para demostrar que el serialevent es una subrutina que se ejecuta cuando pasa por el void loop, al poner el while(1) el programa queda estancado ahi y nunca pasa por el while(1), ergo, nunca ejecuta la subrutina serialevent. Si serialEvent fuera una interrupcion, por mas que este el programa dentro del while(1) la rutina de atencion a la interrupcion por serial la deberia ejecutar.

Pero estas hablando en el aire.. pon un ejemplo de lo que dices.
Si pones solo

void loop() {
 while(1);
}

// y por aca tu void SerialEvent() bla bla bla

Logico que no ves nada pero que tal con este

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
   while(1) {
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
 }
}

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

Se ajusta esto a tu idea o seguimos hablando en el aire..

Te aclaro que no pretendo ser irónico, no actuar con falsa modestia, solo que tirar una idea sin ejemplos es dificil de interpretar porque para ti esta claro lo que dices pero para mi es simplemente algo sin fundamentos.

Puede que esté equivocado. Pero creo que a lo que se refiere @Chember3 es que serialEvent() no es una función que se invoca al generarse una interrupción relacionada con el puerto serie. Sino que se invoca únicamente entre que termina el loop() y se vuelve a llamar de nuevo el loop(). Únicamente si se ha recibido algún dato. Creo que es lo que dice el comentario del ejemplo:

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/

Con lo que serialEvent() no es realmente una interrupción. En más bien "para que el programa quede bonito y ordenado". Pero si vas a comporbar si ha llegado algún dato con la función Serial.available(), lo mismo da que pongas tu código en serialEvent() que al principio del loop(). Siguiendo el ejemplo:

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
 }
}

... esto hace exáctamente lo mismo, pero sin serialEvent().

Pero supongo que @Chember3 lo que busca es atender él mismo la interrupción que se genera cada vez que se recibe un byte por el puerto serie. Porque siendo así, entre otras cosas, no importaría que se estuviera ejecutando un while(1); ya que se ejecutaría el código de la interrupción cuando fuera necesario (a no ser que estén inhabilitadas).

Él ha puesto adredre el while(1); para verificar que serialEvent() no se invoca en la interrupción que atiende a la recepción de un dato en el puerto serie. Yo habría hecho lo mismo para cerciorarme de ello.

Aclarado todo esto, he de decir que actualmente no tengo ni idea de cómo se hace en Arduino lo que él busca. Pero tal vez la aclaración ayude a alguien a entender qué es lo que busca y sí sabe cómo se hace. Y puede que ese alguien le responda.

Mis disculpas por no explicarme bien. Lo unico que quiero saber es si el codigo de serial event de ejemplo que pusieron en los comentarios es realmente una interrupcion. Es decir que no bien entra un dato por serial, el programa deja lo que esta haciendo y atiende la funcion de serial event. Por lo que probé y leí, serial event solo se ejecuta justo despues de que el programa ejecuta la linea void loop. Se podria decir que es lo “primero” en ejecutarse, despues del void setup claro esta.
Gracias por sus respuestas comprensivas de todos modos soy nuevo en el foro y no lo manejo bien

Aun no teniendo acceso a la interrupción, los datos que se reciben mientras el loop() "está ocupado" se guardan en un pequeño buffer (no sé qué tamaño tendrá) y si el loop() "no se entretiene mucho" con los "mal vistos" delay() o con bucles muy "costosos" y no tiene partes "bloqueantes"; no se tendría porqué perder datos en la recepción. Sí que tal vez pierdas algunos si la velocidad de transmisión es muy elevada o se transmiten muchos bytes "de golpe".

Lo probe al poner un bucle while(1) dentro del loop, y nunca se ejecuto la subrutina del serialevent ya que nunca volvia al prinicipio del loop.

De nuevo.. porque no planteas la situación en la que crees que SerialEvent no funciona asi todos podemos opinar debidamente.
O lo planteas hipotéticamente.

Al no ser serialEvent() realmente una interrupción, sólo te quedan dos opciones:

  • Modificar la librería existente para que la rutina de interrupción invoque otra función. Esto vendría siendo un "arma de doble filo" porque dependiendo del retraso que provoque esa otra función, perfectamente podría haber pérdida de datos hasta incluso retrasar el propio contador de millis()/micros(). ¡Por algo no implementaron semejante característica en la librería original!
  • "Reinventar la rueda"; con esto quiero decir que para redefinir completamente la rutina de recepción, tendrías que abstenerte del todo a utilizar todo lo referente a la clase Serial. Tendrías que escribir tú mismo el código para enviar/recibir los bytes; además de manipular algunos registros porque, como dije antes, olvídate del Serial.begin().

IgnoranteAbsoluto:
los datos que se reciben mientras el loop() "está ocupado" se guardan en un pequeño buffer (no sé qué tamaño tendrá)

Por defecto, 64 bytes. También hay otro de ese tamaño, solo que es para encolar los bytes (ingresados mediante write() o print()) a medida que se van transmitiendo.