Primero el codigo
int i,k[3]={0x00,0x00,0x01};
//FUNCION PRINCIPAL
void main(){
trisa=0b00011;
trisb=0x00;
porta=0x00;
portb=0x00;
i=1;
while(1)
{
if(!up){
i++;
if(i>3){i=0;}
portb=k[i];
}
else if(!down)
{
i--;
if(!i){i=3;}
portb=k[i];
}
switch(i)
{
case 1:
portb <<= 1; //No se si es correcto esto, por que no se si usa el carry o no, supongo que no y que va a ser correcto
portb++;
delay_ms(150);
if(bit_test(portb,7)){portb=k[i];} // En ves de hacer 8, como ya se el final es que quede 0xFF ( 1111 1111 ) , pregunto por el bit 7, si se pone a 1 se termino y tengo que resetear
break;
case 2:
portb++;
delay_ms(150);
if(!(~portb)){portb=k[i];} //el negado de portb si es 0 entra por el NOT ( ! ), o sea 0xFF negado es 0x00, que seria un 0 logico y con el ! pasa a 1
break; // Lo mas seguro es que no haga falta el if anterior, y se pueda omitir, si se define como unsigned de 8 bits, cuando este en 255 y se le sume 1, va a ocurrir que va a pasar a 0 solo
case 3:
portb <<= 1; //No se si es correcto esto, por que no se si usa el carry o no
delay_ms(150);
if(bit_test(portb,7)){portb=k[i];}
break;
default:
break;
}
}
Aunque no me gusta la forma de hacerlo, queda lo mas parecido a lo que tenes.
Ahora te digo TUS errores.
Si bajamos de nivel a lo que es el funcionamiento del microcontrolador, cada ves que llamas una funcion se ejecuta un CALL, esa instruccion hace que se guarde la direccion donde se encontraba en un stack(pila) que posee el micro, para que luego cuando se termine de ejecutar esa funcion se utilize un RETURN para sacar esa direccion guardada y volverla a poner en el contador de programa ( PC, es el que va indicando que instruccion debe ejecutarse ), si lo pensas en C a eso seria algo asi:
main() {
while(1)
{
instruccion1; //Supone ocupa direccion 0x10
instruccion2; // direccion 0x12
funcion(); // direccion 0x15
instruccion3; // direccion 0x20
instruccion4; // direccion 0x25
}
}
funcion(){
instruccion5; // direccion 0x30
instruccion6; // direccion 0x32
}
Entonces usando el ejemplo ese de arriba ocurria que se ejecutaria las instrucciones 1 y 2, y luego cuando llega a la funcion se procede a hacer un CALL a funcion(), eso guarda la direccion de la proxima instruccion, que es la de instruccion3 en ese stack. asi que tenemos guardado 0x20 en el stack, y el CALL pone la direccion 0x30 en el contador de programa para que siga ejecutando desde ahi. pasa por las instrucciones 5 y 6, se termina la funcion y se procede a usar un RETURN, esto saca la direccion guardada del stack y la pone en el contador de programa asi el microcontrolador sigue ejecutando desde 0x20 o lo que es lo mismo instruccion 3 y 4.
Ese es el funcionamiento normal, en el que todo lo que va al stack, debe retirarse en algun momento. Tu programa hace lo contrario, no retira nada nunca. Tomemos de ejemplo esto:
void sec_1(){
while(1){
portb=0x00;
delay_ms(150);
for(i=0;i<8;i++){
portb=portb<<1;
portb+=1;
delay_ms(150);
if(up==0&&down==1){
sec_2();
}
}
}
}
Supongamos que no tenes nada en el stack, entonces vos estas ejecutando eso y presionas un boton, esto hace que se guarde la direccion donde quedo, para que cuando sec_2() termine vuelva donde dejo. (1 direccion de retorno guardada en el stack)
Pero si vamos a sec_2() tenemos un while que NUNCA va a salir, ahora en sec_2() ocurre lo mismo, pero ahora vas a sec_3(). Nuevamente se guarda la direccion para cuando termine sec_3, o sorpresa que no se termina nunca, ya tenes 2 direcciones guardadas. Y asi continuamente si vas presionando va a seguir guardando por que nunca se terminan las funciones. Finalmente cuando estas en sec_3() que ocurre? Te vas a sec_1() y de vuelta guardar la direccion.
Ahora tu stack tiene algo asi:
Retorno a sec_3
Retorno a sec_2
Retorno a sec_1
Lo que esta arriba es lo mas reciente que se puso y si se saca es lo primero que sale (clasico ejemplo de la pila de platos). Genial pero ya estamos en sec_1... y si seguimos presionado que ocurre ? y si.. metemos mas y mas y mas y mas direcciones al stack.
Pero el stack tiene un tamaño limitado, por ejemplo algunos tienen solo 8 niveles , es decir 8 lugares, lo cual lleva a un problema, el compilador detecta que lo que estas haciendo es ciclico y encima vas a terminar rebalsando el stack por culpa de eso, entonces te dice que no esta permitida esa "recursion" ( es decir algo que vuelve a pasar ).
Un programa deberia ser algo asi:
Funcion principal
|
|_______> Primera subfuncion
|___________> Funciona que se llama de la primera subfuncion
|
_________se termino__________|
|
|<_ se termino _|
|
|
Aca de vuelta a funcion principal ( normalmente lo hace el while(1))
Mientras que tu programa ocurre que esta continuamente llamando pero jamas vuelve, espero haber sido claro con todos los ejemplos que di.
Y por si no quedo claro el como evitar que ocurra esto, es hacer que el unico while(1) sea el del programa principal, los demas while que pongas SIEMPRE, SIEMPRE deberian terminar alguna ves. y no me refiero llamando a una funcion, sino saliendo de la misma.. ejemplo
while(i<200) i++;
ese while esta bien por que en algun momento i va a llegar a valer 201 y va a salir de ese while