Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Can anyone help me out with a small ASM problem?

Status
Not open for further replies.

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

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
 
As far as I can tell, the -vol key is used to store a preset.

If you add:-

Code:
        movlw        0x01
	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

just before "loop"

I think that it will turn on with the settings at preset1
 
Update

Hi Diver300,

Thanks for the code mate, now it works as I needed it to.

Thanks again..........Al
 
Status
Not open for further replies.

Latest threads

Back
Top