Fade LED RGB

Basándonos en el post de múltiples PWM sin CCP http://electgpl.blogspot.com.ar/2014/10/multiple-pwm-sin-ccp.html realizaremos un paneo o fade del espectro de colores de forma automática, si bien existen leds RGB automáticos que solo hay que alimentarlos para que produzcan este efecto, la idea es dar el pie para luego realizar trabajos mas elaborados.
Primero que nada debemos saber que un LED RGB es en realidad tres leds en un solo package, un led Rojo, un led Verde y un led Azul, el método para formar colores o tonos depende de cuanto se encienda cada color, cuando digo cuanto se encienda estamos hablando del ciclo de trabajo PWM, es decir un led al que lo excitamos con PWM a un ciclo de trabajo del 20% brillara menos que si lo excitamos al 80%, de esta forma con el PWM logramos controlar el brillo. 
Al tratarse de 3 LEDs podremos controlar el brillo de cada uno por individual, lo que nos permitirá no solo encender el led de color Rojo, Verde o Azul, sino también todas sus variantes intermedias hasta lograr una graduación del color.
Esto lo vamos a entender mejor en el Gif que se encuentra abajo, donde podemos ver como varia el valor de 0 a 255 o de 0 a 100% de cada uno de los colores al pasar por todo el espectro.



Ahora que tenemos en claro que debemos variar el valor del ciclo de trabajo de cada color, procedemos a explicar mejor el programa.
Como el post mencionado anteriormente donde se enseña a manipular múltiples canales PWM sin el modulo CCP, se le agregaran lazos for que realizaran la tarea que muestra el gif animado que se encuentra arriba.
Como podremos ver en el firmware estamos manejando los valores de 0 a 15, esto nos dará 16 niveles de cada color, claramente podrían ser mas niveles para una mayor resolución pero en la practica podrán ver que no se nota la diferencia y con 16 niveles tendremos un programa mas rápido.
Ahora la parte del fade de colores.
como vemos en el gif, los pasos serán los siguientes

 R  , G  , B
100%, 0% ,Inc
Dec , 0% ,100%
 0% ,Inc ,100%
 0% ,100%,Dec
Inc ,100%, 0%
100%,Dec , 0%

Ahora que tenemos en claro la secuencia realizaremos un lazo for por cada una de ellas quedando los seis lazos independientes.
Se incluye una demora de 50ms por cada lazo para dar tiempo a ver el incremento o decremento de la variable. El tiempo sera 50ms por 16 ya que se repetirá 16 veces, nos dará un valor de 800ms en cada lazo for, una secuencia de aproximadamente 5s.


#include <16F628A.h>
#FUSES NOWDT, HS, NOMCLR 
#use delay(clock=4000000)
#int_timer0 
void pwm_duty(int pwm0, int pwm1, int pwm2){
   int cont;
   if(cont>15)
      cont=0;
   else
      cont++; 
   if(cont>0&&cont<pwm0)
      output_high(PIN_B0);
   else
      output_low(PIN_B0);
   if(cont>0&&cont<pwm1)
      output_high(PIN_B1);
   else
      output_low(PIN_B1);
   if(cont>0&&cont<pwm2)
      output_high(PIN_B2);
   else
      output_low(PIN_B2);
   set_timer0(0);      
}
void main(){
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); 
   set_timer0(0); 
   enable_interrupts(INT_TIMER0); 
   enable_interrupts(GLOBAL); 
   while(true){
      int r, g, b;
      for(b=0;b<16;b++){
         pwm_duty(16,0,b);
         delay_ms(50);
      }
      for(r=16;r>1;r--){
         pwm_duty(r,0,16);
         delay_ms(50);
      }
      for(g=0;g<16;g++){
         pwm_duty(0,g,16);
         delay_ms(50);
      }
      for(b=16;b>1;b--){
         pwm_duty(0,16,b);
         delay_ms(50);
      }      
      for(r=0;r<16;r++){
         pwm_duty(r,16,0);
         delay_ms(50);
      }
      for(g=16;g>1;g--){
         pwm_duty(16,g,0);
         delay_ms(50);
      }
   }
}



HC08 - Medidor de pulsaciones


Este desarrollo basa su principio de funcionamiento en la fotopletismografia (PPG), este método no es invasivo y realiza la medición de variación de la densidad de la sangre en el tejido utilizando una fuente de luz y un detector. Como la luz no tiene que penetrar en el cuerpo, el PPG se puede aplicar a cualquier parte del cuerpo humano. La luz detectada por el sensor a través del tejido del cuerpo fluctuará de acuerdo con el flujo sanguíneo pulsátil causado por el latido del corazón, esta fluctuación será captada y amplificada para ser procesada.
En la práctica utilizamos un optoacoplador infrarrojo comercial pero luego de un testeo del mismo se decidió cambiar este optoacoplador por uno de construcción propia en base a un LDR y un LED rojo de alta luminosidad, logrando así una mejora considerable sobre todo a la inmunidad a la luz ambiente.
El método empleado será ingresando el dedo dentro del dispositivo interponiéndose entre el emisor y el receptor, de esta forma el diodo emisor emitirá luz roja para el led que hemos utilizado y el LDR la recibirá. 

Esta variación de luz será amplificada y luego será comparada con una tensión de referencia (Trigger), de esta forma logramos ajustar el comparador para que en la salida se produzca un nivel alto cuando se produzca un latido.
Es necesario realizar la calibración del trigger ya que solo debe tomarse el valor máximo R del ritmo cardiaco (Trigger A).
Si en lugar de mover el trigger hacia arriba para que tome solo el valor R y se dejara a nivel de P y T (Trigger B), en lugar de tomar un solo pulso tomaría 3 pulsos y nos daría una lectura errada.



El circuito que acondiciona la señal para ser ingresada en el microconrolador se realizara en base a un amplificador operacional LM358. Se realizara un desacoplamiento de continua para que no ingresen las componentes de continua en el amplificador. Se amplificara la componente de alterna en 101 veces y al mismo tiempo se realiza un filtro pasa bajos para que no amplifique ruido eléctrico producido por luminarias a 50Hz.

Luego de esta primera etapa, le sigue una etapa comparadora donde se procede a comparar la señal de salida del amplificador anterior con una tensión de referencia que se ajusta mediante el potenciómetro de 10k, de esta forma la salida del comparador nos entregara en su salida un nivel alto o bajo dependiendo de la comparación de ambos niveles de tensión, esto lo denominamos nivel de trigger y variando el nivel de este tomaremos solo los picos de señal R que se muestran en la figura anterior, luego de esta comparación se monitorea el pulso del corazón en un LED y al mismo tiempo se ingresa la señal a un multibibrador monoestable en base al timer 555 el cual cumple la función de temporizar aproximadamente 160ms tras detectar un nivel alto en su disparo, este se utiliza para eliminar el posible burst que existe como ruido eléctrico.
Como podemos ver en el grafico del osciloscopio podemos apreciar la señal que sale del bloque amplificador y comparador, en este caso ha sido una prueba de laboratorio donde la señal se encuentra limpia y sin burst pero en otros ambientes el test ha sido distinto y el timer monoestable de
160ms de delay ha desechado ese ruido eléctrico quedando así una salida que permanecerá a nivel alto durante 160ms que luego será ingresada al microcontrolador.
Timer monoestable:




El programa utilizara el modulo TIM para realizar dos tareas principales:
1) TSC para realizar un ciclo de iteración cada 12 segundos configurando el mismo como timer con interrupción por desbordamiento cuando la variable interna del contador sea igual a un valor constante grabado en el registro TMOD.
2) TSC0 para realizar la captura por flanco ascendente, esta misma creara un salto cuando detecte un flanco ascendente en su entrada de captura que luego incrementara en una unidad una variable que suma la cantidad de pulsos.
Usando el modulo TSC0 dentro del ciclo de TSC, se contara cuantos flancos ha contado durante los 4 segundos del timer antes de que desborde el mismo. Una vez calculado los pulsos se procederá a multiplicarlo por 5, ya que 12s*5=60s (ppm) y luego se mostrara en los displays.



  1. ;-------------------------------------------------------------------------
  2. ;- MONITOR CARDIACO PARA VISUALIZAR EL RITMO EN PPM                      -
  3. ;-------------------------------------------------------------------------
  4. $Include 'jl3regs.inc'       ;Libreria para el MC68HC908JL3
  5. ;-------------------------------------------------------------------------
  6. ;- DEFINICION DE CONSTANTES Y VARIABLES                                  -
  7. ;-------------------------------------------------------------------------
  8. RamSt   equ    $0080         ;Direccion de origen de memoria RAM
  9. RomSt   equ    $EC00         ;Direccion de origen de memoria ROM
  10. ResetV  equ    $FFFE         ;Vector de Reset
  11. ;
  12.         org    RamSt         ;Se apunta al origen de memoria RAM
  13. ;
  14. varUni  rmb    1             ;Variable para separacion de Unidades
  15. varDec  rmb    1             ;Variable para separacion de Decenas
  16. varCen  rmb    1             ;Variable para separacion de Centenas
  17. varDel  rmb    1             ;Variable para Loop del Delay
  18. varCont rmb    1             ;Variable para el contador de pulsos
  19. varMue  rmb    1             ;Variable para el muestreo
  20. ;
  21.         org    RomSt         ;Se apunta al origen de memoria ROM
  22. ;-------------------------------------------------------------------------
  23. ;- CONFIGURACION                                                         -
  24. ;-------------------------------------------------------------------------
  25. MAIN    mov    #$11,CONFIG1  ;Deshabilita el COP y LVI
  26.         mov    #$FF,DDRA     ;Configura puerto A como salidas
  27.         clr    PORTA         ;Inicializa el puerto A
  28.         mov    #$FF,DDRB     ;Configura puerto B como salidas
  29.         clr    PORTB         ;Inicializa el puerto B
  30. ;-------------------------------------------------------------------------
  31. ;- CONFIGURACION DEL TIMER Y CAPTURA 1MHz/64=15625Hz -> 65535/15625=4.19s-
  32. ;-------------------------------------------------------------------------
  33. CONFIG  bset   5,TSC         ;Timer (STOP)
  34.         mov    #$04,TSC0     ;Captura por flanco de subida ELS0A
  35.         clra                 ;inicializo A
  36.         mov    #$00,varCont  ;Inicializa varCont
  37.         mov    #$03,varMue   ;Inicializa varMue
  38.         jsr    DEC2BCD       ;Rutina de conversion de Decimal a BCD
  39. ;-------------------------------------------------------------------------
  40. ;- INICIO                                                                -
  41. ;-------------------------------------------------------------------------
  42. INICIO  bset   4,TSC         ;reset de contador TCNT y prescaler
  43.         mov    #$26,TSC      ;Inicializa timer (STOP), prescaler:64
  44.         bclr   5,TSC         ;Timer (START)
  45.         clra                 ;Inicializa A
  46. PULSO   brclr  7,TSC0,SIGUE  ;Espera flanco de subida TOF
  47.         bclr   7,TSC0        ;Baja flag
  48.         inc    varCont       ;Sumo varCont=varCont+1
  49. SIGUE   jsr    MUXDISP       ;Rutina de Multiplexado de displays
  50.         brclr  7,TSC,PULSO   ;Espera a overflow
  51.         bclr   7,TSC         ;Baja flag
  52.         dec    varMue        ;Decrementa varMue
  53.         beq    UPDATE        ;Si varMue=0 salta a UPDATE
  54.         bra    INICIO        ;Si no es igual a 0 salta a INICIO
  55. UPDATE  mov    #$03,varMue   ;Asigna valor 3 a varMue
  56.         ldx    #$05          ;Cargo 5 en X
  57.         lda    varCont       ;Cargo varCont en A
  58.         mul                  ;A*X=A
  59.         jsr    DEC2BCD       ;Rutina de conversion de Decimal a BCD
  60.         mov    #$00,varCont  ;Inicializa varCont
  61.         jmp    INICIO        ;Salta a INICIO
  62. ;-------------------------------------------------------------------------
  63. ;- CONVERSION DE DECIMAL A BCD SEPARADO POR DIGITOS                      -
  64. ;-------------------------------------------------------------------------
  65. DECTBCD ldhx   #$0A          ;Carga X con 10
  66.         div                  ;Divide A/X=A, Resto en H
  67.         sthx   varUni        ;Mueve H a varUni
  68.         clrh                 ;Borra H
  69.         ldhx   #$0A          ;Carga X con 10
  70.         div                  ;Divide A/X=A
  71.         sthx   varDec        ;Mueve H a varDec
  72.         sta    varCen        ;Mueve A a varCen
  73.         rts                  ;Retorno de subrutina
  74. ;-------------------------------------------------------------------------
  75. ;- MULTIPLEXADO DE DISPLAYS                                              -
  76. ;-------------------------------------------------------------------------
  77. MUXDISP clrh                 ;Inicializa H  
  78.         ldx    varCen        ;Carga el valor de Centenas en X
  79.         lda    TABLA,X       ;Busca en la tabla el equivalente
  80.         mov    #$01,PORTA    ;xxxxx001, Disp1=1,Disp2=0,Disp3=0
  81.         sta    PORTB         ;Carga el PORTB con el valor de la tabla
  82.         jsr    DELA100       ;Llama a rutina de Delay 100us
  83.         ldx    varDec        ;Carga el valor de Decenas en X
  84.         lda    TABLA,X       ;Busca en la tabla el equivalente
  85.         mov    #$02,PORTA    ;xxxxx010, Disp1=0,Disp2=1,Disp3=0
  86.         sta    PORTB         ;Carga el PORTB con el valor de la tabla
  87.         jsr    DELA100       ;Llama a rutina de Delay 100us
  88.         ldx    varUni        ;Carga el valor de Unidades en X
  89.         lda    TABLA,X       ;Busca en la tabla el equivalente
  90.         mov    #$04,PORTA    ;xxxxx100, Disp1=0,Disp2=0,Disp3=1
  91.         sta    PORTB         ;Carga el PORTB con el valor de la tabla
  92.         jsr    DELA100       ;Llama a rutina de Delay 100us
  93.         rts                  ;Retorno de subrutina
  94. ;-------------------------------------------------------------------------
  95. ;- RUTINA DE DELAY DE 100us                                              -
  96. ;- (9+(10*9))+5=104us                                                    -
  97. ;-------------------------------------------------------------------------
  98. DELA100 mov    #$09,varDel  ;[5]Se carga el valor 9 a varDel
  99. LOOP    dec    varDel       ;[4]Se decrementa varDel
  100.         beq    FIN05        ;[3]Si varDel=0 salta a FIN05
  101.         bra    LOOP         ;[3]Salta a LOOP
  102. FIN05   rts                 ;[4]Retorno de subrutina
  103. ;-------------------------------------------------------------------------
  104. ;- TABLA DE VALORES PARA EL DISPLAY DE 7 SEGMENTOS                       -
  105. ;- Bits del display XGFEDCBA                                             -
  106. ;-------------------------------------------------------------------------
  107. TABLA   db     00111111     ;Numero 0
  108.         db     00000110     ;Numero 1
  109.         db    %01011011     ;Numero 2
  110.         db    %01001111     ;Numero 3
  111.         db    %01100110     ;Numero 4
  112.         db    %01101101     ;Numero 5
  113.         db    %01111100     ;Numero 6
  114.         db     00000111     ;Numero 7
  115.         db    %01111111     ;Numero 8
  116.         db    %01100111     ;Numero 9
  117. ;-------------------------------------------------------------------------
  118. ;- FINAL                                                                 -
  119. ;-------------------------------------------------------------------------
  120.         org   ResetV        ;Se apunta al Vector de Reset
  121.         dw    MAIN          ;Salta a MAIN
  122.         end                 ;Fin del programa