...
¿Os podéis creer que si le quito ese delay_ms(10) me hace los cálculos mal y me devuelve resultados aleatorios.
Pregunta tonta: alguno de los valores de las variables dentro de ese bucle ¿cambia por alguna interrupción o un DMA o algo parecido?En teoría no, don Diego, porque si miras el fuente, el cálculo sólo se hace cuando capturado=1, mientras que el array se modifica en la interrupción del Timer cuando capturado=0.
:shock: ¿Podés subir un bloque "compilable" donde haga el error?Aquí va:
Llevo dándole vueltas un buen rato a un bucle donde calculo la corriente consumidaCódigo: C
for (i=0;i<IndMuestra;i++) { delay_ms(10); corriente = (muestras[i]-OFFSET)*AJUSTAADC * 4.6; SumaMuestras+=muestras[i]; muestras[i]=0; onda = onda + corriente*corriente; }
¿Os podéis creer que si le quito ese delay_ms(10) me hace los cálculos mal y me devuelve resultados aleatorios.
....:shock: ¿Podés subir un bloque "compilable" donde haga el error?Aquí va:Código: C
#include <18F1320.h> #device ADC=10 #device HIGH_INTS=TRUE #include "math.h" #FUSES NOWDT //No Watch Dog Timer #use delay(internal=8MHz) #use rs232(baud=115200,parity=N,bits=8,stream=PORT1, xmit=PIN_B1, rcv=PIN_B4) #define SALIDA PIN_B3 #define MUESTRASENCICLO 72 #define NUMMUESTRAS MUESTRASENCICLO*10 // Cada onda a 50Hz está dividida en 36 muestras. Cogemos 10 ondas #define OFFSET 512.0 // Restamos 512 porque la señal tiene un offset de 2.5V #define AJUSTAADC 5.0/1024.0 // 5V a 10bits de resolución unsigned int16 muestras[50]; int16 buffer, objetivo; float onda, consumo; int16 potencia; unsigned int8 capturado, calculado; unsigned int8 contadorPWM, cortePWM; unsigned int8 IndMuestra=0; #INT_RDA HIGH void intser() { char c; if ((c>='0') && (c<='9')) buffer = buffer*10 + c - '0'; if ((c == '\r')) { objetivo = buffer; buffer=0; } if (c=='0') output_low(SALIDA); if (c=='1') output_high(SALIDA); // Como la interrupción RDA habrá interrumpido la lectura de la onda, empezamos de nuevo IndMuestra=0; onda = 0; } #INT_EXT void cruce_por_cero() { output_low(SALIDA); set_timer2(0); contadorPWM=0; if (!capturado) { capturado=1; } if (calculado) { calculado=0; capturado=0; IndMuestra=0; } } #INT_TIMER2 void LeerADC() { if (!capturado) { muestras[IndMuestra]=read_adc(); IndMuestra++; }; if (contadorPWM++ == cortePWM) { output_high(SALIDA); } } void main() { int8 i; float corriente; int16 SumaMuestras; setup_adc_ports(sAN0, VSS_VDD); setup_adc(ADC_CLOCK_INTERNAL | ADC_TAD_MUL_0); output_low(SALIDA); setup_timer_2 (T2_DIV_BY_1,198,2); // 187 para 36 ciclos output_float(PIN_B0); output_float(PIN_B4); set_adc_channel(0); onda = 0; IndMuestra=0; contadorPWM=0; enable_interrupts(INT_TIMER2); enable_interrupts(INT_RDA); enable_interrupts(INT_EXT); enable_interrupts(GLOBAL); delay_ms(50); objetivo = 0; cortePWM=25; while (1) { if (capturado) { onda=0; SumaMuestras=0; if (IndMuestra==50) { for (i=0;i<IndMuestra;i++) { delay_ms(10); corriente = (muestras[i]-OFFSET)*AJUSTAADC * 4.6; SumaMuestras+=muestras[i]; muestras[i]=0; onda = onda + corriente*corriente; } if (!SumaMuestras) {// eliminamos el ruido consumo=0.0; potencia = 0; } else { potencia = (int16)(consumo * 181.0); } printf ("%u -> %6.2fA -> %4luW. Obj %lu - CortePWM %u\n", IndMuestra, consumo, potencia, objetivo, cortePWM); } if ((potencia<objetivo) && (cortePWM>0)) cortePWM--; if ((potencia>objetivo) && (cortePWM<49)) cortePWM++; calculado=1; } } }
Deberías dejar a un lado los "delays" y programar en estados de máquina (o máquina de estados). Te permite aislar los procesos en tareas independientes y la búsquedas de errores se simplifica.
Aunque también, ese tipo de errores en el CCS no me sorprende en ese compilador.
Mirá, cuando simulo ese código veo que el índice IndMuestra alcanza el valor 58 antes de resetearlo --> Como muestra[] es de 50 elementos se está escriibiendo sobre las variables que hay después --> resultado impredecible.
.... Si le inyectas una señal cuadrada de 50Hz por la interrupción externa, IndMuestra no pasa de 50.Le inyecte un pulso de 50hz duty 5%, y llegaba a 58.
...
.... Si le inyectas una señal cuadrada de 50Hz por la interrupción externa, IndMuestra no pasa de 50.Le inyecte un pulso de 50hz duty 5%, y llegaba a 58.
...
Deberías dejar a un lado los "delays" y programar en estados de máquina (o máquina de estados). Te permite aislar los procesos en tareas independientes y la búsquedas de errores se simplifica.
Aunque también, ese tipo de errores en el CCS no me sorprende en ese compilador.
Pero si precisamente lo que quiero es eliminar el delay_ms. Está puesto ahí artificialmente porque de lo contrario los cálculos no funcionan bien. No es una tarea síncrona; todo lo contrario.
No sé por qué pero me da que tiene algo que ver con las operaciones matemáticas con los float; ¿pudiera ser que se ejecutan en segundo plano y sólo tiene tiempo de realizarlas cuando meto delays en el bucle principal?
Hola, ya va por la version 5.109.... :D
capturado=0;al final del cálculo, aunque no es del todo prolijo porque en #INT_TIMER2 se sigue haciendo conversiones.
IndMuestra=0;
El problema está en el reset de las variables Indmuestra y capturado.
Cuando terminás el cálculo activás calculado, pero capturado se resetea recién con #la INT_EXT --> Iniciará otro cálculo, pero como la interrupción e #INT_TIMER2 le alterarán Indmuestra hará cualquier cosa.
Lo solucionás agregandoCitarcapturado=0;al final del cálculo, aunque no es del todo prolijo porque en #INT_TIMER2 se sigue haciendo conversiones.
IndMuestra=0;
Con el delay de 10ms andaba porque la #INT_EXT reseteaba capturado antes del primer cálculo.
....No, la desacticación es/era un bug de CCS con algunos micros, en este caso no se desactivan.
En pocas palabras. Usar un delay, desactiva todas las interrupciones (bandera GIE = 0) hasta finalizar el retardo. Sin el delay, la interrupción sucede mucho más antes que 10 ms y aparece el problema.
¿Estoy en lo correcto?
Acá pasa que cuando termina de hacer el cálculo, como capturado sigue activado se ejecuta de nuevo. Pero como las interrupciones te cambian Indmuestra el for se termina donde lo agarre.
Con el delay de 10ms , llegaba antes la interrupción externa y resetea capturado.
Perdón, señores del CCS. Esta vez la culpa no fue vuestra :D