Trigonometry Functions with the PICmicro MCU - Code E-mail
Article Index
Trigonometry Functions with the PICmicro MCU
Assumptions
Equipment (Mid-range PIC MCU, e.g. 16f84)
Discussion
Code
All Pages

Code

#define _version "0.01"</p><pre>
; Author: 		Alex Franke
; Copyright: 		(c)2002 by Alex Franke. All rights reserved. 
;
; Title: 		sin
; Description: 		Computes the sine of an angle given in degrees of a 
;			256-degree circle.
;
; Device: 		Microchip PIC MCU, p16f84
;			or other mid-range PIC MCU's
;
; Update History:	6/11/02	Created
;

 LIST 		R=DEC
 INCLUDE 	"p16f84.inc"

; Registers
 CBLOCK	0x020
sinTemp, theta, temp, temp2
 ENDC

 __CONFIG _CP_OFF & _WDT_OFF & _RC_OSC & _PWRTE_ON


; Main

 org 0

Start

  ; Set up
  movlw		84		; specify an angle value
  nop				; pause here to change value if desired for testing
  movwf		theta		; save that angle for use later

  ; now start the examples...
  ; Assume the angle you're trying to find is in theta and you want to find...
  ; ...its sine (0 to 255) and its sign (positive or negative)
  movf		theta, w	; copy to w so we can work with it
  call		sinw		; we now have the sine in w
  btfsc		theta, 7	; test the original angle to see if it's in Q3 or Q4
    nop				; ... if so, we know it's a negative, so handle that here

  ; ...its sine (-127 to 127)
  movf		theta, w	; copy to w so we can work with it
  call		sinw		; we now have the sine in w
  movwf		temp		; store result in temp register
  bcf		STATUS, C	; clear the carry bit if it's set -- we're about to roll
  rrf		temp, w		; roll temp result right to cut in half, store in w
  btfsc		theta, 7	; test the original angle to see if it's in Q3 or Q4
   sublw 	0		; ...it is, so negate w 
  nop				; sine (-127 to 127) is now in w


  ; ...its cosine (0 to 255) and its sign (positive or negative)
  ; A cosine is basically a sine, but shifted to the left one quadrant. This means
  ; that a sine is a cosine shifted to the right. So the cosine of any angle is 
  ; equal to the sine at the same position one quadrant to the right, or 
  ; cos(x)=sin(90+x). So to convert to sine we add 90 deg (64 degrees in our 256-deg circle)
  ; to the original angle.  
  movf		theta, w	; copy to w so we can work with it
  addlw		64		; add pi/2 so we can just take the sine
  movwf		temp		; move new angle to temp because we test this later
  call		sinw		; we now have the sine in w
  btfsc		temp, 7		; test the original angle to see if it's in Q3 or Q4
    nop				; ... if so, we know it's a negative, so handle that here


  ; ...its cosine (-127 to 127)
  movf		theta, w	; copy to w so we can work with it
  addlw		64		; convert cos to sin
  movwf		temp2		; store in temp2 register so we can compare for negative
  call		sinw		; we now have the sine in w
  movwf		temp		; store result in temp register
  bcf		STATUS, C	; clear the carry bit if it's set -- we're about to roll
  rrf		temp, w		; roll temp result right to cut in half, store in w
  btfsc		temp2, 7	; test the original angle to see if it's in Q3 or Q4
   sublw 	0		; ...it is, so negate w 
  nop				; sine (-127 to 127) is now in w



  ; ...its tangent, cotangent, secant, cosecant, etc
  ; Rather than going into a dissertation on how computers divide numbers, 
  ; let me just recommend using a good divide macro and any of the following 
  ; equations... 
  ;
  ;   tan( x ) = sin( x ) / cos( x )
  ;   cot( x ) = 1 / tan( x )		= cos( x ) / sin( x )
  ;   csc( x ) = 1 / sin( x )
  ;   sec( x ) = 1 / cos( x )
  ; 
  ; These Pythagorean identities may also be useful
  ; 
  ;   sin^2( x ) + cos^2( x ) = 1
  ;   sec^2( x ) = 1 + tan^2( x )
  ;   csc^2( x ) = 1 + cot^2( x )
  ;
  ; These will help with adding and subtracting
  ;
  ;   sin( x + y ) = ( sin( x ) * cos( y ) ) + ( cos( x ) * sin( y ) )
  ;   sin( x - y ) = ( sin( x ) * cos( y ) ) - ( cos( x ) * sin( y ) )
  ;   cos( x + y ) = ( cos( x ) * cos( y ) ) - ( sin( x ) * sin( y ) )
  ;   cos( x - y ) = ( cos( x ) * cos( y ) ) + ( sin( x ) * sin( y ) )
  ;   tan( x + y ) = ( tan( x ) + tan( y ) ) / ( 1 - ( tan( x ) * tan( y ) ) )
  ;   tan( x - y ) = ( tan( x ) - tan( y ) ) / ( 1 + ( tan( x ) * tan( y ) ) )
  ; 
  ; And for doubled angles...
  ;
  ;   sin( 2x ) = 2 * sin( x ) * cos( x )
  ;   cos( 2x ) = cos^2( x ) - sin^2( x ) = ( 2 * cos^2( x ) ) - 1 = 1 - ( 2 * sin^2( x ) )
  ;   tan( 2x ) = ( 2 * tan( x ) ) / ( 1 - tan^2( x ) )
  ;
  ; And as we've used above... What's a cosine? It's on of several cofunctions:
  ;   
  ;   sin( 90 deg - x ) = cos( x )	cos ( x - 90 deg ) = sin( x )
  ;   sec( 90 deg - x ) = csc( x )	csc ( x - 90 deg ) = sec( x )
  ;   tan( 90 deg - x ) = cot( x )	cot ( x - 90 deg ) = tan( x )
  ;
  ; And finally... What's an arcsine, arccosecant, arccosine, arcsecant, arctangent, 
  ; and arccotangent? They're simply the inverses...
  ;   
  ;   arcsin ( sin(x) ) = x		arccos ( cos(x) ) = x
  ;   arcsec ( sec(x) ) = x		arccsc ( csc(x) ) = x
  ;   arctan ( tan(x) ) = x		arccot ( cot(x) ) = x
  ; 

  goto 	Start

Finished
  goto $

sinw
; If bit 7 is clear, we're in quadrant 1 or 3
; If bit 8 is clear, we're in quadrant 1 or 2
;		
;		bit 8 	bit 7
; Quadrant 1	  0	  0	read from begining of table
; Quadrant 2	  0	  1   	read from end of table
; Quadrant 3   	  1	  0	read from begining of table and negate
; Quadrant 4	  1	  1	read from end of table and negate
;
; Angles in quadrants 3 and 4 result in negative sines. Because returning
; a negative value from this subroutine would require an additional entry
; on the call stack (a call to the sine table to get the value before 
; negating it), we'll just leave it up to the user to negate the result
; if necessary. This saves us an additional call. 
; This table returns a value sclaed 0 to 255

  movwf		sinTemp		; Move input to temp variable to test it
  andlw		0x03F		; Clear the first two bits of input - number needs to be <= 64
  btfsc 	sinTemp, 6	; read from the begining or the end of the table?
   sublw	64		; ...read from end, so w = TableSize - Input
  addwf		PCL, f		; Position program counter to appropriate result
  dt 	  0,   6,  13,  19,  25,  31,  37,  44
  dt	 50,  56,  62,  68,  74,  80,  86,  92
  dt	 98, 103, 109, 115, 120, 126, 131, 136
  dt	142, 147, 152, 157, 162, 167, 171, 176
  dt 	180, 185, 189, 193, 197, 201, 205, 208
  dt	212, 215, 219, 222, 225, 228, 231, 233
  dt	236, 238, 240, 242, 244, 246, 247, 249
  dt	250, 251, 252, 253, 254, 254, 255, 255, 255

  end


Last Updated ( Saturday, 26 January 2008 23:03 )