Autor Tema: Problema: Secuencia de luces con CCS Compiler  (Leído 5866 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Marcelo_Jiyeon

  • PIC10
  • *
  • Mensajes: 4
Problema: Secuencia de luces con CCS Compiler
« en: 10 de Julio de 2015, 13:47:38 »
Saludos al foro, estoy creando un secuencial de leds con el pic16f84 y la idea es que mediante un pulsador (on) se prenda un led, después de 5 seg. se prenda el otro y el anterior se queda prendido y así sucesivamente hasta prender 10 leds, el problema que tengo es que este sistema debe tener una PARADA DE EMERGENCIA (stop) lo cual haga que cuando se presiona este pulsador el sistema se pare por completo. Hasta ahora avance en algo el programa y funciona, pero cuando presiono "stop" el sistema se para pero cuando vuelvo a presionar "on" el sistema empieza desde donde se interrumpió y yo quiero que cuando se presione "on" mi sistema vuelva a empezar desde el principio...¿Como podria hacer eso? Hasta ahora no logro resolverlo...Espero algo de su ayuda amigos, saludos...Este es mi programa:

#include <16f84a.h>
#fuses xt,nowdt
#use delay  (clock=4000000)
#byte trisa=0x85
#byte trisb=0x86
#byte porta=0x05
#byte portb=0x06
#bit     on=porta.2
#bit   stop=porta.3
int8 i=0;
void detener();

void main(){
   trisa=0b01100;
   trisb=0x00;
   porta=0x00;
   portb=0x00;
  

   while(1){
      
      if(on==0){
        
         portb=0b10000000;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11000000;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11100000;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11110000;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11111000;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11111100;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11111110;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         portb=0b11111111;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         porta=0b10;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
         porta=0b11;
         for(i=0;i<20;i++){
         delay_ms(250);
         if(stop==0)
         detener();
         }
        
        
      }
      
   }  

}
  
void detener(){
   while(on==1){
   porta=0x00;
   portb=0x00;
  
   }
}
« Última modificación: 10 de Julio de 2015, 17:13:33 por Marcelo_Jiyeon »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema: Secuencia de luces con CCS Compiler
« Respuesta #1 en: 10 de Julio de 2015, 18:25:06 »
Realmente deberias utilizar interrupciones, sino tendrias que esperar hasta que finalicen esos 5 segundos para que le de importancia al boton de "stop", mientras que con la interrupcion se produciria al instante, yo no voy a hacer lo de interrupcion pero si voy a corregirte ese que tenes para que haga lo que deseas

Código: C
  1. int1 funcionando;
  2. int8 i=0,j=0;
  3. int8 val_portb[8]={0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF};
  4. int8 varl_porta[2]={0x02,0x03};
  5. void detener();
  6.  
  7. void main(){
  8.  
  9.    trisa=0b01100;
  10.    trisb=0x00;
  11.    porta=0x00;
  12.    portb=0x00;
  13.    
  14.  
  15.         while(1)
  16.         {
  17.                 if(on==0 && stop ==1)                   // COndicion para que no arranque cuando no deberia
  18.                 {
  19.                         funcionando=1;                  // Esto es un flag de un solo bit nomas
  20.                 }
  21.      
  22.                 if(funcionando==0)                      // Se presiono start y se da inicio
  23.                 {
  24.                         if(j<=7) { portb=val_portb[j];}                 // Me fijo si ya complete lo del portb, estan los primeros 8 valores ? y paso al porta
  25.                         else { porta=val_porta[j-8]; }
  26.                         j++;                                            //Aca incremento para saber cuantos valores pasaron
  27.  
  28.                         for(i=0;i<20;i++)                               //Espera
  29.                         {
  30.                                 delay_ms(250);
  31.                                 if(stop==0)                             // En caso que tenga que detenerse
  32.                                 detener();
  33.                         }
  34.  
  35.                         if (j==10) { j=0; porta=0;}                             // En caso que ya pasaron TODOS los datos limpio y comienzo de nuevo
  36.                                                                                 // No limpio portb ya que en unos microsegundos se va a asignar el nuevo valor
  37.          
  38.                 }        
  39.         }  
  40.  
  41. }
  42.    
  43. void detener()
  44. {
  45.         porta=0x00;
  46.         portb=0x00;
  47.         j=0;
  48.         funcionando=0;
  49. }

Y si queres cambiar los valores o la forma en que se enciendan cambias:

int8 val_portb[8]={0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF};
int8 varl_porta[2]={0x02,0x03};

Desconectado Marcelo_Jiyeon

  • PIC10
  • *
  • Mensajes: 4
Re: Problema: Secuencia de luces con CCS Compiler
« Respuesta #2 en: 10 de Julio de 2015, 18:59:45 »
Amigo KILLERJC muchas gracias por la ayuda, gracias a tus códigos pude aprender más y resolver mi problema y queria preguntarte algo más por favor, ¿como se relaciona j con los valores del array (val_portb), osea lo que quiero decir es que tambien en lugar de poner portb=val_portb[j] como hiciste puedo poner portb=val_portb y al ciclo for colocar j? Es indistinto esto?? Saludos y gracias nuevamente... :)
« Última modificación: 10 de Julio de 2015, 19:02:02 por Marcelo_Jiyeon »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema: Secuencia de luces con CCS Compiler
« Respuesta #3 en: 10 de Julio de 2015, 19:38:44 »
j indica el indice del array.

Si esta funcionando, la primera ves que entra j es igual a 0,
entonces entra al if y se ejecuta portb=val_portb[j]; o lo que es igual a portb=0x80  (1000 0000)

Yo defini mi array con esos valores
int8 val_portb[8]={0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF};
  indices=                0      1      2      3     4      5      6      7

Entonces si J es 3, y uso val_portb[j] que es lo mismo que hacer val_portb[3] va a ser igual a 0xF0 ( 1111 0000 )

Ahora con respecto a tu pregunta.
Podes usar un for, pero con ciertas consideraciones.

y con respecto a esto: portb=val_portb

le falta el [j] , sino lo que estarias cargando al portb es la direccion de memoria donde se ubica  val_portb[0], y no su contenido.
y si quieras hacer algo asi entonces seria un portb= *(val_portb + j ) , que seria lo que apunta la direccion de base val_portb + el offset j , en resumen, igual que val_portb[j], tambien hay ortas formas que se pueden aprovechar de esto pero no le veo sentido a la complicacion. Y si queres complicarte un poco mas la vida, vas a tener que leer sobre punteros, algo MUY poderoso, pero hay que entenderlos. Asi que si no me entendiste a lo que escribi en este ultimo parrafo no les des importancia

Con for seria algo asi:

Código: C
  1. while(1)
  2.         {
  3.                 if(!on && stop)                 // COndicion para que no arranque cuando no deberia
  4.                 {
  5.                         funcionando=1;                  // Esto es un flag de un solo bit nomas
  6.                 }
  7.      
  8.                 if(funcionando)                 // Se presiono start y se da inicio
  9.                 {
  10.                         for(j=0;j<10;j++)
  11.                         {
  12.                                 if(j<=7) { portb=val_portb[j];}                 // Me fijo si ya complete lo del portb, estan los primeros 8 valores ? y paso al porta
  13.                                 else { porta=val_porta[j-8]; }
  14.                                 for(i=0;i<20;i++)                               //Espera
  15.                                 {
  16.                                         delay_ms(250);
  17.                                         if(!stop) { detener(); break; }         // En caso que se presiono el boton salgo del for, no tiene caso que siga estando dentro de este for ( por ejemplo si se presiono el boton y estaba en i = 5
  18.                                 }
  19.                                 if(!funcionando) break;                             // Si se presiono el boton entonces quiere decir que se para y deberia cortar el for que se esta ejecutando, por eso uso el break;
  20.                         }
  21.                         porta=0x00                                                       // Si se para con el boton no hay problema ya que se pone a 0 el porta, pero si no se para deberia ponerlo a 0 para que continue con la animacion
  22.                 }        
  23.         }

Fijate que agregue unos break; esto para que cuando ocurra que ya no funciona, se salga del bucle for, si entra en detener pone a 0 a funcionando y se que paro, entonces no espero esos segundos y directamente salgo esperando por que se presione de nuevo. Si yo no pusiera ese "break;" el for seguiria su marcha hasta completarse.

Yo decidi separar en 2 arrays los valores, es decir un array para el porb ( val_portb[] ) y uno para el porta ( val_porta[] ) solo para "simplicidad" en la lectura, pero podria haber realizado uno solo con todos los datos

Y cambiaria estas 3 lineas:

Código: C
  1. int8 val_port[10]={0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0x02,0x03};
  2.  
  3. //y
  4.  
  5.                                 if(j<=7) { portb=val_port[j];}          //Entraria para los indices de 0 a 7
  6.                                 else { porta=val_port[j]; }      // Entraria para los indices 8 y 9 al igual que en los demas codigos

Todo depende realmente de como te guste hacerlo.
« Última modificación: 10 de Julio de 2015, 19:51:01 por KILLERJC »

Desconectado Marcelo_Jiyeon

  • PIC10
  • *
  • Mensajes: 4
Re: Problema: Secuencia de luces con CCS Compiler
« Respuesta #4 en: 12 de Julio de 2015, 01:13:18 »
Gracias por la respuesta, la verdad me sirvio para resolver mi problema. Pero ahora tengo otra duda, nose si me puedes guiar un poco por favor.
Tengo un programa que realiza TRES secuencias de leds de 8 bits, cuando presiono el pulsador de "up" funciona la SECUENCIA_1 y esta sigue funcionando secuencialmente . Cuando presiono nuevamente "up" pasa a la SECUENCIA_2 y esta sigue funcionando solo hasta que presione nuevamente "up" así hasta la SECUENCIA_3 y cuando presiono "up" pasa a la SECUENCIA_1. El pulsador de "down" hace lo mismo pero a la inversa osea si por ejemplo se encuentra funcionando la SECUENCIA_2 cuando presiono "down" el sistema pasa a la SECUENCIA_1 y así sucesivamente.

Ya resolví un poco el problema, y lo estoy haciendo con funciones, pero lo que veo es que al anidar mis funciones para las secuencias por ejemplo, cuando me encuentro en la tercera funcion void sec_3() y quiero volver a sec_1(); al compilar en el CCS Compiler me aparece el error "Recursion not permited" lo que entiendo es que no permite volver a una función cuando la llamas dentro de otra funcion, ¿como podría hacer este procedimiento sin que me marque ese error? este es un parte del programa DONDE SE ENCUENTRAN MIS FUNCIONES y se puede ver que en la TERCERA FUNCION void sec_3() llamo a la primera funcion void sec_1() y no compila:

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();
         }
      }
   }
}
void sec_2(){
   while(1){
      portb=0x00;
      delay_ms(150);
      for(j=0;j<=255;j++){
         portb++;
         delay_ms(150);
         if(up==0&&down==1){
            sec_3();
         }
      }
   }
}
void sec_3(){
   while(1){
      portb=0x01;
      delay_ms(150);
      for(k=0;k<8;k++){
        portb=portb<<1;
        delay_ms(150);
        if(up==0&&down==1){
            sec_1();//CREO QUE AQUI ES EL PROBLEMA
         }
        
      }
   }
}


Este es mi programa completo:
Código: [Seleccionar]
#include <16f84a.h>
#fuses xt,nowdt
#use delay (clock=4M)
#byte trisa=0x85
#byte trisb=0x86
#byte porta=0x05
#byte portb=0x06
#bit up=porta.0
#bit down=porta.1
int i,j,k;

//FUNCIONES
void incrementar();

void sec_1();
void sec_2();
void sec_3();
//FUNCION PRINCIPAL
void main(){
   trisa=0b00011;
   trisb=0x00;
   porta=0x00;
   portb=0x00;
   while(1){
      if(up==0&&down==1){
         incrementar();
      }
      
   }
}
void incrementar(){
   sec_1();
  
  
}
void sec_1(){
   while(1){
      portb=0x00;
      delay_ms(150);
      for(i=0;i<8;i++){
         portb=portb<<1;//portb<<=1;
         portb+=1;
         delay_ms(150);
         if(up==0&&down==1){
            sec_2();
         }
      }
   }
}
void sec_2(){
   while(1){
      portb=0x00;
      delay_ms(150);
      for(j=0;j<=255;j++){
         portb++;
         delay_ms(150);
         if(up==0&&down==1){
            sec_3();
         }
      }
   }
}
void sec_3(){
   while(1){
      portb=0x01;
      delay_ms(150);
      for(k=0;k<8;k++){
        portb=portb<<1;
        
         delay_ms(150);
         if(up==0&&down==1){
            sec_1();
         }
      }
   }
}
« Última modificación: 12 de Julio de 2015, 01:41:09 por Marcelo_Jiyeon »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema: Secuencia de luces con CCS Compiler
« Respuesta #5 en: 12 de Julio de 2015, 03:22:19 »
Primero el codigo

Código: C
  1. int i,k[3]={0x00,0x00,0x01};
  2.  
  3.  
  4. //FUNCION PRINCIPAL
  5.  
  6.  
  7. void main(){
  8.         trisa=0b00011;
  9.         trisb=0x00;
  10.         porta=0x00;
  11.         portb=0x00;
  12.         i=1;
  13.         while(1)
  14.         {
  15.                 if(!up){
  16.                         i++;
  17.                         if(i>3){i=0;}
  18.                         portb=k[i];
  19.                 }
  20.                 else if(!down)
  21.                 {
  22.                         i--;
  23.                         if(!i){i=3;}
  24.                         portb=k[i];
  25.                 }
  26.                 switch(i)
  27.                 {
  28.                 case 1:
  29.                         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
  30.                         portb++;
  31.                         delay_ms(150);
  32.                         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
  33.                         break;
  34.                 case 2:
  35.                         portb++;
  36.                         delay_ms(150);
  37.                         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
  38.                         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
  39.                 case 3:
  40.                         portb <<= 1;                            //No se si es correcto esto, por que no se si usa el carry o no
  41.                         delay_ms(150);
  42.                         if(bit_test(portb,7)){portb=k[i];}
  43.                         break;
  44.                 default:
  45.                         break;
  46.         }
  47. }

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:

Código: C
  1. main() {
  2.  
  3. while(1)
  4. {
  5.    instruccion1;       //Supone ocupa direccion 0x10
  6.    instruccion2;       // direccion 0x12
  7.    funcion();           // direccion  0x15
  8.    instruccion3;       // direccion 0x20
  9.    instruccion4;       // direccion 0x25
  10. }
  11. }
  12.  
  13. funcion(){
  14.    instruccion5;    // direccion 0x30
  15.    instruccion6;    // direccion 0x32
  16. }

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:

Código: C
  1. void sec_1(){
  2.    while(1){
  3.       portb=0x00;
  4.       delay_ms(150);
  5.       for(i=0;i<8;i++){
  6.          portb=portb<<1;
  7.          portb+=1;
  8.          delay_ms(150);
  9.          if(up==0&&down==1){
  10.             sec_2();
  11.          }
  12.       }
  13.    }
  14. }

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:

Citar
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

« Última modificación: 12 de Julio de 2015, 03:29:32 por KILLERJC »

Desconectado Marcelo_Jiyeon

  • PIC10
  • *
  • Mensajes: 4
Re: Problema: Secuencia de luces con CCS Compiler
« Respuesta #6 en: 13 de Julio de 2015, 21:10:30 »
Gracias de verdad KILLERJC por compartir tus conocimientos...si comprendí lo que explicaste. Aunque te cuento que esto de la programación a mi no me resulta tan fácil, supongo que es cosa de mucha práctica, además estoy estudiando detalladamente cada uno de los códigos que me proporcionaste, gracias nuevamente, todo lo que hiciste me ayudó mucho ....saludos


 

anything