;*** Selector de color por PWM *************************************************
;
; El actual proyecto tiene el propósito de seleccionar un color
; específico usando PWM para un diodo LED-RGB. Por medio del uso de
; retardos por software.
;
;*******************************************************************************
    ERRORLEVEL  -302        ;Directiva para evitar que el ensamblador mande el mensaje (banco incorrecto).
    INCLUDE <P12F629.INC>   ;Carga el archivo de cabecera INC, del PIC12F629. Y sus operandos usados.
    LIST    P=12F629        ;Lista del procesador del micro utilizado

    __CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _BOREN_ON & _CP_OFF & _CPD_OFF
    ;Configuraciónes: Oscilador interno habilitado, Watchdog Timer deshabilitado, Power-Up Timer deshabilitado
    ;                 Master Clear habilitado, Brown-out Detect deshabilitado, Code Protection deshabilitado
    ;                 Data Code Protection deshabilitado.

    CBLOCK 0x20             ;Posición de la memoria de propósito general RAM.
    R_ContA                 ;Variable para contar el "primer ciclo".
    R_ContB                 ;Variable principal para controlar el "primer ciclo".
    Duty                    ;Variable que incrementa el ciclo de trabajo.
    Valley                  ;Variable que decrementa el ciclo de descanzo.
    Temp                    ;Variable que decrementa hasta llegar a cero en el ciclo del TMR0.
    ENDC                    ;Fin de la directiva

    ORG     0               ;Vector de arranque del programa Aqui inicia todo
    GOTO    Configs         ;Salta a la etiqueta Configs

    ORG     4               ;Vector de interrupción, cuando se detecta la interrupción. Es cargado el PC con 0004h
    GOTO    IncDuty         ;Salta a la etiqueta IncDuty

Configs:                    ;Etiqueta Configs:
    BSF     STATUS,RP0      ;Acceso a BANK1: OSCCAL, TRISIO y OPTION_REG.
    CALL    H'3FF'          ;Es llamada la instruccion H'3FF', para calibrar.
    MOVWF   OSCCAL          ;el oscilador interno, luego es cargado en OSCCAL.
    MOVLW   B'10000000'     ;Deshabilita las Resistencias internas, Habilita la
    MOVWF   OPTION_REG      ;Interrupcion por Flanco descendente, Fuente del TMR0 es INTCLOCK
    MOVLW   B'00001100'     ;Es cargado el valor 0Ch a W, luego es cargado a
    MOVWF   TRISIO          ;TRISIO. Entonces GPIO2 y GPIO3 son las unicas entradas.

    BCF     STATUS,RP0      ;Acceso a BANK0
    MOVLW   B'00000111'     ;Es cargado con un 07h el registro CMCON
    MOVWF   CMCON           ;para deshabilitar los comparadore del PIC.
    MOVLW   B'10010000'     ;Habilita Interrupciones globales, Deshabilita Interrupcion
    MOVWF   INTCON          ;de perifericos, Deshabilita interrupcion por TMR0, Habilita GPIO2/INT.
    CLRF    Temp            ;Limpia la variable Temp.
    CLRF    Duty            ;Limpia la variable Duty.
    MOVLW   D'100'          ;Carga 100 en el registro de trabajo W.
    MOVWF   Valley          ;Carga el contenido del registro W a la variable Valley.
    CLRF    GPIO            ;Limpia todos los pines del puerto GPIO<5:0>
    
Main:                       ;Etiqueta Main:
    MOVF    Duty,F          ;Carga el contenido de Duty a Duty, y comprueba si el registro esta vacio
    BTFSC   STATUS,Z        ;mediante la comprobacion del bit Z, del registro de estado STATUS.
    GOTO    ZeroD           ;Salta a la etiqueta ZeroD: cuando el registro esta vacio, Z=1 entonces esta vacio.
    MOVF    Valley,F        ;Si no esta vacio el registro Duty, entonces Z=0, y salta la instruccion GOTO
    BTFSC   STATUS,Z        ;en la variable Valley, cargando su contenido en ella misma, si Z=1 esta vacio
    GOTO    ZeroV           ;pero si Z=0, esta llena la variable Valley y salta la instruccion GOTO.




;---- Subrutinas para crear el efecto estrobo en un LED ------------------------

EdgeDuty:                   ;Etiqueta EdgeDuty:
    BSF     GPIO,0          ;Pone en uno el bit 0, del registro GPIO (desactiva el pin 0).
    MOVFW   Duty            ;Carga el contenido de Duty al registro W.
    MOVWF   Temp            ;Carga el contenido del registro W, a la variable Temp.
    CALL    TmrX            ;Salta a la etiqueta TmrX, y ejecuta todo lo que tenga; regresa a la
                            ;a la linea que le sigue a esta.
EdgeValley:                 ;Etiqueta EdgeValley:
    BCF     GPIO,0          ;Pone a cero el bit 0, del registro GPIO (activa el pin0 ).
    MOVFW   Valley          ;Carga el contenido de la variable Valley al registro W.
    MOVWF   Temp            ;El contenido del registro W es cargado a la variable Temp.
    CALL    TmrX            ;Salta a la etiqueta TmrX, y cuando termina, regresa una linea debajo de esta linea.
    GOTO    Main            ;Salta a la etiqueta Main, creando un ciclo que nunca acaba.

TmrX:                       ;Etiqueta TmrX:
    MOVLW   D'56'           ;Carga en el registro W, la constante 56, para luego cargarse en el registro
    MOVWF   TMR0            ;TMR0, donde comenzará a incrementar en 1, así mismo, hasta alcanzar 256, donde
                            ;se desbordará (256= 100000000), activando el bit T0IF, del registro INTCON
LoopTmrX:                   ;Etiqueta LoopTmrX
    BTFSS   INTCON,T0IF     ;Comprueba siempre si es activado el bit T0IF: si T0IF=1 salta la instruccion
    GOTO    LoopTmrX        ;GOTO, pero si T0IF=0 ejecuta la instruccion GOTO.
    BCF     INTCON,T0IF     ;Pone a cero el bit T0IF del registro INTCON, para reutilizar el TMR0.
    DECFSZ  Temp,F          ;Decrementa en 1, el contenido de la variable Temp, si Temp = 0, salta la
    GOTO    TmrX            ;instrucción GOTO, y ejecuta la instrucción RETURN: lo que permite regresar
    RETURN                  ;a la instrucción donde fue invocada con la intrucción CALL TmrX

ZeroD:                      ;Etiqueta ZeroD:
    BCF     GPIO,0          ;Pone a cero el bit 0, del registro GPIO (desactiva el pin 0).
    GOTO    Main            ;Salta a la etiqueta Main, creando un ciclo que nunca acaba.

ZeroV:                      ;Etiqueta ZeroV:
    BSF     GPIO,0          ;Pone en uno el bit 0, del registro GPIO (activa el pin 0).
    GOTO    Main            ;Salta a la etiqueta Main, creando un ciclo que nunca acaba

;-------------------------------------------------------------------------------


;--- Subrutina de Interrupcion (cuando es activado el pin 2 --------------------
;
;   Cuando es activado el PIN 2, (la interrupción), es dirigido hacia el
;   el Vector 4 en el microcontrolador. Es decir inicia en la posición 4
;   del microcontrolador. Por lo tanto, se puede crear un salto condicional
;   despues de ORG 4, con la intención de ejecutar esta etiqueta.
;   Mas detalles en el PDF de la hoja de datos del PIC12F629, especificamente
;   en la página 61 (acerca de las interrupciones).
;
;-------------------------------------------------------------------------------

IncDuty:                ;Etiqueta IncDuty:
    MOVF    Valley,F    ;Al incrementar Duty, Valley decrementa, es posible que
    BTFSC   STATUS,Z    ;Valley llegue a D'0'; cuando ocurra, se comprueba STATUS,Z
    GOTO    Equ100      ;y entonces si se activa Z, salta a la etiqueta Equ100.
    MOVLW   D'10'       ;Carga la constante 100, en el registro W, luego la variable
    SUBWF   Valley,F    ;Valley le resta el contenido de W, el resultado es almacenado en Valley.
    MOVLW   D'10'       ;Carga la constante 10 al registro de W, luego a Duty, se le suma el con-
    ADDWF   Duty,F      ;tenido de W, y el resultado es almacenado en la Duty.
    GOTO    EndIncDuty  ;Salta a la etiqueta EndIncDuty.

Equ100:                 ;Etiqueta Equ100:
    MOVLW   D'100'      ;Carga la constante 100 en el registro W. Luego carga el contenido del
    MOVWF   Duty        ;registro W, en la variable Duty.
    CLRF    Valley      ;Limpia la variable Valley. Ahora la variable Valley contiene 0.
                        ;Continua la ejecución de instrucciones a la siguiente linea (hacia abajo).

EndIncDuty:             ;Etiqueta EndIncDuty:
    BCF     INTCON,INTF ;Limpia el bit INTF del registro INTCON para reutilizar la interrupción.
    RETFIE              ;Regresa a la instrucción que se ejecutaba antes de activar la interrupción.

;-------------------------------------------------------------------------------

    END                 ;Marca el fin del programa