Finalizar rutina

Hola chicos,

tengo una duda que puede ser muy tonta pero no consigo resolver. He programado un código simple para manejar un motor paso a paso bipolar. El caso es que cuando he intentado empezar a jugar con el número de pasos me ha surgido un imprevisto. Adjunto código:

PHP:
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

#include "FUSES.h"

#define _XTAL_FREQ 4000000


void prueba()
{
        // Primer paso

        PORTBbits.RB0 = 1;
        PORTBbits.RB1 = 1;
        PORTBbits.RB2 = 0;
        PORTBbits.RB3 = 0;
        __delay_ms(50);

        // Segundo paso

        PORTBbits.RB0 = 0;
        PORTBbits.RB1 = 1;
        PORTBbits.RB2 = 1;
        PORTBbits.RB3 = 0;

        __delay_ms(50);

        // Tercer paso

        PORTBbits.RB0 = 0;
        PORTBbits.RB1 = 0;
        PORTBbits.RB2 = 1;
        PORTBbits.RB3 = 1;
        __delay_ms(50);

        // Cuarto paso

        PORTBbits.RB0 = 1;
        PORTBbits.RB1 = 0;
        PORTBbits.RB2 = 0;
        PORTBbits.RB3 = 1;
        __delay_ms(50);

        
}

int main(void) {

    TRISBbits.TRISB0 = 0;
    TRISBbits.TRISB1 = 0;
    TRISBbits.TRISB2 = 0;
    TRISBbits.TRISB3 = 0;
   
    
   //int n = 1;

    for(int i = 1 ; i<10 ; i++)
    {

        prueba();
        
    }
    
}

como veis he creado una función que contiene la secuencia de pasos del motor paso a paso (prueba()). Mi idea era controlar el número de pasos que va dar el motor mediante el bucle for. De esta manera, el bucle for llamaría a la función prueba() 10 veces (hasta que la variable i fuera 10), por tanto, daría 40 pasos.

Pues bien, resulta que una vez programo el código en el microcontrolador, el código se ejecuta infinitamente. Es decir, el motor paso a paso va dando pasos de manera ininterrumpida.

¿Alguien tiene idea de por qué sucede esto? He probado con un return 0 al final del main pero tampoco funciona. Seguramente será una tontería.

Gracias a todos de antemano. Un saludo!
 
lo unico que se me ocurre es que el for esta reiniciando la variable i haciendo que se cicle infinitamente, prueba con un pulsador para verificar el ciclo o agrega otra condicion. ese es todo tu codigo?

puedes agregar por ejemplo j y comparar con un if.

int j=0;

if j>0 {
}
else{
ciclo for
j++;
}
 
Última edición:
Hola Luis30,

no creo que el problema sea el for, ya que este no inicializa la variable i cada vez que se llama a la función prueba(). Es más, he hecho la siguiente prueba:
- Sacar el contenido de la función prueba()
- Introducirlo directamente en el main()
- Quitar cualquier bucle (for, while,..)

De esta forma, OBLIGATORIAMENTE debería ejecutarse la secuencia de pasos UNA SOLA VEZ. Pero esto no sucede. El problema debe estar en la forma de finalizar el main(). Creo que es el main el que se ejecuta eternamente.
 
Hola Dr. Zoidberg,

efectivamente funciona ahora de manera correcta. Sin embargo tengo la duda de por qué pasa esto. En teoría lo que hace el bucle while(1) es quedarse eternamente en ese bucle que no tiene ninguna acción, ¿correcto?

¿Es la única manera de conseguir esto?

Muchas gracias. Un saludo
 
También puede ser con un bucle DO, o la instrucción SLEEP.
Pero para pruebas de funcionamiento, yo usaría una comprobación de pulsador con un IF para ejecutar la rutina.
Así puedes realizar las pruebas que quieras y no una sola vez.
 
Hola Dr. Zoidberg,

efectivamente funciona ahora de manera correcta. Sin embargo tengo la duda de por qué pasa esto. En teoría lo que hace el bucle while(1) es quedarse eternamente en ese bucle que no tiene ninguna acción, ¿correcto?
Eso pasa por que el µC no tiene un sistema operativo a quien devolver el control cuando el programa finaliza, y como hay que mantenerlo haciendo algo, pues que se que quede "dando vueltas".. ;). No sé que le dice el compilador que haga cuando acaba el main, pero al parecer no es algo muy bueno que digamos...

¿Es la única manera de conseguir esto?
Naaaa.
Podés usar:
Código:
do{ }while(1);
o
Código:
for(;;);
Muchas gracias. Un saludo
:apreton:
 
Al momento de usar el ciclo for estás dándole un valor inicial a tu variable i, por lo que cada vez que se ejecuta el ciclo i toma el valor de 1; lo que te recomiendo es declarar la variable int i = 1 al inicio del programa, es decir fuera del main(), y al momento de utilizar el ciclo for, ponerlo de la siguiente manera:

for(i ; i<10 ; i++)
{
prueba();
}

Espero sea de ayuda, espero tus comentarios.
 
Pues sí, aunque en realidad se está generando un bucle mientras 1 sea 1. (O sea, siempre)
Pero como no contiene instrucciones internas, el bucle no hace nada más que generar el mismo ciclo.
 
En realidad es "mientras la condicion sea verdadera" y 1 siempre es verdadero, lo mismo que cualquier cosa distinta de cero.
Como el cuerpo es una oracion vacia, lo unico que hace es evaluar la condicion, que siempre es verdadera.... y queda haciendo eso para siempre...
 
De ese bucle no se sale. Esta hecho para tener.al micro ocupado haciendo algo. Si necesitas salir hay que hacer otra cosa, pero eso es lo que necesitaba quien hizo la consulta
 
Pues bien, resulta que una vez programo el código en el microcontrolador, el código se ejecuta infinitamente. Es decir, el motor paso a paso va dando pasos de manera ininterrumpida.

¿Alguien tiene idea de por qué sucede esto? He probado con un return 0 al final del main pero tampoco funciona. Seguramente será una tontería.
Dr. Zoidberg dijo:
No sé que le dice el compilador que haga cuando acaba el main, pero al parecer no es algo muy bueno que digamos...
No es ninguna tontería. Es algo que hay que tener en cuenta, y que a veces puede ser útil.

Lo que ocurre es que el programa, al terminar, como dice Dr. Zoidberg, no regresa a ningún sitio, por lo que el microcontrolador... sigue ejecutando el código que hay en la memoria de programa. Y al llegar al final, el micro vuelve a la posición 0, y continúa (ver pág. 796 del "Programming and Customizing the PIC Microcontroller", de Myke Predko, 3 ed., McGraw-Hill, 2008).

En un PIC18, la memoria contendrá valores 0xFFFF o 0x0000. Los diseñadores de los PIC tuvieron el detalle de hacer que esas dos combinaciones equivalen a la instrucción nop, por lo que el micro no hace nada -excepto tardar un momento-, hasta que llega al final, y recomienza en la posición 0.

En los PIC del rango medio, la memoria se suele rellenar con 0x03FFF, que equivale a la instrucción addlw 0xFF, es decir, decrementa W en 1. Y lo mismo que antes: al llegar al final, se reposiciona a la dirección 0.

Un ejemplo de para qué puede servir esto tan raro. Supongamos que estamos en un PIC16F84, con 1 Kpalabras de memoria de programa. Podemos escribir el programa más corto -que haga algo- en un PIC:
PHP:
    title “SHORT - Is this the Shortest Possible Application?”
;
; Look at a Two Instruction Application. Continually Update
; w (with the “unprogrammed” ADD 0x0FF) and then use the
; value for “PORTB” and “TRISB”.
;
; Hardware Notes:
; 16F84 Running at 4 MHz
; Reset is tied directly to Vcc and PWRT is Enabled.
; PortB is used for Output
;
;
; Myke Predko
;
; 99.10.26 - “Short” Created
;

    list R=DEC
    include “p16f84.inc”
    __CONFIG _CP_OFF & _XT_OSC & _PWRTE_ON & _WDT_OFF

        org 0x03FE

        tris    PORTB           ; Save WREG in TRISB
        xorwf   PORTB, f        ; XOR PORTB with the contents of WREG

        end
La instrucción tris, lo que hace es mandar el valor de W al registro TRISB. Lo que en realidad hace es:
PHP:
        bsf     STATUS, RP0     ; Bank 1
        movwf   TRISB^0x080     ; Almacena WREG en TRISB
        bcf     STATUS, RP0     ; Bank 0
Y luego hace un xor entre el valor de WREG y el del PORTB. Así que estamos cambiando el valor del puerto B.

A continuación, el micro se lanza a ejecutar 1022 instrucciones "addlw 0x0FF" con lo que tenemos que W se ha incrementado realmente en 2, y se ha esperado 1022 ciclos de instrucciones (una pequeña espera). Al llegar al final, el contador de programa se pone a 0, y se repite todo de nuevo.

Si ponemos un LED en RB7 (el más significativo de PORTB), veremos cómo va cambiando. Como detalle final, el programa se ha colocado (con el org) al final de la memoria de programa, para verificar con el simulador que, efectivamente, W se incrementa en 2 en cada vuelta.
 
El problema es que no conozco el mapa de memoria en el que el compilador distribuye el codigo del programa.
Si en el PC=0 hay un salto al inicio del main y las funciones estan entre este salto y el main, entonces todo funciona OK, pero si estuviera el inicio del main y las funciones a continuacion de este, la finalizacion del main produciria que el proximo codigo que se ejecute sea el de las funciones con cualquier valor en los parametros.
En tu ejemplo en assembler no hay problema, pero usar eso como referencia del compilador.... hummmmm

Mejor es programar defensivamente...
 
Muchas gracias a todos por vuestra colaboración en las respuestas. En especial a Joaquin Ferrero por su detallada explicación y Dr. Zoidberg por su implicación.

Creo que he entendido bastante bien la razón del problema y tengo ahora varias herramientas para solucionarlo gracias a vosotros. Seguiré pendiente de este tema por si alguien más aporta datos interesantes.

Un saludo a todos y gracias!
 
Atrás
Arriba