Autor Tema: Problema con control de LEDs RGB  (Leído 1528 veces)

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

Desconectado Ragnarok

  • PIC10
  • *
  • Mensajes: 4
Problema con control de LEDs RGB
« en: 10 de Junio de 2015, 01:16:05 »
Hola gente  de todopic perdón  si los vuelvo a molestar de nuevo pero ando haciendo un proyecto durante un tiempo con el control de iluminación LED y tengo el problema que mi programa funciona correctamente en simulación pero cuando hago la prueba en protoboard este no funciona como es deseado, agradecería si pueden ayudarme un poco con este problema, uso el simulador proteus y programo con MPLAB XC8 , ademas utilizo el pic 16f819 a 8Mhtz reloj interno y uso el timer1 como temporizador.

Este es el codigo
Código: [Seleccionar]


#include <xc.h>

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB2      // CCP1 Pin Selection bit (CCP1 function on RB2)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)


#define _XTAL_FREQ 8000000

int time=0;int pw0=0; int pw1=0; int pw2=0;
int pw0n=0; int pw1n=0; int pw2n=0;
int c=0;  int rgb=0;

// El tiempo base en este proyecto es de 10msegundos
// Interrupcion del Timer1 como temporizador
void interrupt Timer1(){
 if(PIR1bits.TMR1IF==1){
   // Precarga 66353 = 1 milisegundo ( cada 1 milisegundo cambia de estado la bandera)
    TMR1H=0xF8;
    TMR1L=0x30;

    PORTBbits.RB7=!PORTBbits.RB7;
    time=time+1;

    if(pw0==time){PORTBbits.RB0=0;}
    if(pw1==time){PORTBbits.RB1=0;}
    if(pw2==time){PORTBbits.RB2=0;}

    if(time>=10){
    time=0;

    if(pw0==0){PORTBbits.RB0=0;}
    else{ PORTBbits.RB0=1;}

    if(pw1==0){PORTBbits.RB1=0;}
    else{ PORTBbits.RB1=1;}

    if(pw2==0){PORTBbits.RB2=0;}
    else{ PORTBbits.RB2=1;}


   


  }
    PIR1bits.TMR1IF=0;// Bit de Bandera del Timer1
    }
}





void main(void){
    OSCCONbits.IRCF2=1;// 8 MHZ CRISTAL INTERNO
    OSCCONbits.IRCF1=1;
    OSCCONbits.IRCF0=1;
    OPTION_REGbits.nRBPU=0;// PULL UP
    TRISB=0b01111000;
    PORTBbits.RB0=0;
    PORTBbits.RB1=0;
    PORTBbits.RB2=0;

/////Bits de configuracion del Timer1 //////////////////////////////////////
    INTCONbits.GIE=1;//Habilito las interrupciones Globales
    INTCONbits.PEIE=1;//Habilito las interrupciones perifericas
    T1CONbits.TMR1ON=1;//Habilito el timer1 (ON=1 - OFF=0) (Timer1 es una interrupcion de modulo periferico)
    PIE1bits.TMR1IE=1;//Habilito el timer1 por desvordamiento de timer( configurado como tempirizador)
    T1CONbits.TMR1CS=0;// fuente de reloj del timer (reloj interno)
    T1CONbits.T1CKPS1=0;//bit de prescaler
    T1CONbits.T1CKPS0=0;//bit de prescaler
    //prescaler ajustado a 1:1
///////////////////////////////////////////////////////////////////////////
   
 while(1){

////// BOTON R //////////////////
if(PORTBbits.RB3==0 && rgb==0){
    while(PORTBbits.RB3==0){}

     pw0n=pw0n+1;

     if(pw0n<10){pw0=pw0+1; }
     if(pw0n>9){pw0=pw0-1;}
     if(pw0n==18){pw0n=0;pw0=0;}
    }

///// BOTON G /////////////////
if(PORTBbits.RB4==0){
     while(PORTBbits.RB4==0){}

     pw1n=pw1n+1;

     if(pw1n<10){pw1=pw1+1; }
     if(pw1n>9){pw1=pw1-1;}
     if(pw1n==18){pw1n=0;pw1=0;}
    }

 ////// BOTON B //////////////
 if(PORTBbits.RB5==0  && rgb==0){

     while(PORTBbits.RB5==0){}

     pw2n=pw2n+1;

     if(pw2n<10){pw2=pw2+1; }
     if(pw2n>9){pw2=pw2-1;}
     if(pw2n==18){pw2n=0;pw2=0;}

    }

 ////// BOTON W /////////////
 if(PORTBbits.RB6==0 && rgb==0){

     while(PORTBbits.RB6==0){}
     c=c+1;
     if(c==1){pw0=0,pw1=0,pw2=0;}
     if(c>1 && c<=10){pw0=pw0+1,pw1=pw1+1,pw2=pw2+1; }
     if(c>=11){pw0=pw0-1,pw1=pw1-1,pw2=pw2-1;}
   
     if(c==19){PORTBbits.RB0=0;PORTBbits.RB1=0;PORTBbits.RB2=0; c=0;}
     

   }

    if(PORTBbits.RB4==0 && PORTBbits.RB5==0){rgb=1;}
    else{rgb=0;}

    if(PORTBbits.RB4==0 && PORTBbits.RB6==0){rgb=1;}
    else{rgb=0;}

    if(PORTBbits.RB5==0 && PORTBbits.RB6==0){rgb=1;}
    else(rgb=0);

    if(PORTBbits.RB4==0 && PORTBbits.RB5==0 && PORTBbits.RB6==0){rgb=1;}
    else{rgb=0;}

  }

}



antes que nada explico como funciona el programa:es un poquito larga mi explicación así que pido disculpas si meto la pata en la explicación.

dispongo de 4 botones " R,G,B,W" los tres primeros controlan la intensidad de un led independiente y el cuarto controla la intensidad de todos al mismo tiempo, para hacer el cambio de intensidad utilizo una variable para cada botón que va desde 0 hasta 18 para los primeros tres botones y para "W" su variable va de 0 hasta 19.
para mejor aclaración explicare como funciona el R ya que el G y B funcionaran de la misma manera.
los primeros 9 pulsos me aumentan la intensidad que va desde 0 como el minimo hasta 9 como el maximo, pero los demas pulsos  que van de 10 hasta 18 es para ir devolviendo la intensidad led

if(PORTBbits.RB3==0 && rgb==0){
    while(PORTBbits.RB3==0){}

     pw0n=pw0n+1;

     if(pw0n<10){pw0=pw0+1; }
     if(pw0n>9){pw0=pw0-1;}
     if(pw0n==18){pw0n=0;pw0=0;}
    }

el funcionamiento del W es algo parecido pero con el pulso número 1 hago de todos los leds su intensidad caigan a 0 y en el segundo pulso van aumentando su intensidad hasta llegar a su máximo que es 10 y cuando pasa  11 su intensidad comienza a decender hasta llegar a 19 que es el mínimo valor de intensidad.

 if(PORTBbits.RB6==0 && rgb==0){

     while(PORTBbits.RB6==0){}
     c=c+1;
     if(c==1){pw0=0,pw1=0,pw2=0;}
     if(c>1 && c<=10){pw0=pw0+1,pw1=pw1+1,pw2=pw2+1; }
     if(c>=11){pw0=pw0-1,pw1=pw1-1,pw2=pw2-1;}
   
     if(c==19){PORTBbits.RB0=0;PORTBbits.RB1=0;PORTBbits.RB2=0; c=0;}
     

   }




para hacer el cambio de la intensidad genero una señal  cuadrada con el timer1 configurado como temporizador y este se desvorda cada 1milisegundo, cada vez que se desvorda el temporizador aumenta una variable "time" que va de 0 hasta 10 y retorna a su valor inicial. Hago esto para generar 3 señales PWM con un microncontrolador 16f819 que solo dispone un modulo de PWM.

para generar dichas señales realizo las siguiente condiciones:
 
 if(pw0==time){PORTBbits.RB0=0;} // R   variable pw0 para rojo
    if(pw1==time){PORTBbits.RB1=0;}//G  variable pw1 para verde
    if(pw2==time){PORTBbits.RB2=0;}//B   variable pw2 para azul

    if(time>=10){
    time=0;

    if(pw0==0){PORTBbits.RB0=0;}
    else{ PORTBbits.RB0=1;}

    if(pw1==0){PORTBbits.RB1=0;}
    else{ PORTBbits.RB1=1;}

    if(pw2==0){PORTBbits.RB2=0;}
    else{ PORTBbits.RB2=1;}

cada vez que la varible que le asigne aca pulsador sea igual al numero de la varibale "time" esta me apagara la salida del led pero cuando la variable time se reinicia y pasa  a ser 1 me activa otra vez la salida hasta el momento que llega al numero de la condicion y me apaga de nuevo la salida generandome la señal pwm del ancho de pulso que deseo.



como termine de explicar  ahora con el problema, como dije al principio no me funciona el programa en protoboard correctamente por ejemplo el dia  programe el microncontrolador y proble el boton R y este me funcionaba de 0 a 9 bien pero cuando pulsaba hasta 12 o 14  la salida se apagaba completamente o se olvia a encender sin tener que suceder eso porque yo coloque como condicion de 0 a 9 como el maximo y de 10 a 18 a volver al minimo y apagarse.

tambien hice la prueba con el boton W el que me controla a  todos pero este funciona igual al R y hasta peor porque hace cosas al azar. asi que vengo en busca de su ayuda de como arreglar este problema ya que no veo el error que estoy cometiendo en mi programacion. gracias
 



Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema con control de LEDs RGB
« Respuesta #1 en: 10 de Junio de 2015, 15:39:48 »
Dejame entender.

De 0 a 9 incrementa, siendo 9 el maximo, si seguis presionando empieza a disminuir hasta que llegas a 18=0.

1 pulsador incrementa R 0-18 (Max 9)
1 pulsador incrementa B 0-18 (Max 9)
1 pulsador incrementa G 0-18 (Max 9)
1 pulsador incrementa R,B y G 0-18, el contador va de 0 a 19, aunque 0 deberia entrar 1 sola ves, solo entraria a 0 si es que queres que si se presion R o G o B vuelva a resetearse y mover todos juntos

Entiendo que intentaste hacer en algunas partes, pero creo que si pudieras explicar que son la variable rbg, esto:

Código: C
  1. if(PORTBbits.RB4==0 && PORTBbits.RB5==0){rgb=1;}
  2.     else{rgb=0;}
  3.  
  4.     if(PORTBbits.RB4==0 && PORTBbits.RB6==0){rgb=1;}
  5.     else{rgb=0;}
  6.  
  7.     if(PORTBbits.RB5==0 && PORTBbits.RB6==0){rgb=1;}
  8.     else(rgb=0);
  9.  
  10.     if(PORTBbits.RB4==0 && PORTBbits.RB5==0 && PORTBbits.RB6==0){rgb=1;}
  11.     else{rgb=0;}

Y el codigo de tu interrupcion seria un poco mas pasable. Y facil de entender, ademas de explicar que variables hay y para que las estas usando, por ejemplo por lo que veo pw2n es un contador que tenes en la funcion del color B, y lo que maneja realmente el PWM es pw2, es asi ?.

Otra cosa mas, tendrias el inverso como esta planteado actualmente donde el maximo seria 1 y el 9 o 0 seria tu valor minimo, segun la interrupcion que tenes, ademas tenes 2 preguntas a cada pwx que hacen conflicto ahi.
Tenes puesto en mal lugar el tema del contador de time. a mi parecer, pero todo depende de como queres que funcione.

En fin Pienso que para arreglarlo deberias:

  • Quitar eso de la variable rgb, que realmente no aporta nada..

Lo de tu variable rgb es simple por que quitarlo, si en algun momento presionas un boton este va a quedar atrapado en la funcion del boton hasta que no se suelte el mismo, por ende jamas vas a poder presionar 2 juntos, seria MUY pero MUY mucha casualidad que lo hagas, y aun asi si los presionas los 2 juntos va a entrar a la 1ra funcion y quedar atrapada ahi y no a ambas funciones.
Por otra parte le pondria un pequeño delay entre if y el while de los botones para un "antirebote" de unos 5/10 ms.

Código: C
  1. ////// BOTON R //////////////////
  2. if(!PORTBbits.RB3){
  3.     __delay_ms(10);                         //Antirebote
  4.     while(!PORTBbits.RB3);                 // Espero que suelte

  • Otra cosa cambiar esto:
Código: C
  1. if(c==19){PORTBbits.RB0=0;PORTBbits.RB1=0;PORTBbits.RB2=0; c=0;}

por esto

Código: C
  1. if(c==19){pw0=0; pw1=0; pw2=0; c=1;}

La explicacion es simple, vos unicamente manejas ahi los valores de pw0,pw1 y pw2, no sus puertos. De eso se encarga la interrupcion. Si modificas sus puertos y no su pwx cuando entre a la interrupcion se encenderia o no segun el valor que tengan.
Si queres que una ves presionado cualquiera de los botones R,G o B vuelva a reiniciar los valores, usa c=0; dentro de esas funciones. Asi cuando presiones de nuevo W este reinicie los valores a 0
Observaras ademas que puse c=1, ya que si pongo c=0, cuando entre nuevamente va a incrementar y no va a pasar nada, es decir vas a tener que pulsar 2 veces para que comienze a incrementar.

  • Modificar tu rutina de interrupcion, eliminar esa doble pregunta sobre los pwx


Tu rutina de interrupcion tiene un problema y es que estas preguntando por 2 cosas a la ves. Me refiero a estos:

Código: C
  1. if(pw0==0){PORTBbits.RB0=0;}
  2.     else{ PORTBbits.RB0=1;}

Voy a suponer que time va de 0 a 9, apenas incrementas time deberias de preguntar si es 10 y volverlo a 0, pero esto lo estas haciendo despues lo cual ES un error por como lo tenes programado.

Código: C
  1. PORTBbits.RB7=!PORTBbits.RB7;
  2.     time++;
  3.     if(time==10){time=0; PORTBbits.RB0=1; PORTBbits.RB1=1; PORTBbits.RB2=1;}
  4.     if(pw0==time){PORTBbits.RB0=0;}
  5.     if(pw1==time){PORTBbits.RB1=0;}
  6.     if(pw2==time){PORTBbits.RB2=0;}

Asi como lo puse va a  producir un pequeño glitch de unos microsegundos, es decir un pulso de ese tiempo, sino:

Código: C
  1. PORTBbits.RB7=!PORTBbits.RB7;
  2.     time++;
  3.     if(time==10){time=0;}
  4.     if(pw0>=time){PORTBbits.RB0=0;} else {PORTBbits.RB0=1;}
  5.     if(pw1>=time){PORTBbits.RB1=0;} else {PORTBbits.RB1=1;}
  6.     if(pw2>=time){PORTBbits.RB2=0;} else {PORTBbits.RB2=1;}

y se soluciona
« Última modificación: 10 de Junio de 2015, 15:51:42 por KILLERJC »

Desconectado Ragnarok

  • PIC10
  • *
  • Mensajes: 4
Re: Problema con control de LEDs RGB
« Respuesta #2 en: 11 de Junio de 2015, 01:20:48 »
Hola KillerJC, gracias por responder a mi duda y si olvide el explicar algunas partes del codigo.
 
Pues la variable "rgb" la tenia pensada para que no se pudieran pulsar 2 botones o mas al mismo tiempo, pero ya con tu aclaracion de que solo entra a una funcion y luego va a la otra me quedo claro eso asi que esa variable ya no la estoy usando.
 

ahora en esto:
Código: [Seleccionar]
    if(pw0==time){PORTBbits.RB0=0;}
    if(pw1==time){PORTBbits.RB1=0;}
    if(pw2==time){PORTBbits.RB2=0;}

    if(time>=10){
    time=0;

    if(pw0==0){PORTBbits.RB0=0;}
    else{ PORTBbits.RB0=1;}

    if(pw1==0){PORTBbits.RB1=0;}
    else{ PORTBbits.RB1=1;}

    if(pw2==0){PORTBbits.RB2=0;}
    else{ PORTBbits.RB2=1;}

esta parte del codigo la utilizo para generar el pwm de cualquiera de las tres variables (pw0, pw1,pw2) y funciona de la siguiente manera, cuando hago la pregunta de que si time es igual a pwx si esto es correcto apago la salida x pero para volver a encender la salida x hago la pregunta de que si pwx=0 si esto ocurre me mantedra la salida apagada pero si esto no pasa la volvera a encender y  todo esto me hara la señal que yo quiera dependiendo de el valor que tenga pwx, asi que este pedazo de codigo no lo puedo ni tocar porque no me generaria la señal, pero si tienes una manera diferente de hacerlo seria de mucha ayuda para evitar el conficto que puede tener el programa.


 ahora con respecto a esto:
Código: [Seleccionar]
if(c==19){PORTBbits.RB0=0;PORTBbits.RB1=0;PORTBbits.RB2=0; c=0;} si me di cuenta de ese error esta mañana y lo corregi y utilice las variables como lo tenias pensado y me funcion y tambien agrege c=1 para evitar el pulso de mas que tenia.


pues lo del rebote de los pulsadores no lo sabia hasta esta mañana y para evitar lo hice de esta manera:
Código: [Seleccionar]
if(PORTBbits.RB3==0 && r==0){
   
    while(PORTBbits.RB3==0){__delay_ms(100);r=1;}
//   
   
     if(PORTBbits.RB3==1 && r==1){
     r=0;
     pw0n=pw0n+1;

     if(pw0n<10){pw0=pw0+1; }
     if(pw0n>9){pw0=pw0-1;}
     if(pw0n==18){pw0n=0;pw0=0;}
   
    }

creo que puede funcionar en fisico, pero me gustaria tu opinion : lo utilizo asi, mientras esta pulsado se mantendra en el ciclo infinito esperando y manteniendo la variable r=1, pero cuando sale del ciclo infinito pregunto de que si la entrada esta en alto y la r=1 si esto pasa hara la secuencia dentro del if pero primero llevando la variable r=0 para que no vuelva a entrar en esta pregunta.

y por ultimo gracias por tu ayuda. :)





Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema con control de LEDs RGB
« Respuesta #3 en: 11 de Junio de 2015, 04:49:41 »
Citar
creo que puede funcionar en fisico, pero me gustaria tu opinion : lo utilizo asi, mientras esta pulsado se mantendra en el ciclo infinito esperando y manteniendo la variable r=1, pero cuando sale del ciclo infinito pregunto de que si la entrada esta en alto y la r=1 si esto pasa hara la secuencia dentro del if pero primero llevando la variable r=0 para que no vuelva a entrar en esta pregunta.

por que crear una variable + ejecutar muchas veces la demora todo sin sentido. puediendo hacerlo y que funciona con mucho menos codigo como lo que te pase

Código: C
  1. ////// BOTON R //////////////////
  2. if(!PORTBbits.RB3){
  3.     __delay_ms(10);                         //Antirebote
  4.     while(!PORTBbits.RB3);                 // Espero que suelte
  5.  
  6.      if(pw0n<10){pw0=pw0+1; }
  7.      if(pw0n>9){pw0=pw0-1;}
  8.      if(pw0n==18){pw0n=0;pw0=0;}
  9. }

el rebote es cuando presionas un boton y por un pequeño momento oscila entre cerrado y abierto (un rebote, imaginate una pelotita que la tiras al suelo y tenes que esperar hasta que se queda quieta ) hasta que queda tocando el boton y se queda en un estado fijo, por eso mismo con un solo delay basta, como en el codigo que te pase ( ahora lo puse completo para que te des cuenta.

Con respecto a la interrupcion tenes un problema con el codigo que tenes, por eso te dije que lo cambies.
Ahora que lo miro bien, me equivoque en lo que dije antes, tu problema es 1 solo, pero que se remedia facilmente. Asi como esta tu codigo cabe la posibilidad que time sea igual a 10 al momento de compararlo con las salidas, esto hace que el maximo ocurra en 10 y no 9.
Si cambias de orden los if entonces no va a ocurrir eso
Código: C
  1. if(time>=10){
  2.     time=0;
  3.  
  4.     if(pw0==0){PORTBbits.RB0=0;}
  5.     else{ PORTBbits.RB0=1;}
  6.  
  7.     if(pw1==0){PORTBbits.RB1=0;}
  8.     else{ PORTBbits.RB1=1;}
  9.  
  10.     if(pw2==0){PORTBbits.RB2=0;}
  11.     else{ PORTBbits.RB2=1;}
  12.     }
  13.  
  14.     if(pw0==time){PORTBbits.RB0=0;}
  15.     if(pw1==time){PORTBbits.RB1=0;}
  16.     if(pw2==time){PORTBbits.RB2=0;}

Citar
pero si tienes una manera diferente de hacerlo seria de mucha ayuda para evitar el conficto que puede tener el programa

No diferente sino mas compacta.
Si pensas es 1 hasta que llega a time y de time en adelante es 0 la salida  es decir que

de 0 a time = 1
de time a 9 = 0
Y eso lo simplifique aca:

Código: C
  1. PORTBbits.RB7=!PORTBbits.RB7;
  2.     time++;
  3.     if(time==10){time=0;}                                                             // Esto para que time vaya de 0 a 9 y vuelva a comenzar
  4.     if(pw0>=time){PORTBbits.RB0=0;} else {PORTBbits.RB0=1;}  
  5.     if(pw1>=time){PORTBbits.RB1=0;} else {PORTBbits.RB1=1;}
  6.     if(pw2>=time){PORTBbits.RB2=0;} else {PORTBbits.RB2=1;}

Lo unico fijate donde comparo con 10, si lo hubiera puesto abajo el if(time==10)  como en tu codigo, en algun momento pw0,pw1,pw2 se compararia con 10, que no es un numero valido ya que nos manejamos de 0 a 9
« Última modificación: 11 de Junio de 2015, 04:58:18 por KILLERJC »