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

Saludos....

Soy algo nuevo en el mundo de la programacion de PIC´s, y por ello la forma de programacion que se me ocurre siempre es la secuencial. Pues, quiero saber si hay formas de programacion para hacer el código algo más robusto...... que no se cuelgue, que no se ande con problemas con el tiempo..... ya que esa forma secuencial presenta problemas de codigo con el tiempo, presenta fallas, y la solcion que encontre es la de programar otra ves el PIC.

gracias.
 
La pregunta sería ¿Quien fue el tarao que inventó los delays?¿En que estaba pensando?¿Que sentido tienen?
No me cabe en la cabeza y la tengo bien grande.

Usando timers oh sorpresa!

Simil humano:
Si en casa tengo que hacer un huevo duro no me quedo al lado del fuego contando hasta mil. Pongo una alarma de un despertador (interrupciones) o miro el reloj cada cierto tiempo (polling) y mientras tanto hago cosas, contesto al teléfono si llaman, abro la puerta si tocan, limpio, me ducho, o cocino otra cosa. Lo que nunca hago es contar hasta mil y no hacer nada más sin oír ni ver en varios minutos.
Un sistema en un delay es un sistema muerto.

Siempre, absolutamente siempre hay algo que hacer y quemar CPU es más que absurdo. Es como comprar un coche de mas caballos e ir pisando el freno todo el rato al mismo tiempo que el acelerador.

Es un tema muchas veces tratado. En mi particular punto de vista son un sinsentido .

 
Última edición:
Entendemos tu odio hacia las esperas. A mi tampoco me gustan.

Pero hay situaciones en las que sí hay que esperar. Ya lo expliqué en un mensaje anterior con el tema de un ascensor: al llegar a un piso hay que esperar entre 100 y 200 ms (la recomendación del fabricante decía 150 ms) para que las puertas dejen de vibrar antes de que su motor las abra. (Sí, esto lo hemos hablado muchas veces, pero no todo es blanco o negro).

Es una espera imperceptible para el que va en el ascensor. Y sirve para alargar la vida de los sistemas mecánicos, como recomendación del propio fabricante.

Lo que sí tengo claro es que no pongo un bucle de espera para mover el ascensor de un piso a otro.

Volviendo al hilo, la recomendación que le doy es que se fije en el organigrama de la aplicación, y que piense qué eventos (hechos imprevistos) pueden suceder en cada paso y entre cada paso.

La robustez de un programa es la resistencia de ese programa a eventos. Por ejemplo, en el caso del ascensor, que el usuario pulse el botón de alarma cuando está entre dos pisos. O que se marche la electricidad y al cabo de un tiempo vuelva: el ascensor estará en cualquier parte y posición. O que las puertas de un piso en concreto no se abran (¿cómo se lo indicamos al usuario?) En sitios con alta actividad sísmica, como Chile, es peligroso que los ascensores funcionen mientras ocurre un temblor de cierta intensidad (los cables pueden salirse de las guías).

Cosa distinta es la homeostasis, que es la facilidad de adaptación a los nuevos cambios. Por ejemplo, y siguiendo el caso del ascensor, si aparece un vecino "gracioso" que se dedica a pulsar todos los botones cuando deja el ascensor, para que el pobre esté funcionando 10 minutos sin dar un servicio real, ¿cómo podemos detectar esta situación y adaptarnos para la próxima vez que ocurra? (quizás no sea importante para viviendas de 5 o 6 pisos, pero sí si son de 10, 15 o 20 pisos) (truco: el ascensor lleva un sensor de paso u obstáculo en las puertas). Si los cortes de electricidad son frecuentes, ¿podemos colocar el ascensor en un sitio adecuado antes de que ocurra? (esto implica que el ascensor aprenda en qué momento del día es más frecuente que ocurra el corte). Si las puertas de un determinado piso tardan cada vez más en abrirse (medidas en ms), ¿cuánto tiempo pasará antes de que el ascensor avise al servicio técnico? (sí: los ascensores ahora son capaces de llamar a "su casa").

Mi recomendación, para el que está empezando, es que lea mucho código. Es un buen medio para aprender soluciones estándar, atajos, trucos y... comenzar a sospechar si el hacer tanto bucle vacío (las esperas) es una buena forma de programar. Más tarde se dará cuenta de que un microcontrolador dormido consume mucha menos energía (instrucción SLEEP en los PIC).

Debería existir un artículo en la Witronica sobre cómo pasar un problema escrito con esperas, a otra solución basada en temporizadores o interrupciones.
 
Última edición por un moderador:
Un delay sin delay se puede hacer de muchas maneras.

Otra cosa que suelen hacer que tambien esta mal es hacer un bucle while dentro de una funcion de leer boton para evitar rebotes.


Bueno los delays son buenos cuando quieres hacer un programa plano , monotarea e imperfecto.

Para hacer un delay de una hora haces esto

while(contador>=(60*60))
{
delay(1000);
contador++;
}
contador=0;

Ese bucle de 1 hora te garantiza no hacer absolutamente nada en 1 hora
 
Última edición por un moderador:
Aprovechando el título muy general del tema cuestiono sobre el uso del watchdog, mucho se habla de activarlo por cuestiones de seguridad, y con justa razón, pero pocos explican bien de cómo usarlo o integrarlo a un algoritmo en concreto (más allá del ejemplo de transmisión serie, espera de interrupciones etc).
En lo particular suelo usarlo en uno que otro desarrollo enfocado a control de válvulas y relés, pero mi conocimiento se limita a no más allá de protección de un lazo de espera o de un evento como los ejemplos que antes dije y que, al actuar, solamente reinician al sistema y es necesario que el operador vuelva a ejecutar la secuencia de inicio y puesta en marcha. (n)

Me interesa una aplicación similar donde el sistema, pese a un problema de cuelgue, pueda retornar al punto donde se "descarriló" sin necesidad de que el usuario interfiera, es más, que ni note tal efecto, pero a veces el programa es algo complicado y me falla la integración con el WDT. De aquí también cuestiono, ¿el tema del WDT se incorpora durante el desarrollo del programa principal?, o bien al final como "cubierta de protección? :unsure:

Alguien instruido en tal tema que pueda aportar ejemplos concretos o sugerencias de uso.

Saludos
 
El Watch-dog, al ser un timer, se desbordará, y cuando eso pase, el microcontrolador se reiniciará.
Por ese motivo, se debe estar reseteando antes de que se desborde.
Eso se debe hacer dentro de las rutinas que puedan durar más del tiempo al que se configuró el WDT.

La configuración del WDT se hace al inicio y siempre es mejor usar los periodos de desborde más cortos.
Pero eso hay que tomarlo en cuenta, dependiendo de cuanto se pueda tardar una rutina compleja.
Y esto con el motivo de no estar reseteándolo constantemente durante el proceso de la misma.

Si el WDT se ha desbordado debido a un cuelgue del programa, el programa se iniciará desde el vector de reset.
Para que se inicie desde otro punto, se tendría que guardar un valor en la EEPROM que dependerá del punto en el que se encuentre el programa.
Para guardar el valor se puede hacer uso de la misma interrupción que genera el WDT.

Al inicio del programa, se deberá leer la EEPROM e ir a la rutina en la que se estaba antes del reset.
Obviamente también se deberán guardar valores de variables y volverlos a asignar.

También se pueden verificar otros registros para saber a qué se debió el reset, y actuar de diferente forma.
Por ejemplo: un reset por Brown-out (Bajo voltaje)
 
No tiene mucho sentido, por no decir ninguno, volver a donde estaba antes del reset por WD.
Si se dispara el WD es porque el programa no estaba donde debía y por lo tanto hay que NO volver ahí, para no volver a estar colgado.

Dependerá de la máquina o lo que sea, en algunas no se podrá hacer, pero yo lo que hacía es una secuencia de inicio para volver a cero y volver a empezar de forma segura.

Es bueno llevar un registro de cuelgues porque es probable que estés haciendo algo mal. Sobre todo vigilar el uso de la pila.
Yo añadía en la lista de averías los resets del WDT junto Al resto de incidencias con la fecha y hora de la incidencia.

Normalmente se sabe por qué causa se ha hecho el reset, si es en el pin, en el generador interno de power on, en el whatchdog etc. Así que puedes hacer distintas cosas según sea un reinicio manual, por fallo de alimentación o por otra causa.

Los sistemas que yo usaba tenían un segundo WD que activaba un oscilador interno si fallaba el externo, y podías "salvar los muebles"
Y en algunos les ponía además uno externo.

Mira, otra cosa más WDT+ retardos = ....

 
Última edición:
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.

Programo en modo monotarea y hasta ahora funciona bien. Creo que si necesitas que un botón no rebote, pues en ese momento no necesitas nada mas, asi que por eso uso delays todos los que necesite.

Seguramente en algunos casos esto no se debe hacer, pero si sabes darle un orden a cada cosa en el programa, los delay no deberían ser problema pues igual hacen parte de todos los lenguajes de programación.

El programa mas largo que he hecho es uno para controlar un procesador de audio ... ya saben todas esas cosas como: controlar volumen, selección de entradas, on-off, retardo de salidas, control remoto etc. Todo es monotarea y usa delays y hasta ahora funciona perfecto. No uso ninguna interrupción y el sistema debe apagarse si un pin cambia de estado porque algo fallo en el amplificador; lo hace sin problemas.

Quizás la protección deba esperar máximo 200ms, por si algo falla mientras espera que un botón no rebote. Pero con lo leído aquí, llenare esos 200ms diciéndole al programa que revise el pin de protección ... antes no sabia que hacer en ese tiempo. Dejo de ejemplo la rutina principal (en Proton), desde donde llamo todo a ver que opinan!. Gracias.:cool:

'*****TECLADO LOCAL Y CONTROL REMOTO*******************
POWER:
While 1 = 1
Repeat
SONYIN_WORD = SonyIn
If ONOFF = 0 And FLAG = 0 Then GoSub ENCENDER
If ONOFF = 0 And FLAG = 1 Then GoSub APAGAR
If INPUTS = 0 And FLAG = 1 Then GoSub ENTRADA1
If UP = 0 And FLAG = 1 Then GoTo VOLUP
If DOWN = 0 And FLAG = 1 Then GoTo VOLDOWN
If PROT = 0 And FLAG = 1 Then GoTo PROTECT
If SONY = 21 And FLAG = 0 Then GoSub ENCENDER
If SONY = 21 And FLAG = 1 Then GoSub APAGAR
If SONY = 18 And FLAG = 1 Then GoTo VOLUP
If SONY = 19 And FLAG = 1 Then GoTo VOLDOWN
If SONY = 20 And FLAGM = 0 Then GoSub MUTEON
If SONY = 20 And FLAGM = 1 Then GoSub MUTEOFF
If SONY = 37 Then GoSub ENTRADA1
If SONY = 9 And FLAGL = 0 Then GoSub LOUDON
If SONY = 9 And FLAGL = 1 Then GoSub LOUDOFF
Until SONY <> 255
Wend
****************************************
 
consejo

no uses delays

siempre repites lo mismo y no tienes en cuenta en que lenguaje esta programando :rolleyes:

La pregunta sería ¿Quien fue el tarao que inventó los delays?¿En que estaba pensando?¿Que sentido tienen?
No me cabe en la cabeza y la tengo bien grande.

Usando timers oh sorpresa!

:eek: y si te digo que para determinados lenguajes, los timers son engorrosos y asignar un valor fijo a una variable...luego sumar o restar una variable temporal, ejecutar el bucle, etc etc puede o no tener practicamente desvemtajas y ventajas si recordamos que "nadie" ñe pregunto en que lenguaje programa? :unsure:
En ASM, arduino y C es valido... que hacemos con el basic? vamos a la respuesta del hilo concretamente y abramos un tema aparte para charlar ese asunto... el pibe es iniciado y le estan hablandpo como si fuera un programador de la NASA :angel::cool:

ups, perdon... desbarranque :LOL:
 
Si, la verdad es que me repito más que el ajo.
Me sorprende mucho cuando la gente habla de monotarea etc. No se, para gustos colores.
Nunca he hecho nada en monotarea más que monerías, no se me ocurre el uso.
Lo último que hice, bastante sencillo comparado con otras cosas, no es de la NASA ni mucho menos:
Una centralita de un motor monocilindrico.
Dos sensores, uno en el cigüeñal y otro en el árbol de levas, el encendido y el inyector, una consola local y un puerto serie bluetooth.
Se podía poner a punto con el motor en marcha. ¿Que sentido tendría que para hacer la puesta a punto hubiera que parar el motor?. Se podía elegir si visualizaban o modificabas el avance del encendido, el punto y la duración de la inyección. Por el display y por el puerto serie a la vez y con el motor en marcha.
El motor alcanza las 15000rpm con facilidad y generaba 36 interrupciones por vuelta de cigueñal.
Estaba hecho con la sopa de sobre del arduino.
Obviamente sin delays, si se ponen delays se jode todo.
Obviamente no es de la NASA, una consola, un puerto serie, dos sensores y dos actuadores es bastante poca cosa. Sobran las tres cuartas partes de los pines de un arduino uno.
Con delays por medio se necesita una CPU para cada cosa.

Batallita 2.
Yo aprendí a programar de forma autodidacta con un libro de Ángulo el 6502 usando los timmers del 6522. Cuando en clase me enseñaron a hacer delays con el 8085 "se me cayeron los palos del sombrajo", ya entonces no lo entendí y hasta el día de hoy sigo sin entenderlo. Cada día que pasa lo entiendo menos.

Supongo que el que aprendió con los delays vive feliz en Delayworld. Los que tuvimos la suerte (no sé si buena) de empezar "bien" somos los apóstoles de los timmers o algo así. O será otra cosa.

No veo ninguna dificultad en emplear cuatro o seis o diez instrucciones en lanzar un timmer y si que veo muchas pegas en quemar algunos millones de instrucciones para hacer lo mismo.
Si, es más fácil escribir delay 1000 que aprender cómo va un timmer pero el beneficio compensa sobradamente.

.
 
Última edición:
Tengo que admitir que yo también soy de programación secuencial y delays...

La verdad es que aprendí a programar en básic y más tarde en Pascal y supongo que eso me marco. Desde entonces todo lo que he programado en alto nivel siempre ha sido condicionado a esa forma de programar..

Me imagino que es buena idea cambiar algún delay por un bucle en el que durante ese tiempo estés por ejemplo supervisando entradas (si es que no trabajas con interrupciones)...

Le daré unas cuantas vueltas a mi forma de programar, siempre he sentido que independientemente del lenguaje nunca he sacado ni una mínima parte de la capacidad de proceso del hardware (hasta en programación orientada a objetos mi mente seguía pensando en secuencial).

 
Hola el post 5# es muy claro sobre cómo evitar delays.
Una manera consiste en incrementar una variable cada vez que el programa llega al final y vuelve a comenzar. Cuando se alcance un valor X pues se toma la acción que se desea. Otra opción es activar algún timer. Cuando desborde se puede volver a reiniciar o tomar acción según el tiempo deseado.
 
Es sencillo, piensa todo lo que hay que hacer y no dejes de hacerlo.
Actualizar el display
Mirar el teclado
Mirar el puerto serie
Enviar por el puerto serie
Hacer el proceso en si
Mirar el botón de paro de emergencia
Mirar el resto de entradas y salidas

Siempre hay cosas que hacer, si no las haces el sistema va mal. Si pulsas una tecla y hay que esperar a que se acabe otra cosa para que responda, no es aceptable. Si pulsas el paro de emergencia y no para, no es admisible etc etc.
Todo eso se mete en el bucle y ya está, basta con poner la alarma para ver si el tiempo ha pasado y entonces haces lo que toca por haber pasado el tiempo .
Si necesitas un delay para un rebote de una tecla, llama a una función que mire la temperatura o que mire si hace viento o llueve. Si no se te ocurre que hacer es que o tu sistema es muy básico o algo así. Siempre hay demasiadas cosas útiles que hacer, normalmente más de las que puedes alcanzar.

Guarda un registro de las incidencias y si el sistema se cuelga tendrás registros para ver que está pasando.

Por ejemplo, como la lectura de las entradas analógicas suele ser lenta, guarda copia en RAM de los valores y cada vez que tengas que esperar para otra cosa los actualizas. Así tienes lecturas instantáneas recientes, basta con leer la variable.
Yo no hacía ni eso, como sabía que el conversor AD tardaba 14us en responder lo que hacía era lanzar la lectura, intercalar quince instrucciones útiles del algoritmo y leer el resultado. Claro que para ser tan fino me parece que habría que cambiar alguna librería. Ciertamente algunas de estas cosas es muy fácil en ensamblador y menos en C. No sé por que diablos el conversor AD del arduino tarda 100us, me parece una bestialidad, habría que ver cómo está escrita la función analogRead.

 
Última edición:
Atrás
Arriba