• 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.

move WORD to TXREG

Status
Not open for further replies.

scomi

New Member
I wonder how can i move a 16 bits WORDS of one variable to the TXREG register so that it can transmit serially via the hardware UART of PIC 16F88. As one BYTE can have 8 bits of data... how to mov 16 bits to TXREG?


Code:
;--------------------------------------------------------------------
;                  Main Program Starts Here!
;
Start:
	clrf 	PORTA
	clrf	PORTB
	bsf	STATUS,RP0	; bank 1
	ifdef	__16F88
	movlw	B'11101111'	; PortA directions (16F88)
	movwf	TRISA
	movlw	B'11000001'	; PortB directions (16F88)
	movwf	TRISB
	movlw	B'01100000'	; 4MHz internal osc (16F88)
	movwf	OSCCON
	else
	movlw	B'11111111'	; PortA directions (16F870)
	movwf	TRISA
	movlw	B'00000000'	; PortB directions (16F870)
	movwf	TRISB
	movlw	B'11111111'	; PortC directions (16F870)
	movwf	TRISC
	endif
	movlw   B'01010111'	; Weak pullups enabled, Timer0 src = clkout/256
	movwf	OPTION_REG
	bcf	STATUS,RP0	; bank 0

; Set up Interrupts

	clrf	INTCON		; clear any pending ints
	clrf	PIR1
	bsf	INTCON,PEIE	; enable peripheral ints
	bsf	INTCON,GIE	; enable interrupts

; set up LCD Display

	movlw	25		; wait 500mS
	call	waitx20k

	call	LCDinit		; Set up the LCD display
	call	show_signon	; show signon message

	movlw	50		; wait 1 second
	call	waitx20k

; set up A/D convertor

	bsf	STATUS,RP0	; bank 1
	ifdef	__16F88
	movlw	b'10110000'	; right-justify, ext vref (16F88)
	movwf	ADCON1
	movlw	b'00001111'
	movwf	ANSEL		; Analog inputs on RA0~RA3 (16F88)
	else
	movlw	b'10001101'	; right-justify, ext vref, RA1/RA0 (16F870)
	movwf	ADCON1
	endif
	bcf	STATUS,RP0	; bank 0
	movlw	b'01000000'	; CLK/8
	movwf	ADCON0

; Start Timer0

	movlw	REFRESH_DELAY
	movwf	TMR0

; initialize variables

	clrf	Flags
	clrf	Flags2
	movlw	0
	movwf	pagenum
	clrf	Page_Timer
	clrf	Blade_Timer
	clr16	CCPR
	clr16	Period
	clr32	AmpSum
	clr32	rpm
	movlw	2
	movwf	NumBlades

; Set up CCP1 and Timer1 for rpm capture

	clrf	TMR1L
	clrf	TMR1H		; clear Timer1
	movlw	b'00100001'
	movwf	T1CON		; 4:1 prescaler, Timer1 ON
	bcf	PIR1,TMR1IF
	bcf	PIR1,CCP1IF	; clear Int flags
	banksel	PIE1
	bsf	PIE1,CCP1IE	; enable CCP1 Ints
	bsf	PIE1,TMR1IE	; enable TMR1 Ints
	banksel	0
	movlw	b'00000111'	; capture every 16th leading edge
	movwf	CCP1CON		; enable Capture

ReadInputs:
	clr16	Volts
	clr16	Amps
	clr16	Watts
	movlw	64		; 64 times oversampling
	movwf	Readings
NextRead:
	movlw	b'01000001'	; CLK/8, select RA0 (Volts), A/D on
	movwf	ADCON0
	call	wait100		; wait 100uS to stabilize analog input
	bsf	ADCON0,GO_DONE	; start A/D conversion
waitv:	btfsc	ADCON0,GO_DONE
	goto	waitv		; wait until conversion Done
	movf	ADRESH,w
	movwf	Temp1
	addwf	Volts
	bsf	STATUS,RP0
	movf	ADRESL,w	; add 10 bit A/D result to Volts
	bcf	STATUS,RP0
	movwf	Temp2
	addwf	Volts+1
	skpnc
	incf	Volts

	bcf	Flags,MAX_VOLTS
	movf	Temp1,w
	xorlw	b'00000011'
	skpnz
	bsf	Flags,MAX_VOLTS	; Volts overloaded ?
	movf	Temp2,w
	xorlw	b'11111111'
	skpz
	bcf	Flags,MAX_VOLTS

	movlw	b'01001001'	; CLK/8, select RA1 (Amps), A/D on
	movwf	ADCON0
	call	wait100		; wait 100uS to stabilize analog input
	bsf	ADCON0,GO_DONE	; start A/D conversion
waita:	btfsc	ADCON0,GO_DONE
	goto	waita		; wait until conversion Done
	movf	ADRESH,w
	movwf	Temp1
	addwf	Amps
	bsf	STATUS,RP0
	movf	ADRESL,w	; get 10 bit A/D result
	bcf	STATUS,RP0
	movwf	Temp2
	addwf	Amps+1
	skpnc
	incf	Amps

	bcf	Flags,MAX_AMPS
	movf	Temp1,w
	xorlw	b'00000011'
	skpnz
	bsf	Flags,MAX_AMPS	; Amps overloaded ?
	movf	Temp2,w
	xorlw	b'11111111'
	skpz
	bcf	Flags,MAX_AMPS

	decfsz	Readings
	goto	NextRead	; accumulate readings

	clrc
	rr16	Volts		; Volts / 2

	movlw	Volts
	call	Divx12		; Volts / 12.8

	movlw	Amps
	call	Divx12		; Amps / 12.8

	btfsc	Flags,GOT_ZERO	; have Amps been zeroed ?
	goto	sub_zero
get_zero:
	mov16	Amps,ZeroAmps	; record zero Amps value
	bsf	Flags,GOT_ZERO
sub_zero:
	bcf	Flags,NEG_AMPS
	sub16	ZeroAmps,Amps	; subtract zero value from Amps
	skpnc
	goto	got_amps
	bsf	Flags,NEG_AMPS
	com16	Amps		; Amps = -0 to -0.99
got_amps:
	mov16	Amps,aa
	mov16	Volts,bb
	call	Mult16		; Watts = Volts * Amps
	movi16	1000,aa
	call	Div32		; Watts = Watts / 1000
	subi16	500,bb
	skpc			; remainder > 0.5 ?
	goto	store_watts
	inc16	dd+2		; yes, round up
store_watts:
	mov16	dd+2,Watts
calc_Ah:
	add1632	Amps,AmpSum	; AmpSum = accumulated Amps
	mov32	AmpSum,dd
	movi16	3600*3,aa	; 3 reads per second, 3600 seconds per hour
	call	Div32		; AmpHours = AmpSum  / (reads per hour)
store_Ah:
	mov16	dd+2,AmpHours


; CCPR is a copy of the CCPR1 register. It is updated from the Interrupt
; routine. This may happen at any time, so we must prevent it from being
; updated while copying it. We cannot disable interrupts while copying
; because it could upset capture timing.
;
	bsf	Flags,LOCK_P	; lock CCPR
	mov16	CCPR,Period     ; get period (1/rpm)
	bcf	Flags,LOCK_P	; unlock CCPR

; reduce rpm jitter by averaging this and previous measurement

	tst16	Period
	skpz			; got good rpm ?
	goto	sp_good
	clr16	OldPeriod	; no, old period = 0
	goto	sp_done
sp_good:
	tst16	OldPeriod
	skpnz			; got previous good rpm ?
	goto	sp_done		; no
	mov1632	Period,dd
	add1632	OldPeriod,dd
	rr32	dd		; dd = (Period+OldPeriod)/2
	mov16	Period,OldPeriod ; old period = current period
	mov16	dd+2,Period	; Period now averaged
sp_done:


	movlw	LCDLINE2
	call	Set_Cursor
	call	Show_rpm	; "99999rpm   x 9"
	call	Show_Blades

	endif

; Wait 1/3 second (3 readings per second)
; Check buttons while waiting

ref_delay:
	btfss	INTCON,TMR0IF
	goto	ref_delay	; wait for Timer0 overflow (55.555mS)
	movlw	REFRESH_DELAY
	addwf	TMR0		; recharge Timer0
	bcf	INTCON,TMR0IF
	call	page_button	; handle page button
	call	blade_button	; handle blades button
	decfsz	ref_timer
	goto	display_page	; 6 Timer0 overflows = 333.3mS (1/3 Second)
check_hold:
	btfss	HDBTN		; hold switch on ?
	goto	do_display	; yes, hold last readings

	goto	ReadInputs	; no, get new readings

	END
From the code, it is like A and A+1 denoted as the two bytes stored.
How can i mov 2 bytes of this into my W register? Wanna seeking help from you guys... Thanks.
 

Nigel Goodwin

Super Moderator
Most Helpful Member
As already said, you send two bytes - you don't even have a 16 bit variable anyway, there are only 8 bit variables in the PIC in question.
 
Last edited:

scomi

New Member
Well.... the variable AH is declared as WORDS:

Code:
; AmpereHours
	WORD	AH ;

And the way it is obtained by having accumulated value of AmpSum where the macro add1632 is used, it adds 16 bit to 32 bit. At last, mov16 is called for 16 bits macro big endian.

Code:
calc_Ah:
	add1632	Amps,AmpSum	; 
	mov32	AmpSum,dd
	movi16	3600*3,aa	; 3 reads per second, 3600 seconds per hour
	call	Div32		; AH = AmpSum  / (reads per hour)
store_Ah:
	mov16	dd+2,AH
        call Ser_sent

Ser_sent:
   banksel      SPBRG
   movlw      .25                  ; 9.6kbps
   movwf      SPBRG
   movlw      b'00100100'      ; brgh = high (2)
   movwf      TXSTA            ; enable Async Transmission, set brgh

   ; Provide a settling time for startup
   banksel      tmp1
   clrf       tmp1
   settle
   decfsz       tmp1, f
   goto       settle


   ; Send a character through the UART
loop
[COLOR="Red"][B][I]   movlw      AmpHours[/I][/B][/COLOR]
   call      send
   goto      $

;----------------------
; SEND function
;----------------------
send
   banksel      TXREG
   movwf       TXREG            ; Send data which has been stored in W

trans_wt
   banksel      TXSTA
   btfss       TXSTA, TRMT         ; Loop until data is sent
   goto      trans_wt      
   return

   end
I am not sure about this:
movlw AmpHours
as i just pass the literal value of it...:confused:
 

tresca

Member
I guess the only alternative is to bit bang your data. You can send 16bits out or more out, since you are in control. But depending on where you are sending the data, it may or may not work. I think PC it would not work (could be wrong).

But it would be easier to send 2 bytes.
 

scomi

New Member
I guess the only alternative is to bit bang your data. You can send 16bits out or more out, since you are in control. But depending on where you are sending the data, it may or may not work. I think PC it would not work (could be wrong).

But it would be easier to send 2 bytes.
If using bit bang which means I will need to use software UART?????
I am sending data to another module.... RF module....
can explain in details for that as i aint catch up what you are guiding here, thanks.
I am running short of time... :(
 

tresca

Member
Yes a sofware UART.

I dont have any details on it. I don't program in ASM unless I need to and i have a C compiler that contains a software UART library.

Look up software uart or bitbang serial. I'm sure you can find some asm code.

Why is it crucial to send 16bits ? Why cant you break it up into 2 bytes ?
 

Sceadwian

Banned
scomi can you refrence the data sheet for your RF module, or part number?
 

Sceadwian

Banned
That module accepts standard serial data, no software uart is required. You break the word into two bytes, and send each byte, then on the receiving end you put those bytes back into the word. I don't know PIC ASM so I can't write the code for you. Perhaps Nigel could whip up some quick code examples so Scomi know's what we're all talking about. Just how to take a word and break it into two bytes and, then takes those bytes and break put it back into a word.
 

Nigel Goodwin

Super Moderator
Most Helpful Member
Well.... the variable AH is declared as WORDS:
That's completely meaningless, it's just a word (no pun intended), all it does is allocate two bytes - there are no registers bigger than a byte, nor does there need to be.

Just send one of those bytes, then send the second one - as simple as that. It doesn't matter which way round you send them, as long as you receive them in the same order.

Something like this:

Code:
movf LoByte, w
call SendSerial
movf HiByte, w
call SendSerial
 

scomi

New Member
That's completely meaningless, it's just a word (no pun intended), all it does is allocate two bytes - there are no registers bigger than a byte, nor does there need to be.

Just send one of those bytes, then send the second one - as simple as that. It doesn't matter which way round you send them, as long as you receive them in the same order.

Something like this:

Code:
movf LoByte, w
call SendSerial
movf HiByte, w
call SendSerial
OK..so which means something like this?

Code:
loop
   movlw      AmpHours
   movf LoByte, w
   call SendSerial
   movf HiByte, w
   call SendSerial
   goto      $
Thanks Nigel.
 

Nigel Goodwin

Super Moderator
Most Helpful Member
OK..so which means something like this?

Code:
loop
   movlw      AmpHours
   movf LoByte, w
   call SendSerial
   movf HiByte, w
   call SendSerial
   goto      $
Thanks Nigel.
No, 'MOVLW AmpHours' won't do anything, it will just load the 8 bit number represented by AmpHours (the address it represents) into W.

LoByte and HiByte are the two GPR's you're using as a 16 bit variable, you need to substitute whatever you're using. AmpHours and AmpHours+1 are the probable names.
 
Status
Not open for further replies.

EE World Online Articles

Loading
Top