Escribo un código (para Atmega168P) para recibir datos de la interrupción USART como se muestra a continuación:
ISR (USART_RX_vect)
{
unsigned char count=0;
unsigned char coder[13];
int over_uart=0;
for (count=0;count<13;count++)
{
while (!recive_485)
{
over_uart++;
wdt;
if (over_uart>=20000) {
coder[0]=0;
count=14;
over_uart=0;
break; }
}
coder[count]=UDR0;
}
}
Cada vez que recibo 13 bytes de datos y los coloco en coder
una matriz.
Uso una variable over_uart
para calcular el tiempo entre cada uno de los bytes recibidos. si over_uart>=20000
, significa que:
El progreso de recepción se inicia, pero tenemos un problema en las líneas que no obtienen el siguiente byte en 20000 ms. Termina el último comando y busca nuevos 13 bytes que recibirá de la línea.
¿Alguien conoce una forma optimizada que encuentre un retraso entre la recepción de datos de USART (sin ayuda de la over_uart
variable)?
EDITAR :
Corrijo el problema en mi código y elimino el retraso puesto en ISI como golpe:
ISR (USART_RX_vect)
{
coder[count]=UDR0;
if (coder[count] == 20)
UartFlag=True;
else
count++;
}
Y en Main
función:
while (1)
{
if (UartFlag)
{
DoSomthing();
count=0;
UartFlag=Fulse;
}
}
Tenga en cuenta que la rutina de interrupción es solo el código al que se salta, nada más. Entonces, su código es totalmente un malentendido:
La mayoría de sus variables deben ser estáticas. En su código, son locales apilados que se recrean en cada interrupción. Además, debido al flujo de código indeterminado causado por las interrupciones, debe deshabilitar las posibles optimizaciones en las variables vulnerables declarándolas como "volátiles".
No hagas ese tipo de bucles allí. Tenga en cuenta que cada entrada de interrupción es parte del bucle de recopilación de datos.
Para resolver el problema, su mejor opción es usar un temporizador de hardware. En cada entrada de interrupción, tome una lectura de un temporizador que se restablece con el código de salida de la interrupción anterior. Por lo tanto, puede determinar fácilmente si hay un desbordamiento y solucionarlo.
Parece que está diseñando algún tipo de protocolo de comunicación que garantiza la integridad de los datos. Su criterio de integridad consiste en recibir una cantidad esperada de datos en un tiempo limitado.
Si bien este enfoque es técnicamente posible, le aconsejo que busque enfoques más estándar (por ejemplo, enviar paquetes con un byte de inicio y una suma de verificación). Dichos enfoques no tienen restricciones de tiempo (en cambio, simplemente analiza un flujo continuo de bytes) y se pueden hacer arbitrariamente robustos (con una suma de verificación lo suficientemente larga, está prácticamente garantizado que nunca recibirá un paquete dañado).
Confiar en el tiempo para las verificaciones de integridad de datos escala muy mal. Su enfoque inevitablemente fallará una vez que su sistema necesite recibir más datos o su código se vuelva lo suficientemente complejo como para introducir demoras internas que no podrá predecir.
Además, si se adhiere a un protocolo estándar como HDLC , XMODEM o MIN , es probable que encuentre bibliotecas que ya lo implementen, lo que le ahorrará mucho tiempo.
Aquí hay una versión de pseudocódigo para su ISR que no entra en un estado de espera en el ISR y no requiere cambios en ninguna otra parte de su programa.
La premisa básica es que el ISR mantiene una copia local del búfer de recepción. Una vez que este búfer tiene 13 caracteres completos dentro del límite de tiempo, pasa el búfer al código principal a través de un búfer global llamado rcv_buff y genera un semáforo llamado data_ready
Para determinar si ha recibido 13 caracteres dentro del límite de tiempo, utiliza la función time() que devuelve el tiempo en segundos desde la época. Si time() no está disponible en su biblioteca, puede crear una función similar desde un reloj del sistema.
ISR:
// declare local_count,local_buff, last_time as local static variables
// rcv_buff and data_ready are globals for main()
local_count++; // bump receive counter
local_buff[local_count-1]=UDR0; // save in local buffer
// time() returns time in secs (since epoch)
if time()-last_time>20 then { // over time limit, empty local buffer
local_count=0; // reset the local character counter
local_buff=''; } // flush the local buffer
last_time = time(); // save current time in secs for next pass
data_ready=False; // squelch the semaphore
if (local_count==13) then { // we have 13 characters, pass to main code
local_buff[local_count)=\0 // ensure string ends with null
rcv_buff=local_buff; // pass the local buffer to main
data_ready = True; // raise the semaphore for main
local_count=0; // reset local buffer for next packet
local_buff=''; } // flush the local buffer
Editar: se limpió la indexación del búfer para la compatibilidad con C. Comentarios mejorados
probablemente quieras entender cómo funcionan las interrupciones en general antes de sumergirte en ellas. Una vez que haga eso, es probable que tenga que volver a escribir su isr por completo.
Dicho esto, una forma de hacer lo que quieres hacer es algo como esto:
current_time = time_now(); //stamp current time
time_elapsed = current_time - previous_time; //calculate the time difference
previous_time = current_time; //update previous time
requiere un marco totalmente diferente al que tienes ahora, por cierto.
Eugenio Sh.
Tony Estuardo EE75
brahans
scott seidman
Ali
coder
por la razón. cuando se activa la interrupción, recibo datos, los introduzcocoder
y continúo con otra tarea... el punto es que DEBO obtener 13 bytes y luego hacer otra tareaAli
Ali
Eugenio Sh.
Tony Estuardo EE75
brahans
coder
, luego salga del ISR . Espere la próxima interrupción, repita hasta que haya puesto 'suficientes' bytescoder
o cualquier otra condición que necesite (como la expiración de un temporizador). No se quede sentado esperando dentro del ISR a que sucedan más cosas.Ali
Ali
chris stratton
Ali