|
Page 5 of 5 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
|