Autor Tema: Ayuda con secuencias LED  (Leído 2185 veces)

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

Desconectado Luis_Luigi

  • PIC10
  • *
  • Mensajes: 1
Ayuda con secuencias LED
« en: 12 de Octubre de 2017, 01:16:36 »
Hola, como están. Mi duda o problema es la siguiente...
Me dejaron de tarea entregar varios programas, de los cuales con un botón accionaban la secuencia y con otro apagaba esa secuencia oeste segundo empezaba otra.
El primer problema es que cuando acaba la secuencia tengo que pulsar en seguida el otro botón o mantenerlo presionado para apagar o cambiar la secuencia.
Todo era risas y diversión hasta que en el penúltimo ejercicio tenia que controlar 2 secuencias y un apagado con un solo botón (primer pulso encendido y mostrar la primera secuencia, segundo pulso cambiaba a otra secuencia y el tercer pulso apagaba todo), el problema aquí también es que para cambiar la secuencia tenia que apretar el botón en el momento exacto porque si lo mantenía apretado aparecía un error en proteus.
Mis preguntas son:
¿Hay alguna manera de cambiar la secuencia sin que espere a que termine la primera? (y si la hay) ¿Como lo hago?
De igual manera que el penúltimo ejercicio:
¿Como cambio la secuencia sin esperar a que termine la anterior CON UN SOLO BOTÓN?
para mostrarles les dejo el código de mi dolor de cabeza (el penúltimo ejercicio), y otro código del primer problema.

seria de mucha ayuda... MUCHÍSIMA ayuda que me ayudaran a resolver estos.
Gracias por leer y responder.

NOTA: los puertos A los configure solo para botones (en especial el 0 y el 1) mientras que B Y D para LED'S. TODO EN "PIC C COMPILER".
___________________________EJERCICIO QUE HE "RESUELTO"___________________________________________
#include <18f4550.h>
#fuses nomclr,nowdt,noprotect,hspll,pll1
#use delay(clock=4MHz)


#BYTE PORTA=0xF80
#BYTE TRISA=0xF92

#BYTE PORTB=0xF81
#BYTE TRISB=0xF93

void main(){
     
     
   bit_set(TRISB,0);
   bit_set(TRISB,1);
     
   bit_clear(TRISA,1);
   bit_clear(TRISA,2);
   
   while (1){
      if (bit_test(PORTB,0) == 1){
         do{
            bit_set(PORTA, 1);
            delay_ms(200);
            bit_clear(PORTA, 1);
            delay_ms(200);
            bit_set(PORTA, 2);
            delay_ms(200);
            bit_clear(PORTA, 2);
            delay_ms(200);
         }while ((bit_test(PORTB,1) == 0));
      }
   }
}
______________________PENÚLTIMO EJERCICIO______________________________
#include <18f4550.h>
#fuses nomclr,nowdt,noprotect,hspll,pll1
#use delay(clock=4MHz)


#BYTE PORTA=0xF80
#BYTE TRISA=0xF92

#BYTE PORTB=0xF81
#BYTE TRISB=0xF93

#BYTE PORTD=0xF83
#BYTE TRISD=0xF95
void main(){
   int contador=0;
   bit_set(TRISA,0);
     
   bit_clear(TRISB,0);
   bit_clear(TRISB,1);
   bit_clear(TRISB,2);
   bit_clear(TRISB,3);
   bit_clear(TRISB,4);
   bit_clear(TRISB,5);
   bit_clear(TRISB,6);
   bit_clear(TRISB,7);
   
   bit_clear(TRISD,0);
   bit_clear(TRISD,1);
   while(true){
      if((bit_test(PORTA,0) == 1)){
         contador++;
      }
      if (contador == 1){
      while ((bit_test(PORTA,0) == 1)){
         do{
            bit_set(PORTB,0);
            bit_set(PORTB,2);
            bit_set(PORTB,4);
            bit_set(PORTB,6);
            bit_set(PORTD,0);
            delay_ms(500);
            bit_clear(PORTB,0);
            bit_clear(PORTB,2);
            bit_clear(PORTB,4);
            bit_clear(PORTB,6);
            bit_clear(PORTD,0);
            delay_ms(500);
            bit_set(PORTB,1);
            bit_set(PORTB,3);
            bit_set(PORTB,5);
            bit_set(PORTB,7);
            bit_set(PORTD,1);
            delay_ms(500);
            bit_clear(PORTB,1);
            bit_clear(PORTB,3);
            bit_clear(PORTB,5);
            bit_clear(PORTB,7);
            bit_clear(PORTD,1);
            delay_ms(500);
         }while ((bit_test(PORTA,0) == 0));
      }
         contador++;
      }
      if (contador == 2){
         do{
            bit_set(PORTB,0);
            bit_set(PORTB,2);
            bit_set(PORTB,4);
            bit_set(PORTB,6);
            bit_set(PORTD,0);
            bit_set(PORTB,1);
            bit_set(PORTB,3);
            bit_set(PORTB,5);
            bit_set(PORTB,7);
            bit_set(PORTD,1);
         }while ((bit_test(PORTA,0) == 0));
         contador++;
      }
     }
   }
« Última modificación: 12 de Octubre de 2017, 01:19:38 por Luis_Luigi »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con secuencias LED
« Respuesta #1 en: 12 de Octubre de 2017, 12:37:47 »
Analicemos el problema... Voy a darte las causas y me gustaria que vos llegues a una solucion de codigo.

Como sabes el programa es secuencial , primero ejecuta una instruccion, luego ejecuta otra y asi... Ocurre que las instrucciones de cambiar un bit son muy rapidas, y es por esto que usamos los delays, sino cambiaria demasiado rapido como para que lo veamos.

Esos delays, hacen que el compilador se ponga a ejecutar instrucciones que no tienen ningun fin, saltos sin sentido, instrucciones que no hacen nada como NOP, etc, todo para que pase el tiempo que le dimos. El problema de esto, es que mientras esta en ese delay no podemos hacer nada, es como si dejara de responder.

Otro problema... supongamos que tenes la lectura del boton y pasa por 4 delays de 1segundo cada uno, si presionas el boton en el primer delay, hasta que llegue a la lectura del boton deberias tener que tenerlo presionado esos 3 o 4 segundos hasta que llegue a esa instruccion.

Y ese es tu problema.

¿Como soluciono esto?

Podriamos acortar la cantidad de la demora, para que el boton se lea mas rapidamente. Esto trae aparejado otro problema. Y es que va a ir mas rapido la secuencia, pero por ejemplo suplirlo para que no cambie de secuencia luego de que pase varias veces.

Podemos usar una interrupcion de un boton, para que sea atendido, ya que al ocurrir una interrupcion este dejaria esperando al delay, iria a a la interrupcion y luego volveria al delay.

Para evitar tantos delays en el "while" de la secuencia, podrias utilizar un array, y guardar los datos ahi, para que funcionen como una tabla.

Podes usar un Timer que te de esos "0.5 segundos", y asi evitar que el micro este haciendo "nada", y te olvidas de los delays, Ahora al ejecutarse tan rapido vas a tener que proteger tu boton, para que no se detecte varias veces.

Esas son algunas de posibles soluciones, para evitar problemas creo que lo mas simple seria usar arrays, y buscarle la vuelta a los delays.
Presenta tu eleccion de solucion a estos problemas, es decir intenta implementar alguna solucion y luego vemos que hay de malo.

------------------------------------------------

PD:

Veo que usas el #BYTE, CCS cambia la direccion (TRISx) si es que usas output(PIN_B0) o input() por ejemplo.
Para evitar esto, CCS posee una directiva que se llama #USE FAST_IO(B) , donde la B es por el puerto B, de esa forma luego haces set:_tris_b(0b11111111) Y pones como entrada y/o salida a los pines que vos quieras, lo bueno es que al usar ese FAST_IO no te va a cambiar la direccion de los otros pines. Ejemplo:

Suponete que tenes RB0 entrada, y RB7:RB1 como salida, ahora si queres sacar un dato por el PORTB, usas output_b(), entonces haces:

Código: C
  1. #USE FAST_IO(B)
  2.  
  3. void main(void)
  4. {
  5.     set_tris_b(0b11111110);
  6.  
  7.     while(1)
  8.     {
  9.          output_b(0b01010101);
  10.          delay_ms(500);
  11.          output_b(0b10101010);
  12.          delay_ms(500);
  13.     }
  14. }

A pesar que yo ponga un 1 o un 0 sobre RB0, este se va a mantener como entrada, y por lo tanto no va a tener efecto sobre este. Todo esto gracias al #USE FAST_IO(B). Y otra cosa, no tengo que usar los BYTE para definir los registros, que es lo que intenta evitar CCS. Y si quiero leer un pin hago input(PIN_B0) y eso me devuelve 0 o 1.

PD2:

No se si te diste cuenta, pero los "delays" mientras menos se usen o eliminarlos por completo, es lo mejor, ya que estos hacen que el micro este ocupado haciendo nada. Y no permiten que responda a las entradas.

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Ayuda con secuencias LED
« Respuesta #2 en: 22 de Octubre de 2017, 17:45:34 »
Yo lo que hago con los delay es meterlos en un bucle for . De modo que si necesito 1 segundo de demora hago:

  for(i=0;i<=1000;i++) delay_ms(1);

 De esta forma si que se atiende una interrupcion dentro del retardo. Si necesito mas velocidad en la atencion de la interrupcion pues hago lo mismo pero con microsegundos. delay_us(x);

  Eso si,  si necesitas que los retardos sean lo mas exactos posible mas vale tener un clock bastante rapido o usar los Timer.

  Lo de las secuencias yo haria un control de pulsador donde éste lo unico que hace es incrementar una variable en una unidad seguido de un If para limitar el valor de esa variable al numero de secuencias o funciones que se tengan que atender, luego tirarle un switch a esa variable y en cada “case:” hace su secuencia una y otra vez.

« Última modificación: 22 de Octubre de 2017, 17:51:46 por remi04 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con secuencias LED
« Respuesta #3 en: 22 de Octubre de 2017, 19:15:14 »
Citar
De esta forma si que se atiende una interrupcion dentro del retardo. Si necesito mas velocidad en la atencion de la interrupcion pues hago lo mismo pero con microsegundos. delay_us(x);

La interrupcion no es afectado por los delays. Si haces el delay comun o con un for, la interrupcion es atendida en el mismo tiempo. Porque la funcion "delay_ms" no es que por 1ms el micro esta ejecutando 1 sola instruccion, sino que delay_ms se hace con varias instrucciones que usualmente tarda 1 o 2 ciclos de reloj ( Fosc/4 ), asi que si lo haces con el for o con directamente el delay_ms, dentro de estas instrucciones cuando se produzca una interrupcion, salta solo al vector de interrupcion apenas termine de ejecutar lo que estaba haciendo ( instrucciones en ASM como dije solo llevan 1 o 2 ciclos de reloj )

Citar
Lo de las secuencias yo haria un control de pulsador donde éste lo unico que hace es incrementar una variable en una unidad seguido de un If para limitar el valor de esa variable al numero de secuencias o funciones que se tengan que atender, luego tirarle un switch a esa variable y en cada “case:” hace su secuencia una y otra vez.

Muy buena solucion, tambien podrias ver si podes implementar arrays y aprovechar la variable que incrementas con el boton.
Lo mas importante que el tiene problema es que cada una de las secuencias hace que no responda el micro. Por lo tanto deberias implementar de otra forma la secuencia.


 

anything