En la sexta entrega de nuestro tutorial, vamos a ver las instrucciones que se utilizan para crear bucles capaces de repetir una determinada cantidad de veces una parte de nuestro programa.Seguramente habrán notado que usando una etiqueta y una instrucción GOTO podemos hacer que una parte de nuestro programa se repita. El problema que tiene ese método es que utilizado así, en crudo, solo permite que el bucle en cuestión se repetirá un numero infinito de veces.
Los lectores mas atentos se habrán dado cuenta que si empleamos una variable y la instrucción IF…ENDIF, podemos ir contando la cantidad de veces que el bucle se ha ejecutado, para salirnos de el en el momento deseado.
Vamos a verlo en detalle. Supongamos que necesitamos un bucle que se repita 20 veces. Podemos definir una variable auxiliar, de tipo BYTE (que permite valores de hasta 255) asignarle el valor 0, y en cada iteración del bucle sumarle 1. Cuando el valor de la variable sea igual a 20, sabremos que las instrucciones dentro del bucle se han ejecutado ese número de veces. El programa podría quedar más o menos así:
DIM AUX AS BYTE ‘Declaro la variable “AUX” como BYTE
AUX = 0 ‘Asigno “0” a la variable “AUX”.
bucle: ‘Aquí comienza el bucle que debe repetirse 20 veces…
instruccion1
instruccion2
…
instruccionn
AUX = AUX + 1 ‘Sumo 1 al valor de “AUX”
IF AUX = 20 THEN ‘si “AUX” es igual a 20…
GOTO fuera ‘Salto a la etiqueta “fuera”.
ENDIF
GOTO bucle ‘fin del bucle.
fuera: ‘aquí comienza el resto del programa
…
…
END
Este método funciona perfectamente, y puede modificarse para cualquier número de iteraciones, recordando que la variable AUX deberá ser de tipo WORD si el número es mayor a 255. Si necesitáramos iterar más de 65535 veces, deberemos utilizar más de una variable.
Pero afortunadamente BASIC tiene instrucciones mas especificas, elegantes y potentes para resolver este tipo de situaciones.
FOR – TO – STEP – NEXT
Esta es quizás una de las instrucciones que esta disponible en todos los dialectos BASIC, desde la época de las “home computers”. El BASIC del PIC SIMULATOR IDE también la soporta, y seguramente la emplearemos en casi todos nuestros programas.
Esta estructura, al igual que el caso anterior, necesita de una variable tipo Byte o Word para funcionar. En cada iteración del bucle, la variable va cambiando su valor. Cuando el valor de la variable alcanza o supera el valor prefijado, el bucle termina. La forma del bucle es la siguiente:
FOR variable = valor_inicial TO valor_final STEP paso
instruccion1
instruccion2
…
instruccionn
NEXT variable
La cuenta comienza asignando a “variable” el “valor_inicial”, y termina cuando “variable” alcanza el valor “valor_final”. Cada iteración del bucle el valor de la “variable” se incrementa el valor fijado por “paso”.
Veamos un ejemplo concreto. Supongamos que queremos sumar los números del 1 al 100. El programa quedaría como sigue:
DIM A AS BYTE ‘Declaro la variable “A” como BYTE
DIM TOTAL AS WORD ‘Declaro la variable “TOTAL” como WORD
TOTAL = 0 ‘Asigno “0” a la variable “TOTAL”.
FOR A = 1 TO 100 STEP 1 ‘”A” va de 1 a 100 de 1 en 1
TOTAL = TOTAL + A ‘Sumo “A” al valor de “TOTAL”.
NEXT A ‘fin del bucle.
Hemos declarado la variable A como BYTE, ya que su valor va a mantenerse en el rango 0…255. Para TOTAL utilizamos una variable tipo WORD, ya que la suma va a superar el valor máximo de un BYTE. (Recordemos que WORD permite valores en el rango 0…65535)
El bucle se ejecuta 100 veces, la primera de ellas A vale 1, la segunda 2, la tercera 3, hasta la última en la que vale 100. Ese incremento (1 por vez) esta dado por el valor a continuación del STEP. En los casos como este en que STEP vale 1, puede omitirse, como veremos en ejemplos posteriores.
TOTAL comienza valiendo 0 (se le asigna ese valor fuera del bucle) y en cada iteración se le suma el valor que tenga A en ese momento. De esa manera, TOTAL va tomando los valores 1, 3, 6, 10, …. 5050.
Tanto valor_inicial como valor_final y paso también pueden ser variables, lo que permite que un determinado bucle FOR…NEXT sea utilizado dentro de una subrutina (como veremos más adelante) con diferentes valores cada vez.
El siguiente trozo de código hace lo mismo que el anterior, pero emplea variables en lugar de valores fijos:
DIM A AS BYTE ‘Declaro la variable “A” como BYTE
DIM INICIO AS BYTE ‘Declaro la variable “INICIO” como BYTE
DIM FINAL AS BYTE ‘Declaro la variable “FINAL” como BYTE
DIM PASO AS BYTE ‘Declaro la variable “PASO” como BYTE
DIM TOTAL AS WORD ‘Declaro la variable “TOTAL” como WORD
INICIO = 1 ‘Asigno “1” a la variable “INICIO”.
FINAL = 100 ‘Asigno “100” a la variable “FINAL”.
PASO = 1 ‘Asigno “1” a la variable “PASO”.
TOTAL = 0 ‘Asigno “0” a la variable “TOTAL”.
FOR A = INICIO TO FINAL STEP PASO ‘”A” va de 1 a 100 de 1 en 1
TOTAL = TOTAL + A ‘Sumo “A” al valor de “TOTAL”.
NEXT A ‘fin del bucle.
Y el mismo ejemplo, sin usar STEP:
DIM A AS BYTE ‘Declaro la variable “A” como BYTE
DIM TOTAL AS WORD ‘Declaro la variable “TOTAL” como WORD
TOTAL = 0 ‘Asigno “0” a la variable “TOTAL”.
FOR A = 1 TO 100 ‘”A” va de 1 a 100 de 1 en 1
TOTAL = TOTAL + A ‘Sumo “A” al valor de “TOTAL”.
NEXT A ‘fin del bucle.
Si quisiéramos sumar otro grupo de números, bastaría con modificar el valor de las variables INICIO y FINAL.
Hay casos en que es necesario que el valor de la variable de control del bucle se decremente en lugar de ir aumentando. Un cronometro descendente seria una aplicación practica de este caso. Para lograr esto, se puede usar un valor negativo para STEP. El siguiente ejemplo cuenta desde 50 hasta 20, de 5 en 5:
DIM A AS BYTE ‘Declaro la variable “A” como BYTE
FOR A = 50 TO 20 STEP -5 ‘”A” va de 50 a 20 de 5 en 5
instruccion1
instruccion2
…
instruccionn
NEXT A ‘fin del bucle.
De la misma manera que ocurría con IF-THEN-ELSE-ENDIF, pueden anidarse diferentes bucles FOR-TO-STEP-NEXT , uno dentro de otro:
FOR variable1 = valor_inicial1 TO valor_final1 STEP paso1
FOR variable2 = valor_inicial2 TO valor_final2 STEP paso2
instruccion1
instruccion2
…
instruccionn
NEXT variable2
NEXT variable1
La única condición, igual que ocurría con IF… es que un bucle debe estar completamente contenido dentro del otro, sino el compilador nos avisara del error y se negará a generar el archivo .HEX correspondiente.
El siguiente anidamiento daría un error en el compilador:
FOR variable1 = valor_inicial1 TO valor_final1 STEP paso1
FOR variable2 = valor_inicial2 TO valor_final2 STEP paso2
instruccion1
instruccion2
…
instruccionn
NEXT variable1
NEXT variable2
Para que el anidamiento sea correcto, el primer NEXT debe ser el correspondiente al segundo FOR (el de la “variable2”). Este FOR se repetirá tantas veces como lo indique el FOR de la “variable1”
Para terminar, veamos el siguiente código:
AllDigital
TRISC = 0
Dim a As Byte
For a = 0 To 255
WAITMS 250
PORTC = a
Next a
Si lo compilamos y cargamos en al PIC TRAINER 40 conectado a la placa de 8 I/O como lo hicimos en la entrega anterior, veremos como los LEDs “cuentan” en binario desde 0 a 255.
WHILE – WEND
La segunda estructura de control que proporciona PIC BASIC es WHILE – WEND. Su propósito también es la construcción de bucles que se ejecutan un numero de veces, y se puede decir que esta a “mitad de camino” entre la construcción de un bucle mediante etiquetas y GOTOs y la utilización de un FOR…NEXT. Su estructura es la siguiente:
WHILE condición
instruccion1
instruccion2
…
instruccionn
WEND
Mientras que la condición sea verdadera, el grupo de instrucciones dentro del cuerpo del WHILE-WEND se ejecuta. Las características de la condición son las mismas que vimos antes para la instrucción IF-THEN-ELSE-ENDIF.
Por supuesto, si no somos cuidadosos al momento de elegir la condición, puede darse el caso de que el numero de repeticiones del bucle sea infinito, y nunca salgamos de él. De hecho, esta circunstancia se aprovecha en algunos programas para repetir indefinidamente un grupo de instrucciones. También hay que tener presente que si la condición no es cierta al momento de ejecutar la primera vez el WHILE, el flujo del programa pasara directamente a la instrucción posterior al WEND y las instrucciones dentro del bucle no se ejecutaran ninguna vez.
No hay mucho mas para decir de WHILE-WEND , solo analizar algunos ejemplos:
Ejemplo 1:
El siguiente es un bucle infinito. Como dentro del cuerpo del WHILE-WEND no se cambia el valor de la variable A, esta siempre vale “0” y la condición del WHILE nunca es falsa, por lo que se repite eternamente: es un caso similar a los que vimos en la entrega anterior del tutorial.
DIM A AS BYTE
A = 0
…
WHILE A = 0
instruccion1
instruccion2
…
instruccionn
WEND
…
Ejemplo 2:
Las instrucciones dentro del siguiente WHILE-WEND no se ejecutan nunca, dado que la condición siempre es falsa:
DIM A AS BYTE
A = 0
…
WHILE A > 0
instruccion1
instruccion2
…
instruccionn
WEND
…
Ejemplo 3:
Las instrucciones dentro del siguiente WHILE-WEND se ejecutan 20 veces, y al terminar la variable B contiene la suma de los números del 0 al 20 naturales:
DIM A AS BYTE
DIM A AS BYTE
A = 0
B = 0
WHILE A < 20
A = A + 1 ‘Incremento la variable A
B = B + A ‘Sumo a B el valor de la variable A
WEND
Cuando A = 20, se suma su valor a A, y al llegar al WEND el control del programa se transfiere al WHILE, donde se evalúa la condición A < 20, se determina que es falsa, y el programa pasa el control a la línea que exista después del WEND.
Este bucle hace la misma suma que el que realizamos antes con FOR…NEXT. No se puede decir que uno sea mejor o peor que el otro: solo son dos formas distintas de hacer lo mismo, y en cada situación decidiremos cual nos conviene más.
Esto es todo por hoy, seguiremos avanzando la próxima semana. ¡Los espero!
excelente.