bigal_scorpio
Active Member
Hi to all,
I have just built an RGB lighting project from an instructable using a PIC16F627A and it works fine, but I would like to modify the code slightly.
As programming goes I am learning MeBasic, so ASM even with the excellent commenting the code has, means very little to me. If it was basic I think I could just about manage to modify the code so the PIC would power up with the last used setting and the LEDs turned on, but this is beyond me in ASM.
If anyone could suggest or help in any way I would be very grateful as this would make my project perfect for my every need.
Here is the code provided by 5Volt (who has some great projects on his site!)
Thanks for looking........Al
I have just built an RGB lighting project from an instructable using a PIC16F627A and it works fine, but I would like to modify the code slightly.
As programming goes I am learning MeBasic, so ASM even with the excellent commenting the code has, means very little to me. If it was basic I think I could just about manage to modify the code so the PIC would power up with the last used setting and the LEDs turned on, but this is beyond me in ASM.
If anyone could suggest or help in any way I would be very grateful as this would make my project perfect for my every need.
Here is the code provided by 5Volt (who has some great projects on his site!)
Thanks for looking........Al
Code:
;**********************************************************************
; *
; Filename: Rainbow.asm *
; Date: 23 Novembre 2006 *
; File Version: 1.0 *
; *
; Released under Creative Commons *
; Attribution-Noncommercial-Share Alike 2.5 License *
; 01 / 01 / 2007 - A. Lambardi *
; *
;**********************************************************************
; *
; Files required: *
; *
;**********************************************************************
; *
; Notes: *
; 20 MHz external crystal oscillator *
; PWM is generated in software via TMR0 interrupt *
; Remote control codes are the ones generated by a RC5 TV remote *
; manufactured by Philips and some others based on SAA3010. *
; Universal remote controls should be fine as long as Philips TVs *
; are supported *
; *
;**********************************************************************
list p=16f628a ; list directive to define processor
#include <p16f628a.inc> ; processor specific variable definitions
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_OFF & _HS_OSC & _MCLRE_ON & _LVP_OFF
;MACROs
BANK0 MACRO
bcf STATUS, RP1
bcf STATUS, RP0 ; Select Bank 0
ENDM
BANK1 MACRO
bcf STATUS, RP1
bsf STATUS, RP0 ; Select Bank 1
ENDM
;***** VARIABLE DEFINITIONS
w_temp equ 0x70 ; variable used for context saving
status_temp equ 0x71 ; variable used for context saving
PWM_R equ 0x73 ; PWM width for red
PWM_G equ 0x74 ; PWM width for green
PWM_B equ 0x75 ; PWM width for blue
current_PWM equ 0x76 ; PWM counter position (0 - (pwm_steps)-1)
EE_ad equ 0x77 ; EEprom address to write to
EE_dt equ 0x78 ; EEprom data read or to be written
Curr_mem equ 0x79 ; colour preset (0->9)
on_off equ 0x7A ; current on / off status
system_bits equ 0x7C ; remote RC5 system bits
command_bits equ 0x7D ; remote RC5 command bits
tmp equ 0x7E ; temp register
; Constants
Out_R_port equ PORTB ; output port to red LED
Out_R_bit equ 3
Out_G_port equ PORTB ; output port to green LED
Out_G_bit equ 4
Out_B_port equ PORTB ; output port to blue LED
Out_B_bit equ 5
Echo_LED_port equ PORTB ; monitor LED
Echo_LED_bit equ 6
IR_port equ PORTB ; IR remote receiver
IR_bit equ 7
TMR0_TC equ 0x80
pwm_steps equ 0x20 ; PWM resolution
off_sts equ 0x00 ; LEDs off status
on_sts equ 0x01 ; LEDs on status
;**********************************************************************
ORG 0x000 ; processor reset vector
clrf PCLATH ; clear page bits
goto main ; go to beginning of program
goto 0 ; a safety measure in case PC gets lost...
goto 0
;Interrupt service Routine (ISR)
ORG 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register
bcf STATUS,RP0 ; Bank 0
I_TMR0
btfss INTCON, T0IF ; is it TMR0?
goto Fine_ISR ; no, jump
bcf INTCON, T0IF ; yes, clear interrupt flag
; now do PWM: for each colour, when PWM counter (current_PWM, which varies
; between 0 and 32) reaches PWM_R (or PWM_G or PWM_B) the relevant Red (or
; Green or Blue) output is turned on, otherwise it is turned off.
do_red
movf PWM_R,w ; loads w with value to check against PWM counter
btfsc STATUS,Z ; is it completely off ?
goto R_OFF ; yes, keep it so
subwf current_PWM,w ; now compare PWM counter against threshold limit for the colour
btfss STATUS,C
goto R_ON ; counter is greater, turn output on
R_OFF
bcf Out_R_port,Out_R_bit ; counter is lower, turn output off
goto R_fine
R_ON
bsf Out_R_port,Out_R_bit
goto R_fine
R_fine
; do the same for Green and Blue (same comments apply)
do_green
movf PWM_G,w
btfsc STATUS,Z
goto G_OFF
subwf current_PWM,w
btfss STATUS,C
goto G_ON
G_OFF
bcf Out_G_port,Out_G_bit
goto G_fine
G_ON
bsf Out_G_port,Out_G_bit
goto G_fine
G_fine
do_blue
movf PWM_B,w
btfsc STATUS,Z
goto B_OFF
subwf current_PWM,w
btfss STATUS,C
goto B_ON
B_OFF
bcf Out_B_port,Out_B_bit
goto B_fine
B_ON
bsf Out_B_port,Out_B_bit
goto B_fine
B_fine
do_done
incf current_PWM,f ; PWM counter++, keep it within limits
movlw (pwm_steps - 1)
andwf current_PWM,f
goto Fine_ISR
;
Fine_ISR
movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie
;############### Main #####################################################################
main
bcf STATUS, RP1
bcf STATUS, RP0 ; Select Bank 0
call IO_init ; configure IOs and peripherals
call Reg_init ; configure variables
call Tmr0_init ; configure TMR0
call Tmr1_init ; configure TMR1 ; used for delays and remote control timing
bsf INTCON, PEIE ; enable peripherals interrupts
bsf INTCON, GIE ; global interrupt enable: PWM is on !
loop
; check the remote input
btfsc IR_port,IR_bit
goto loop
; IR detected !
call _w_telecomando ; read from remote: if returns with C == 0 then false alarm..
btfss STATUS,C
goto loop ; false alarm, loop.
; now I have remote key code in command_bits register !
movlw on_sts ; check if currently on
subwf on_off,w
btfss STATUS,Z ; if on, check all keys
goto check_on_off_k ; currently off: check on off key only
movlw 0x01 ; key 1
subwf command_bits,W
btfsc STATUS,Z
goto R_up
movlw 0x04 ; key 4
subwf command_bits,W
btfsc STATUS,Z
goto R_down
movlw 0x02 ; key 2
subwf command_bits,W
btfsc STATUS,Z
goto G_up
movlw 0x05 ; key 5
subwf command_bits,W
btfsc STATUS,Z
goto G_down
movlw 0x03 ; key 3
subwf command_bits,W
btfsc STATUS,Z
goto B_up
movlw 0x06 ; key 6
subwf command_bits,W
btfsc STATUS,Z
goto B_down
movlw 0x21 ; channel- on my remote
subwf command_bits,W
btfsc STATUS,Z
goto fr_sin
movlw 0x20 ; channel+ on my remote
subwf command_bits,W
btfsc STATUS,Z
goto fr_destra
movlw 0x11 ; vol- key on my remote: store curren values into preset no...
subwf command_bits,W
btfsc STATUS,Z
goto memo ; now must receive a number to store into preset and store
movlw 0x10 ; vol+ key on my remote: recall preset no...
subwf command_bits,W
btfsc STATUS,Z
goto recall ; now must receive a number to recall preset from and set.
check_on_off_k
movlw 0x0C ; on/off key
subwf command_bits,W
btfsc STATUS,Z
goto _turn_on_off ; toggle on / off
goto loop
memo
; wait and read remote for a preset number (0 to 9)
call wait200 ; wait 200ms circa and blink monitor LED
memo_1
btfsc IR_port,IR_bit
goto memo_1
; same as 'loop', just accept only keys 0 to 9 and store into EEPROM
call _w_telecomando
btfss STATUS,C
goto memo_1
movlw 0x0A ; check if <= 9
subwf command_bits,W
btfsc STATUS,C
goto loop ; not a number, get back to main loop
movf command_bits,W ; mult. by 3
addwf command_bits,W
addwf command_bits,W ; now w holds EEPROM address of chosen preset (for Red, Green is +1, Blue is +2)
movwf EE_ad
movf PWM_R,W
movwf EE_dt
call EE_write
incf EE_ad ; point to Green
movf PWM_G,W
movwf EE_dt
call EE_write
incf EE_ad ; point to Blue
movf PWM_B,W
movwf EE_dt
call EE_write ; done
call wait200 ; just wait a little and blink monitor LED
goto loop
recall
; as in 'memo': just recall preset instead and set RGB values
call wait200
recall_1
btfsc IR_port,IR_bit
goto recall_1
; usual remote loop, wait for pulse from remote
call _w_telecomando
btfss STATUS,C
goto recall_1
movlw 0x0A
subwf command_bits,W
btfsc STATUS,C
goto loop ; not a valid number, get back to main loop
movf command_bits,W
movwf Curr_mem
movwf EE_dt
movlw (eed & 0xFF)
movwf EE_ad
call EE_write ; store current preset number into EEprom
call EE_to_RGB ; apply changes to RGB
call wait200 ; wait and blink monitor LED
goto loop
fr_sin ; left arrow: surf the presets backward
decf Curr_mem ; decrement preset number
movlw 0xFF ; check for underflow
subwf Curr_mem,W
btfss STATUS,Z
goto fr_fine
movlw 0x09 ; underflow, set to 9
movwf Curr_mem
goto fr_fine
fr_destra ; right arrow: surf the presets forward
incf Curr_mem ; increment preset number
movlw 0x0A ; check for overflow throughout 9
subwf Curr_mem,W
btfss STATUS,Z
goto fr_fine
clrf Curr_mem ; overflow, set to 0
goto fr_fine
fr_fine
movf Curr_mem,W
movwf EE_dt ; set current preset as default (into EEPROM)
movlw (eed & 0xFF) ; default preset EEPROM address
movwf EE_ad
call EE_write ; save
call EE_to_RGB ; update RGB
call wait200 ; wait and blink monitor LED
goto loop
_w_telecomando
; check for start and toggle bits from remote
call wait592 ; delay 1778/3us
; we are at 2/3 of first bit: must be 0
btfsc IR_port,IR_bit
goto _w_nok ; no, loop!
; now wait 1778us. Must be 0.
call wait1778
btfsc IR_port,IR_bit
goto _w_nok ; no, loop allarme!
call wait1778 ; ok!, wait for toggle bit and dispose of it.
; now receive 5 "system bits". Don't actually use them.
movlw 0x05
movwf tmp
_5bits
call wait1778 ; wait for one bit
rlf IR_port,W
rlf system_bits ; move to dest (MSB first)
decfsz tmp
goto _5bits
movlw b'11100000'
iorwf system_bits ; clear the three mos significant bits.
comf system_bits,F ; Complement. I want a zero to be a IR pulse,
; not really necessary, but helps my 'forma mentis'
; now receive 6 "command bits". Need them. These are the pressed key code
movlw 0x06
movwf tmp
_6bits
call wait1778 ; comments same as above
rlf IR_port,W
rlf command_bits
decfsz tmp
goto _6bits
movlw b'11000000'
iorwf command_bits
comf command_bits,F
_w_ok
bsf STATUS,C ; return SUCCESS
return
_w_nok
bcf STATUS,C ; return FAILURE
return
wait200 ; wait for 200 ms circa and blink monitor LED
bsf Echo_LED_port,Echo_LED_bit ; turn on monitor LED
movlw .15
movwf tmp
wait200_l
call wait006
decfsz tmp
goto wait200_l
bcf Echo_LED_port,Echo_LED_bit ; turn off monitor LED
return
wait006 ; wait for 13ms circa
clrf TMR1H
clrf TMR1L
goto tmr1_st
wait1778 ; wait for 1778us
movlw 0xDD
movwf TMR1H
movlw 0x46
movwf TMR1L
goto tmr1_st
wait592 ; wait for 592us
movlw 0xF4
movwf TMR1H
movlw 0x70
movwf TMR1L
tmr1_st
bcf PIR1,TMR1IF ; clear TMR1 interrupt flag del TMR1, but do not use interrupt
bsf T1CON,TMR1ON
loopTmr1
btfss PIR1,TMR1IF ; poll TMR1 IF
goto loopTmr1
bcf T1CON,TMR1ON ; time elapsed, turn off timer
return
R_down
bcf INTCON, GIE ; disable interrupts (going to mess with registers handled by interrupt.
movf PWM_R,f ; clear already?
btfsc STATUS,Z ; if == 0 already then finished
goto R_fatto
decf PWM_R ; no, decrement
goto R_fatto ; 'fatto' stands for 'done' !
R_up
bcf INTCON, GIE ; disable interrupts (going to mess with registers handled by interrupt.
incf PWM_R ; increment target (max value is pwm_steps - 1)
movlw pwm_steps + 1 ; check against max
subwf PWM_R,w
btfss STATUS,Z ; if == max, then modify as (val massimo - 1)
goto R_fatto
movlw pwm_steps
movwf PWM_R
R_fatto
bsf INTCON, GIE ; enable interrupts
call wait200
goto loop
G_down ; now do green. Same comments as above
bcf INTCON, GIE
movf PWM_G,f
btfsc STATUS,Z
goto G_fatto
decf PWM_G
goto G_fatto
G_up
bcf INTCON, GIE
incf PWM_G
movlw pwm_steps + 1
subwf PWM_G,w
btfss STATUS,Z
goto G_fatto
movlw pwm_steps
movwf PWM_G
G_fatto
bsf INTCON, GIE
call wait200
goto loop
B_down ; now do blue. Same comments as above
bcf INTCON, GIE
movf PWM_B,f
btfsc STATUS,Z
goto B_fatto
decf PWM_B
goto B_fatto
B_up
bcf INTCON, GIE
incf PWM_B
movlw pwm_steps + 1
subwf PWM_B,w
btfss STATUS,Z
goto B_fatto
movlw pwm_steps
movwf PWM_B
B_fatto
bsf INTCON, GIE
call wait200
goto loop
IO_init
bsf STATUS,RP0 ; Bank1
; bsf PCON,OSCF ; internal oscilator to 4 MHz
movlw b'10000111' ; PORTB <3:6> output, everything else input
movwf TRISB
movlw 0xFF ; PORTA input
movwf TRISA
movlw b'11000001' ; prescaler = 4 as. to TMR0,no pull up on PORTB
movwf OPTION_REG
clrf VRCON ; Vref off
bcf STATUS,RP0 ; Bank 0
movlw 0x07
movwf CMCON ; Comparators off
return
Tmr1_init
;
clrf T1CON ; prescaler = 1, source Fosc/4 , disabled
bsf STATUS,RP0 ; Bank1
bcf PIE1, TMR1IE ; disable interrupt
bcf STATUS,RP0 ; Bank0
return
Tmr0_init
clrf TMR0
bsf INTCON, T0IE ; enable TMR0 interrupt.
bcf INTCON, T0IF
return
Reg_init
clrf current_PWM
clrf PWM_R
clrf PWM_G
clrf PWM_B
bcf Out_R_port,Out_R_bit ; turn off outputs
bcf Out_G_port,Out_G_bit
bcf Out_B_port,Out_B_bit
bcf Echo_LED_port,Echo_LED_bit
movlw off_sts
movwf on_off ; initial status is 'off'
return
_turn_on_off
bcf INTCON, GIE ; disable interrupts (going to mess with registers handled by interrupt.
movf on_off,f ; toggle between on and off status
btfss STATUS,Z
goto sts_is_on
sts_is_off
movlw on_sts
movwf on_off ; now status is 'on'
movlw (eed & 0xFF) ; load last used preset
movwf EE_ad
call EE_read
movwf Curr_mem
call EE_to_RGB
bsf INTCON, GIE ; enable interrupt
call wait200
goto loop
sts_is_on
movlw off_sts
movwf on_off ; now status is 'off'
clrf PWM_R ; turn off lights
clrf PWM_G
clrf PWM_B
bsf INTCON, GIE ; enable interrupt
call wait200
goto loop
EE_to_RGB
; recover from EEprom RGB preset values pointed by Curr_mem
movf Curr_mem,W ; multiply by 3
addwf Curr_mem,W
addwf Curr_mem,W ; x3
movwf EE_ad
call EE_read ; read R
movwf PWM_R ; and write
incf EE_ad
call EE_read ; read G
movwf PWM_G ; and write
incf EE_ad
call EE_read ; read B
movwf PWM_B ; and write
return
EE_write ; store in EEprom dati at EE_dt at address EE_ad
movf EE_dt,W
bcf PIR1,EEIF ; clear write completed flag
bsf STATUS,RP0 ; sel Bank 1
movwf EEDATA
movf EE_ad,W
movwf EEADR
bcf INTCON,GIE ; Dis. interrupts
bsf EECON1,WREN ; enable write
movlw 0x55 ; > mandatory security sequence as per specification
movwf EECON2 ; > write 55h
movlw 0xAA ; >
movwf EECON2 ; > write AAh
bsf EECON1,WR ; this is a 'write'
bcf STATUS,RP0 ; sel Bank 0
EE_dl_loop1
btfss PIR1,EEIF ; wait for write complete
goto EE_dl_loop1
bsf STATUS,RP0 ; sel Bank 1
bcf EECON1,EEIF ; clear EE write complete flag
bcf EECON1,WREN ; disable write la scrittura
bsf INTCON,GIE ; enable interrupts.
bcf STATUS,RP0 ; sel Bank 0
return
EE_read
movf EE_ad,W ; EEprom address to read from
bsf STATUS,RP0 ; sel Bank 1
movwf EEADR
bsf EECON1, RD ; this is a read
movf EEDATA, W ; W = EEDATA
movwf EE_dt
bcf STATUS,RP0 ; sel Bank 0
return
fill (goto 0), (0x400-$)
org 0x2100 ; colours preset (10, 3 per colour)
DE 0x00,0x00,0x10 ; my default, can be modified here or via remote control
DE 0x00,0x10,0x00
DE 0x10,0x00,0x00
DE 0x10,0x10,0x00
DE 0x10,0x00,0x10
DE 0x00,0x10,0x10
DE 0x10,0x10,0x10
DE 0x10,0x15,0x1F
DE 0x1F,0x15,0x10
DE 0x15,0x1F,0x10
eed DE 0x00 ; last used preset
end