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.

Line Draw in Assembly

Status
Not open for further replies.

jpanhalt

Well-Known Member
Most Helpful Member
This question relates to a continuation of my project from last Winter (See: https://www.electro-tech-online.com/threads/ks0108-glcd-busy-reads.125826/).

In brief, I am making a remote level indicator to help in manipulating forks attached to a front-end loader of a tractor. My progress before I suspended work was to get a Memsic accelerometer working and read by a 12F683, software serial communication, and a 16F1519 driven grahical display GLCD). I will probably use an XBee for an RF link. I am working in Assembly and have not connected everything to work together yet.

At the display level, I was able to plot pixels and draw vertical and horizontal lines by just repeating a pattern. I would like to be able to actually draw a line that deviates from horizontal in rough proportion to the inclination of the forks.

I am grateful for the help from several members who made my progress possible. We are still in early Fall in Northern Ohio, and it will be a late October before before things stop growing, grass doesn't need cutting, and I can concentrate for a long enough period to actually start back where I left off.

I hope there is no harm in starting early and thought I would post this request now for input, tips, and code bits for a line draw program in PIC Assembly. At least I can study your suggestions and be more prepared for when I pull out my boxes of project notes.

Regards,

John

P.S. This is not a final year project due on Friday. :D
 
Hi John,

This is my line routine for the 16 series chip. It works out which quadrant the line is in and chooses the correct routine to plot the line. I think I've included all subroutine (except plot etc). Have a go at getting it working and come back with any problems.
Code:
; plots from XPos,YPos to XEnd,YEnd
; DX and DY are Delta X and Delta Y
; ForI and ForJ are count variables.
; LCDTemp is a temporary variable.
; b_Critical is bit that gets set if there is a critical error in the GLCD routines.
; The plot sub should plot as XPos,YPos

Line		movfw	XEnd
		movwf	XCopy
		movfw	YEnd
		movwf	YCopy
		movfw	XPos		;63
		subwf	XEnd,W		;0
		call	Abs
		movwf	DX		;63
		movfw	YPos		;31
		subwf	YEnd,W		;31
		call	Abs		;0
		movwf	DY		;0
		subwf	DX,W		;63-0 = 63 + C
		btfsc	STATUS,C
		goto	XBigger		;jumps
;Y is biggest dimension
		movfw	YPos
		subwf	YEnd,W
		btfss	STATUS,C
		call	SwapEm
		bcf	STATUS,C
		rrf	DY,W
		movwf	ForJ
		incf	DY,W
		movwf	ForI
		movfw	XPos
		subwf	XEnd,W
		btfsc	STATUS,C
		goto	YBigXRight
; line goes left
YBXLLoop	call	Plot
		btfsc	b_Critical
		return
		incf	YPos,F
		movfw	DX
		subwf	ForJ,F
		btfsc	STATUS,C
		goto	NoDecX
		movfw	DY
		addwf	ForJ,F
		decf	XPos,F
NoDecX		decfsz	ForI,F
		goto	YBXLLoop
DoneLine	movfw	XCopy
		movwf	XPos
		movfw	YCopy
		movwf	YPos
		return

YBigXRight
; line goes right
YBXRLoop	call	Plot
		btfsc	b_Critical
		return
		incf	YPos,F
		movfw	DX
		subwf	ForJ,F
		btfsc	STATUS,C
		goto	NoIncX
		movfw	DY
		addwf	ForJ,F
		incf	XPos,F
NoIncX		decfsz	ForI,F
		goto	YBXRLoop
		goto	DoneLine

XBigger ; or same
		movfw	XPos		;63
		subwf	XEnd,W		;0-63 = -63 NC
		btfss	STATUS,C	;no skip
		call	SwapEm		;swapped
		bcf	STATUS,C
		rrf	DX,W
		movwf	ForJ
		incf	DX,W
		movwf	ForI
		movfw	YPos
		subwf	YEnd,W
		btfsc	STATUS,C
		goto	XBigYDown
; line goes up
XBYULoop	call	Plot
		btfsc	b_Critical
		return
		incf	XPos,F
		movfw	DY
		subwf	ForJ,F
		btfsc	STATUS,C
		goto	NoDecY
		movfw	DX
		addwf	ForJ,F
		decf	YPos,F
NoDecY		decfsz	ForI,F
		goto	XBYULoop
		goto	DoneLine

XBigYDown
; line goes down or level
XBYDLoop	call	Plot
		btfsc	b_Critical
		return
		incf	XPos,F
		movfw	DY
		subwf	ForJ,F
		btfsc	STATUS,C
		goto	NoIncY
		movfw	DX
		addwf	ForJ,F
		incf	YPos,F
NoIncY		decfsz	ForI,F
		goto	XBYDLoop
		goto	DoneLine

SwapEm		movfw	XPos
		movwf	LCDTemp
		movfw	XEnd
		movwf	XPos
		movfw	LCDTemp
		movwf	XEnd
		movfw	YPos
		movwf	LCDTemp
		movfw	YEnd
		movwf	YPos
		movfw	LCDTemp
		movwf	YEnd
		return

Abs		addlw	0x80
		addlw	0x80
		btfsc	STATUS,C
		return
		xorlw	0xff
		addlw	1
		return

I also have a routine that will plot a line using an angle and direction if that would be useful.

Have fun,

Mike.
 
Wow, that was fast and great help. My 12F683 will be transmitting an angle (±10°) -- I hope. At least I have gotten it to read the PWM from the inclinometer and do a look-up table.

Eventually, a line based on angle and direction will be most helpful. But, no rush. Let me digest this program.

John
 
The angle/direction routines are spread over a few files (GLCD, math, Tableread etc.) so will take a little longer to sort out. However, for ±10° it's easier to use a dedicated lookup table.

Let me know how you get on.

Mike.
 
I will probably just encode everything and not use real angles. By that I mean, I may send deflections as 0 to 14 plus a sign bit. The corresponding deflections would not be distributed linearly. Near horizontal, 1/4" may make a difference. At 5°, that would not be important at all. Deflections are at the fork tips, 42". Despite the turn-key nature of XBee, I am still worried about that link being the weak link.

After briefly looking at your program, I think it will do everything I need. It would be nice, though, to be able to specify angle for other purposes in the future. Also, others using Assembly may find it very useful.

John
 
I would have a play with a pixel editing program, even the Windows Paint program, and have a look at what the angles look like with your exact number of LCD pixels. I think for your application if the screen has a lowish number of pixels it might be better to have a set of screen display "lines" and just use a lookup table that displays the line you want, for whatever the angle is.

That saves you the hassle of doing tan() in assembler and also gives the ability to display data non-linearly, and also to use a more attractive graphics "line" for each setting.

It also sorts out a coordinate problem with having the lines centred, as to do it by calc means the line is drawn from one end to the other, so centreing on the middle pixel of the line is tricky.
 
Here's the angle/length code. I wrote it about 8 years ago and so can't remember exactly how it works but I think my added comments are correct.

Code:
; ALL angles are 0 to 255
; I think zero is 3 oclock and 64 is 12 oclock

;variables
;Angle, Length - line parameters
;XPos, YPos - start coords
;AccLo, AccHi - 16 bit accumulator
;Pointer - 16 bit memory pointer
;Temp - guess
;b_Sign - a bit variable to hold the sign value


;the way I assign bit variables is as follows

	cblock		0xnn
Flags
	endc

#define	b_Sign		Flags,7
#define	b_Crytical	Flags,6

;etc.

;The code

RadialLine	bcf	STATUS,C
		rlf	Length,F
		movfw	Angle
		call	GetCos
		call	Calc
		addwf	XPos,W
		movwf	XEnd
		movfw	Angle
		call	GetSine
		call	Calc
		sublw	0
		addwf	YPos,W
		movwf	YEnd
		goto	Line

Calc		bcf	b_Sign
		btfss	AccHi,7
		goto	NoNeg
		bsf	b_Sign
		call	Negate
NoNeg		bcf	STATUS,C
		rrf	AccHi,F
		rrf	AccLo,F
		bcf	STATUS,C
		rrf	AccHi,F
		rrf	AccLo,F
		bcf	STATUS,C
		rrf	AccHi,F
		rrf	AccLo,F
		movfw	Length
		call	Mult8x8
		movfw	AccHi
		btfsc	b_Sign
		sublw	0
		return

;will multiply W by AccLo and return the result in AccHi:Lo
Mult8x8
		clrf	AccHi
		clrf	Count
		bsf	Count,3
		rrf	AccLo,F
Loop		btfsc	STATUS,C	;SKPNC
		addwf	AccHi,F
		rrf	AccHi,F
		rrf	AccLo,F
		decfsz	Count,F
		goto	Loop
		return

GetCos		addlw	.64

;will return a 10  bit (+sign) value equal to (sin(w)+1)*512
GetSine		movwf	Temp
		btfsc	Temp,6		;are we in 2nd or 4th quadrant
		sublw	0		;negate - note 64 will become 192
		andlw	0x7f		;and now back to 64
		addlw	low SineTab
		movwf	Pointer
		movlw	high SineTab
		btfsc	STATUS,C
		addlw	1
		movwf	Pointer+1
		call	SetEEAdd
		call	ReadEEWord
		btfss	Temp,7		;are we in the 3rd or 4th quadrant
		return

SineTab
		dw	0,25,50,75,100,125,150,175
		dw	199,224,248,273,297,321,344,368
		dw	391,414,437,460,482,504,526,547
		dw	568,589,609,629,649,668,687,706
		dw	724,741,758,775,791,807,822,837
		dw	851,865,878,890,903,914,925,936
		dw	946,955,964,972,979,986,993,999
		dw	1004,1008,1012,1016,1019,1021,1022,1023
		dw	1024
		dw	-.122 

; need to negate Acc
Negate
		comf	AccLo,F
		comf	AccHi,F
		incfsz	AccLo,F
		return
		incf	AccHi,F
		return

;Note:- the various banking instructions may be wrong.
;       they are correct for 16F88 and 16F688
; this could be converted to use the retlw type table instead.

SetEEAdd	bsf	STATUS,RP1		;#2
		movfw	Pointer
		movwf	EEADR
		movfw	Pointer+1
		movwf	EEADRH
		bcf	STATUS,RP1
		return

ReadEEWord	bsf	STATUS,RP1		;#2
		bsf	STATUS,RP0		;#3
		bsf	EECON1,EEPGD
		bsf	EECON1,RD
		nop
		nop
		bcf	STATUS,RP0		;#2
		movfw	EEDAT
		movwf	Acc
		movfw	EEDATH
		movwf	Acc+1
		incfsz	EEADR,F		;Increment address
		goto	DoneREE
		incf	EEADRH,F
DoneREE		bcf	STATUS,RP1	;#0
		return

Have fun.

Edit, just noticed I double the line length as the first instruction. I don't remember why I did that but it may need removing. Don't have the equipment or time to work it out at the moment.

Mike.
 
Last edited:
It also sorts out a coordinate problem with having the lines centred, as to do it by calc means the line is drawn from one end to the other, so centreing on the middle pixel of the line is tricky.

This isn't a problem. You start in the middle and do the line each way 180° apart - or with my code 128 apart.

Mike.
 
@Pommie,

Thank you. That should be fun to play with, even if it turns out not to be needed for the tractor project.

@Mr RB

You are quite right about the limited angles that will or can be displayed. My screen is only 64X128. The final solution may be very simple as you suggest.

As for tangents, you can't live without them. ;) Conversion from the duty cycle produced by my sensor, which is proportional to g, to angle and/or deflection is done with a table.

In reality, this particular project is a learning tool for me that has a practical application. At the very outset, I connected the sensor module to the data module of the hacked digital level with a long 4-wire shielded cable (20-ft telephone cable) and had a working device. But, I find this so much more fun and gratifying to do.

John
 
Status
Not open for further replies.

Latest threads

Back
Top