¿Cómo programar un código más robusto?

Mi técnica es hacer una rutina principal corta que llame a subrutinas y luego regrese a esa rutina principal; nunca he visto que se bloquee o falle inesperadamente ... solo cuando hay alguna variación brusca en la alimentación.
Esta solución es clásica, desde luego, pero no deja de ser un "delay encubierto", es decir: estamos malgastando ciclos de procesamiento en el caso normal en que no haya que hacer nada. Como diría Scooter, malgastamos vatios, convirtiéndolos en calor, sin ninguna utilidad.

Scooter indica que siempre hay que hacer alguna cosa, en esos bucles, pero muchas aplicaciones consisten en esperar que ocurra un evento del exterior. Leer el estado de los botones es una tarea, sí, pero si el resultado es que el usuario no ha pulsado ningún botón, entonces esos ciclos se suman a los perdidos, en el bucle principal.

Por todo ello, los microcontroladores traen una instrucción de SLEEP, que duerme el procesador, dejando los puertos de entrada preparados para recibir alguna interrupción, y en algunos casos, los temporizadores funcionando, provocando una interrupción al final del conteo.

Si tu aplicación puede quedarse dormida, porque todos los posibles eventos pueden asociarse a interrupciones, estamos hablando de que tu batería puede pasar de durar un par de semanas, a durar meses.

En Youtube hay unos cuántos vídeos que muestran las diferencias de consumos y trucos para llevar el consumo al límite (inferior), como por ejemplo estas magníficas 4 partes con muy buenos gráficos, Reducing Arduino's Power Consumption Part 1

Deberíamos volver al tema que nos ocupa: la robustez. ;)
 
Si, en algunos casos echar a dormir el micro es una opción. Pero yo al menos nunca he hecho nada así, mis sistemas siempre trabajaban 24/7/365.
Por ejemplo, una calculadora se echa a dormir hasta que pulses el botón de ON. Si en vacaciones no la usas, no se enciende nunca.

Respecto a la robustez, para mi hay dos tipos de código: el que se cuelga y el que no se cuelga.
En C será más difícil meter la pata, en ensamblador si no vigilas la pila etc puede que la desbordes o que no recuperes bien los datos y se corrompa. Pero siempre puede haber un bug en una condición extraña que cuelgue el sistema cada dos meses porque "se alineen los astros" eso es cuestión de depurar bien.
El resto de la robustez, para mi viene del hard; Buena fuente, apantallamientos, optoacopladores etc.

He visto muchos sistemas que funcionan y no sé por qué, porque pasean sin más las señales con cables sin más por sitios inverosímiles.

En ese aspecto, uniendo este hilo con el del 8085, a mi me parecen más robustos los microcontroladores que los microprocesadores, seguramente porque los buses del sistema están dentro de un chip y no salen de él y son mucho más inmunes al ruido eléctrico.


 
Para que el codigo sea "robusto" lo primero que hay que hacer es resolver el problema en forma "simple" y trazable, sin agregar experimentos ni ideas luminosas. No hay que optimizar NADA hasta tener la certeza de que el programa funciona cumpliendo los requisitos.
Debe haber un modelo del programa (top-down, UML, lo que sea) que permita analizar y trazar el comportamiento.
No usar herramientas sofisticadas si el contexto no lo requiere, es decir, si con un delay funciona y cumple los requisitos, pues se usa un delay y ya.

Claro que todo esto requiere que el diseñador tenga los conocimientos y la mente clara. Hoy hay tantas herramientas que cualquier mermo hace software, pero no cualquier mermo piensa en estabilidad, performance, uso de recursos, escalabilidad, etc, etc.

 
mira usare un DELAY para que mas o menos veas como puedo hacer un retardo grande sin usar un delaysote solo usando un delaysito.


usare seudo codigo para que veas como mas o menos se hace , escribire en un display cada segundo usando un delaysito.

Código:
incremento=0

bucle infinito
{

[COLOR="Red"][B]SI incremento >=  100 [/B][/COLOR]//100 veces mi incremento es 1 segundo
entonces 
 incremento=0  //reinicio mi incremento
 escribo display " me reescribo cada 1 segundo"



[B]delaysito 10ms[/B]
incremento++  cada 10ms se incrementara 

} // regreso al bucle infinito


¿cual es la idea?

como se ve en lugar de hacer un delaysote use un minidelay para reescribir una pantalla
se puede usar esta idea en cualquier lenguaje.

pero SI se puede sustituir ese mini delay con un timer propio del cualquier micro y darle una patada al delay usando el mismo ejemplo

ahora con un timer


Código:
incremento=0
bandera =0     //declaro una variable nueva llamada bandera puede ser cualquier nombre

declaro mi timer a un desborde de 10ms
{
incremento++

SI incremento >=100 
entonces 
bandera =1
incremento=0
}



bucle infinito
{


SI bandera ==1 
entonces

 escribo display " me reescribo cada 1 segundo"
 bandera=0 //reinicio mi bandera a 0 


} // regreso al bucle infinito
 
Última edición:
El problema de los minidelays es que acumulas error y sigues perdiendo ciclos. Eso sí, es mejor que uno grande.
Si no tienes mucha carga de trabajo y no necesitas precisión es una opción mejor que matar un sistema varios segundos.



 
Las máquinas de estados y los uC son una buena combinación. ;)

Incluso las máquinas son tan útiles, que programas de alto nivel suelen ser útiles para manejar una interfaz de usuario.
 
yo creo que por default.

es como el goto en C no le veo chiste de hacer un codigo espagueti en C pero existe goto como si se tratara de basic.

si es cierto que delay es comodo pero usar delay y goto terminas haciendo un programa plano, monotarea o espaguetizado.

pero para hacer algo para ver si funciona es como agarrar palitos silicon y maskingtape y ver que funciona y dices ahhh ahora si vi que funciona lo voy a hacer bien.
 
Yo creo que por inercia. La gente aprendió a usar delays, y como son facilones ya siguen explicando así. Yo creo que hay gente que no sabe lo que es un timer y "vive feliz".
Pero si, me sorprende mucho que el delay esté en el cuerpo de arduino y la librería de los timers sea un añadido reciente, hasta hace poco había que hacer un túnel hasta el C estandard y manejar los timers desde ahí.
Debería de estar, porque es útil, pero con un letrero en rojo parpadeante de "solo usar para monear".

 
Yo creo que es... porque lo dicen los libros, usados por los profesores.

Estoy mirando el primero, "Microcontroladores PIC. Diseño práctico de aplicaciones", de José Mª Angulo Usategui e Ignacio Angulo Martínez. McGraw-Hill, 3ª edición, 2003.

En él, se comenta un ejercicio para el parpadeo de un LED.

La versión en ensamblador usa un temporizador, cuyo valor se va comprobando en un bucle (cuando se comprueba que el temporizador llega a 1, se cambia el valor del LED, y vuelve a bucle, a seguir esperando).

La versión en C, comenta las funciones delay_*() de la biblioteca que ofrece el compilador PCM.

Pero... solo un par de páginas más adelante, comenta otro ejemplo en el que hace uso del temporizador para hacer parpadear el mismo LED, esta vez usando el poder de la interrupción del propio temporizador, mientras que el proceso principal se dedica a explorar el estado de otras entradas.

Entonces... si los profesores o alumnos que tuvieron acceso a este y a otros magníficos libros, no les dio la gana pasar la página para aprender una técnica más, es culpa suya.

Como profesor, yo enseño a los alumnos todas las técnicas, y a diferencia de Scooter, sí que animo a los alumnos a que usen retardos. Tanto los bucles vacíos como los bucles principales están consumiendo ciclos de máquina sin cesar, pero... ¿qué importa? La mayor parte de los problemas se resuelve así porque el sistema lo permite. Y se tiene energía de sobra.

Lo que importa es enseñarles el concepto de eficiencia energética, y por qué es importante. Alargar la vida de los componentes, de la batería, del propio microcontrolador, el calor/ruido generado.... todo esto es un plus para ellos, que los convertirá en mejores profesionales.
 
yo aprendi con delays por que no sabia como declarar y calcular un timer.

pero cuando queria hacer 2 tareras diferentes como escribir un display mientras controlaba un motor tenia que hacer por pedacitos.

el problema es que el delay me hacia un programa plano y monotarea.

cuando vi como declarar los timers vi que podia hacer cosas mas como controlar el brillo de un led mientras controlaba un motor y recibia datos del puerto serie todo casi al mismo tiempo.


ese es un problema comun profesores que por acabar rapido el tema dicen haganlo asi.

pero la culpa es de los alumnos tambien
por que no quieren investigar, quieren que el profesor se los diga peladito y en la boca.
 
Y como lo harian en caso de leer 8 entradas analogicas?

Código:
               set_adc_channel(0);  //PREPARO PARA PRIMER EJE
               delay_us(10);              
               Eje1=read_adc();
               set_adc_channel(1);  //PREPARO PARA EJE 2
               delay_us(10);
               Eje2=read_adc();
               set_adc_channel(2);  //PREPARO PARA EJE 3
               delay_us(10);
               Eje3=read_adc();
               set_adc_channel(3);  //PREPARO PARA EJE 4
               delay_us(10);
               Eje4=read_adc();
               set_adc_channel(4);  //PREPARO PARA EJE 5
               delay_us(10);
               Eje5=read_adc();
               set_adc_channel(5);  //PREPARO PARA EJE 6
               delay_us(10);
               Eje6=read_adc();
               set_adc_channel(6);  //PREPARO PARA EJE 7
               delay_us(10);
               Eje7=read_adc();
               set_adc_channel(7);  //PREPARO PARA EJE 8
               delay_us(10);
               Eje8=read_adc();

Aca el delay es muy corto, pero se repite 8 veces, como se podria hacer? hay otra manera o para leer los analogicos si o si va el delay?
 
Última edición:
Por favor, lee la última parte de #20.

Es muy posible que ni siquiera necesites usar retrasos, ya que el mismo proceso de lectura del ACD es lento.
 
¿Y cómo lo harían en caso de leer 8 entradas analógicas?
Para ahorrar pines, yo uso este circuito integrado: TLC1543C
Acá el retardo es muy corto, pero se repite 8 veces.
¿Cómo se podría hacer? ¿Hay otra manera o para leer los analógicos, o sí o sí va el retardo?
Lo que se debe hacer es leer la bandera de conversión finalizada. (GO/DONE)
Y para que el ADC vaya lo más rápido posible, hay que seleccionar bien su configuración conforme al reloj del micro. (Bits ADCSx)
 
Por favor, lee la última parte de #20.

Es muy posible que ni siquiera necesites usar retrasos, ya que el mismo proceso de lectura del ACD es lento.


Gracias, habia pasado por alto ese mensaje, ahí lo leí, vos decis que si le saco los delay funcionaria igual? dentro del bucle leo 8 entradas analogicas, y 4 digitales de 8 bits, para leer 32 botones, ademas de otras funciones (dos encoders por interrupcion, y el encendido de varios leds), si bien funciona bien, noto que algunos botones a veces no responden como deberian.


Para ahorrar pines, yo uso este circuito integrado: TLC1543C

Lo que se debe hacer es leer la bandera de conversión finalizada. (GO/DONE)
Y para que el ADC vaya lo más rápido posible, hay que seleccionar bien su configuración conforme al reloj del micro. (Bits ADCSx)

No tengo problemas de pines, porque con 8 potenciometros estoy bien, salvo que multiplexando entradas pueda aprovechar instrucciones, en mi caso no me afecta.

Y el micro lo tengo configurado a 8 bits:

#include <18F4550.h> // Definición de registros internos del PIC18F2550.
#DEVICE ADC=8 // CAD a 8 bits, justificación a a la derecha.

No se si será eso a lo que te referis.
 
Última edición:
Y el micro lo tengo configurado a 8 bits:
#include <18F4550.h> // Definición de registros internos del PIC18F2550.
#DEVICE ADC=8 // CAD a 8 bits, justificación a a la derecha.

No se si será eso a lo que te referis.
No, sino al reloj que se le otorgará al ADC para que realice su tarea más rápido.
ADCON0 Register.jpg

8 bits de resolución para el ADC, es la configuración por defecto en PIC C Compiler, así que aunque no declares #DEVICE ADC = 8, la conversión será a 8 bits.
5 / 256 = 19.5 mV por bit.
#DEVICE ADC = 10 // 10 bits de resolución.
5 / 1024 = 4.88 mV por bit.
 
Al revés, esperar hasta que se desactive, que es cuando la conversión ha finalizado.
Pero el bit GO/DONE tiene dos propósitos.
Se debe activar por software para iniciar la conversión y esperar a que se ponga en cero. (Por hardware)

Por ejemplo: (No en PIC C Compiler, que hace este proceso con read_adc())
ADCON0bits.GO = 1; // Iniciar la conversión.
while (ADCON0bits.GO); // Esperar hasta que termine la conversión.
// Por hacer...
 
pues si como dicen

puedes leer el ADC y cuando la bandera se active puedes hacer una lectura


O también... activar la interrupción de eso que seguramente exista, el 80c537 la tenía, pero como yo sabía que eran 14µs sencillamente intercalaba 15 instrucciones 1µs por si acaso. Eso si, era ensamblador y tenía como diez mil cosas que hacer, así que encontrar 14 o 15 era fácil.

5 ms me parece una salvajada de tiempo, 100ms como el arduino ya ni lo cuento.
El while está bien, así ajustarás para perder solo lo necesario, si son 4,2ms mejor que 10.

Habría que ver que tareas tienes pendientes además de leer los pines y hacerlas en esos 10ms; que fácilmente dan para unos cuantos miles de instrucciones dependiendo del cristal.
 
Última edición:
Atrás
Arriba