;蛍のプログラム
;#define    F873

#ifdef F873
    list    p=16f873a
    include <p16f873a.inc>
    __CONFIG    _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _CPD_OFF

#define pLed1   PORTA,0
#define pLed2   PORTA,1
#define pLed3   PORTA,2
#define pLed4   PORTA,3

#define LedPort PORTA
#define kMaskLed    0x0f

#else
    list    p=12f675
    include <p12f675.inc>
    __CONFIG    _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _MCLRE_OFF & _INTRC_OSC_NOCLKOUT & _CPD_OFF

#define pLed1   GPIO,0
#define pLed2   GPIO,1
#define pLed3   GPIO,2
#define pLed4   GPIO,4

#define LedPort GPIO
#define kMaskLed    0x17

#endif
    radix   dec
    errorlevel  -302


    cblock 0x20
    w_temp
    status_temp
    timer
    saveTimer
    pwm1        ;GP0 duty 0-127
    pwm2        ;GP1 duty
    pwm3        ;GP2 duty
    pwm4        ;GP4 duty

    count1:2        ;H,L 0x000-0x3ff for PWM1
    count2:2        ;H,L 0x000-0x3ff for PWM2
    count3:2        ;H,L 0x000-0x3ff for PWM3
    count4:2        ;H,L 0x000-0x3ff for PWM4

    temp
    endc


    org 0
    nop
    goto    Main

    org 4
    movwf   w_temp             ;Interrupcion
    movf    STATUS,W
    movwf   status_temp

    bcf INTCON,T0IF               ;clear_interrupt(TMR0);
PwmOnWait:                       ;do{
    movf    pwm1,W              ;TMR0 siempre = a 0... una estupides
    subwf   TMR0,W                 ; if(pwm1<TMR0){pLed1=1;}else{pLed1=0;}
    btfss   STATUS,C
    bsf pLed1
    btfsc   STATUS,C
    bcf pLed1

    movf    pwm2,W                ;Comparacion de PWM para
    subwf   TMR0,W
    btfss   STATUS,C              ; if(pwm2<TMR0){pLed2=1;}else{pLed2=0;}
    bsf pLed2
    btfsc   STATUS,C
    bcf pLed2

    movf    pwm3,W                 ; if(pwm3<TMR0){pLed3=1;}else{pLed3=0;}
    subwf   TMR0,W
    btfss   STATUS,C
    bsf pLed3
    btfsc   STATUS,C
    bcf pLed3

    movf    pwm4,W
    subwf   TMR0,W
    btfss   STATUS,C              ; if(pwm4<TMR0){pLed4=1;}else{pLed4=0;}
    bsf pLed4
    btfsc   STATUS,C
    bcf pLed4

    movlw   kMaskLed
    andwf   LedPort,W
    bnz PwmOnWait                 ;}while(LedPort&kMaskLed)

    incf    timer,F                ; timer++;

    movf    status_temp,W
    movwf   STATUS
    swapf   w_temp,F
    swapf   w_temp,W
    retfie

;*****************************
;count1-4を＋１する。最大は、0x3ff
CountInc    macro   dest                  ; void CountInc(int16 *dest) {
    movlw   1                             ; *dest++;
    addwf   dest+1,F                      ; *dest&=0xFDFF;
    btfsc   STATUS,C                      ; }
    incf    dest,F
    bcf dest,2
    endm
;count1-4からpwm1-4を設定する
Count2Pwm macro count,pwm                 ; void Count2Pwm(int16 *count, int *pwm){
    LOCAL   Area000, Area100, Next
    movf    count,F                       ; select(((*count&0xFF00)>>8)){
    bz  Area000                           ;  case 0:
    movlw   1                             ;         *pwm=(*count&0xFF)/2;
    subwf   count,W                       ;          break;
    bz  Area100                           ;  case 1:
;area 0x200-0x3ff                         ;          *pwm= (~(*count&0xFF))/2;
    clrw                                  ;          break;
    goto    Next                          ;  default:          //2 o mas
;area 0x100-0x1ff                         ;          *pwm=0;
Area100:                                  ;
    movf    count+1,W                     ;
    sublw   255                           ;
    movwf   temp                          ;
    bcf STATUS,C                          ;
    rrf temp,W
    goto    Next

;area 0x000-0x0ff
Area000:
    bcf STATUS,C
    rrf count+1,W
    movwf   pwm

Next:
    movwf   pwm
    endm

;*******************************
;Main
;*******************************
Main:
#ifndef F873
    call    0x3ff              ;Solo caso de tener reloj interno.
    banksel OSCCAL
    movwf   OSCCAL
#endif
    call    Init               ;Configuracion
MainLoop:
    movf    timer,W            ;while(1) {
    movwf   saveTimer           ; saveTimer=timer;
MainWait:
    clrwdt                       ; while(saveTimer==timer);
    movf    timer,W
    subwf   saveTimer,W
    bz  MainWait

    CountInc    count1             ; CountInc(&count1);
    CountInc    count2
    CountInc    count3
    CountInc    count4

    Count2Pwm count1, pwm1         ; Count2Pwm(&count1,&pwm1);
    Count2Pwm count2, pwm2
    Count2Pwm count3, pwm3
    Count2Pwm count4, pwm4

    goto    MainLoop               ;} // while(1)


Init:
    banksel OPTION_REG
    movlw   0x85               ;Configuracion interrupciones
    movwf   OPTION_REG

    banksel INTCON
    movlw   0x20
    movwf   INTCON

#ifdef F873
    banksel ADCON1
    movlw   0x06
    movwf   ADCON1

    banksel TRISA              ;Todo digital PORTA salida e igual a 0
    movlw   0x00
    movwf   TRISA

    banksel PORTA
    clrf    PORTA
#else
    banksel ANSEL              ; Todo digital 1 entrada todas salidas (xxoo iooo)
    clrf    ANSEL

    banksel CMCON
    movlw   0x07
    movwf   CMCON

    banksel TRISIO
    movlw   0x08        ;xxoo iooo
    movwf   TRISIO

    banksel GPIO
    clrf    GPIO
#endif
;count1-4,pwm1-4初期値
    clrf    count1
    movlw   3
    movwf   count2
    movlw   2
    movwf   count3
    movlw   1
    movwf   count4

    clrf    count1+1              ;Count1 = 0x000
    clrf    count2+1              ;Count2 = 0x300
    clrf    count3+1              ;Count3 = 0x200
    clrf    count4+1              ;Count4 = 0x100

    clrf    pwm1                  ;pwm1=pwm2=pwm3=pwm4=0
    clrf    pwm2
    clrf    pwm3
    clrf    pwm4

    bsf INTCON,GIE                ;Activo interrupcion
    return


    org 0x3ff
    retlw   0x80    ;dummy

    end
