Code:
' Sine Calculation - Interpolated Method
' ======================================
' Melanie Newman
' 15/Sept/2004
' Program demonstrates SINE calculation
' using a simple interpolative method.
' Input Angles valid from 0-359.99 degrees
' Output SINE to four decimal places ie 1.0000
' Display is on 2-line LCD with 3 buttons
' Same circuit layout as per 'Olympic Timer' previously posted.
'
' PIC Defines
' ===========
'
' Change these defines to suit your chosen PIC
' Your PIC must have 180 Bytes of EEPROM
'
@ DEVICE pic16F876, XT_OSC
@ DEVICE pic16F876, WDT_ON
@ DEVICE pic16F876, PWRT_ON
@ DEVICE pic16F876, BOD_ON
@ DEVICE pic16F876, LVP_OFF
@ DEVICE pic16F876, CPD_OFF
@ DEVICE pic16F876, PROTECT_OFF
@ DEVICE pic16F876, WRT_OFF
'
' Hardware Defines
' ================
'
' LCD Display
' -----------
' Adjust these to suit your chosen LCD pinout
'
Define LCD_DREG PORTC ' Port for LCD Data
Define LCD_DBIT 4 ' Use upper 4 bits of Port
Define LCD_RSREG PORTC ' Port for RegisterSelect (RS) bit
Define LCD_RSBIT 0 ' Port Pin for RS bit
Define LCD_EREG PORTC ' Port for Enable (E) bit
Define LCD_EBIT 3 ' Port Pin for E bit
Define LCB_BITS 4 ' Using 4-bit bus
Define LCD_LINES 2 ' Using 2 line Display
Define LCD_COMMANDUS 2000
' Command Delay (uS)
Define LCD_DATAUS 50 ' Data Delay (uS)
'
' Control Buttons/Lines
' ---------------------
ButtonUp var PortB.0 ' Take this pin low momentarily to INCREMENT
ButtonDown var PortB.1 ' Take this pin low momentarily to DECREMENT
ButtonSet var PortB.2 ' Take this pin low momentarily to SET
'
' Software Defines
' ----------------
Angle var WORD ' Input angle 0-36000 representing 0.00-360.00 degrees
CounterA var BYTE
KeyBut var BYTE ' Keyboard Button Code
Sine var WORD ' Sine value 0-10000 representing 0-1.0000
SineMax var WORD ' High-end of Lookup
SineMin var WORD ' Low-end of Lookup
SineNeg var BIT ' Flag indicating Negative answer
TempA var WORD
TempB var BYTE
UserData var BYTE[5] ' User-Entry Edit Field
UserMax var BYTE ' Variable to keep numeric entry within integer limitations
UserPos var BYTE ' User Entry Field Position
'
' EEPROM Presets
' --------------
Data @0,$00,$AF ' 1 = 175 (Sine of 1 Degree = 0.0175)
Data $01,$5D ' 2 = 349 (Sine of 2 Degrees - 0.0349)
Data $02,$0B ' etc, etc
Data $02,$BA
Data $03,$68
Data $04,$15
Data $04,$C3
Data $05,$70
Data $06,$1C
Data $06,$C8
Data $07,$74
Data $08,$1F
Data $08,$CA
Data $09,$73
Data $0A,$1C
Data $0A,$C4
Data $0B,$6C
Data $0C,$12
Data $0C,$B8
Data $0D,$5C
Data $0E,$00
Data $0E,$A2
Data $0F,$43
Data $0F,$E3
Data $10,$82
Data $11,$20
Data $11,$BC
Data $12,$57
Data $12,$F0
Data $13,$88
Data $14,$1E
Data $14,$B3
Data $15,$46
Data $15,$D8
Data $16,$68
Data $16,$F6
Data $17,$82
Data $18,$0D
Data $18,$95
Data $19,$1C
Data $19,$A1
Data $1A,$23
Data $1A,$A4
Data $1B,$23
Data $1B,$9F
Data $1C,$19
Data $1C,$92
Data $1D,$07
Data $1D,$7B
Data $1D,$EC
Data $1E,$5B
Data $1E,$C8
Data $1F,$32
Data $1F,$9A
Data $20,$00
Data $20,$62
Data $20,$C3
Data $21,$20
Data $21,$7C
Data $21,$D4
Data $22,$2A
Data $22,$7D
Data $22,$CE
Data $23,$1C
Data $23,$67
Data $23,$AF
Data $23,$F5
Data $24,$38
Data $24,$78
Data $24,$B5
Data $24,$EF
Data $25,$27
Data $25,$5B
Data $25,$8D
Data $25,$BB
Data $25,$E7
Data $26,$10
Data $26,$35
Data $26,$58
Data $26,$78
Data $26,$95
Data $26,$AF
Data $26,$C5
Data $26,$D9
Data $26,$EA
Data $26,$F8
Data $27,$02
Data $27,$09
Data $27,$0E
'
' Start Program
' =============
'
' Initialise Processor
' --------------------
TRISA=%00000001
TRISB=%11111111
TRISC=%00000000
OPTION_REG.7=0 ' Enable Pull-Up's
Pause 1000
Angle=0
'
' Enter Data
' ----------
' This section gets variable ANGLE
' ANGLE is a value 0-36000 where 36000 represents 360.00 Degrees.
' Press UP/DOWN Buttons to set the Angle 0-360, then Press SET to Accept the value
'
Loop:
LCDOut $FE,$01,$FE,$0E,"Angle "
Gosub DisplayAngle
LCDOut " Deg"
UserPos=0
Gosub UserEntry
If Angle>35999 then
LCDOut $FE,1,"Angle must be",$FE,$C0,"less than 360.00"
Pause 1000
goto Loop
endif
'
' Calculate & Display SINE
' ------------------------
' This section gets and Displays the resultant variable SINE
'
Gosub CalculateSine
LCDout $FE,$C0,"Sine "
If SineNeg=1 then LCDOut "-"
LCDOut #SINE DIG 4,".",#SINE DIG 3,#SINE DIG 2,#SINE DIG 1,#SINE DIG 0
'
' Loop around again (Press SET to Continue)
' -----------------------------------------
While KeyBut<>3:Gosub GetKey:Wend
LCDOut $FE,1
While KeyBut<>7:Gosub GetKey:Wend
Goto Loop
'
' Subroutine Calculates Sine
' --------------------------
CalculateSine:
SineNeg=0
If ANGLE>18000 then SineNeg=1 ' Determine if negative Result
TempA=Angle ' Reduce angle to 1st Quadrant (0-90 degrees only)
If TempA>17999 then TempA=TempA-18000
If TempA>9000 then TempA=9000-(TempA-9000)
'
' Load Low-End of Lookup
' ----------------------
CounterA=TempA/100
If CounterA=0 then
SineMin=0
else
If CounterA=90 then
SineMin=10000
else
TempB=CounterA*2-2:Read TempB,SineMin.Highbyte
TempB=TempB+1:Read TempB,SineMin.Lowbyte
endif
endif
'
' Load High-End of Lookup
' -----------------------
CounterA=CounterA+1
If CounterA=>90 then
SineMax=10000
else
TempB=CounterA*2-2:Read TempB,SineMax.Highbyte
TempB=TempB+1:Read TempB,SineMax.Lowbyte
endif
'
' Determine the Decimal Fraction (Interpolation) Bit
' --------------------------------------------------
TempB=TempA-((TempA/100)*100)
Sine=SineMin+(((SineMax-SineMin)*TempB)/100)
Return
'
' Subroutine Reassembles User-Entered Angle
' -----------------------------------------
ReassembleAngle:
Angle=UserData(0)*10000
Angle=Angle+(UserData(1)*1000)
Angle=Angle+(UserData(2)*100)
Angle=Angle+(UserData(3)*10)
Angle=Angle+UserData(4)
'
' subroutine Displays Angle
' -------------------------
DisplayAngle:
LCDOut $FE,$86,$FE,$0C
If Angle>9999 then
LCDOut #ANGLE DIG 4
else
LCDOut " "
endif
If Angle>999 then
LCDOut #ANGLE DIG 3
else
LCDOut " "
endif
LCDOut #ANGLE DIG 2,".",#ANGLE DIG 1,#ANGLE DIG 0
Return
'
' Subroutine Scans Buttons
' ------------------------
' KeyBut - 0 = Invalid (SET+UP+DOWN Pressed)
' - 1 = Invalid (SET+UP Pressed)
' - 2 = Invalid (SET+DOWN Pressed)
' - 3 = SET Pressed
' - 4 = Invalid (UP+DOWN Pressed)
' - 5 = UP Pressed
' - 6 = DOWN Pressed
' - 7 = No Buttons Pressed
GetKey:
KeyBut=0 ' Zero any previous Result First
KeyBut.0=ButtonDown ' Read Input Buttons
KeyBut.1=ButtonUp
KeyBut.2=ButtonSet
Pause 100 ' Allows for 10cps auto-repeat
Return
'
' Subroutine performs User Numeric Field Entry
' --------------------------------------------
UserEntry:
For CounterA=0 to 4
UserData(CounterA)=Angle DIG (4-CounterA)
Next CounterA
UserEntryLoop:
CounterA=$86+UserPos
If UserPos>2 then CounterA=CounterA+1
LCDOut $FE,CounterA,$FE,$0E
UserEntryLoopSkip:
Gosub GetKey
UserMax=9
If UserPos=0 then UserMAX=3
If KeyBut=5 then
UserData(UserPos)=UserData(UserPos)+1
If UserData(UserPos)>UserMAX then UserData(UserPos)=0
gosub ReassembleAngle
goto UserEntryLoop
endif
If KeyBut=6 then
If UserData(UserPos)=0 then
UserData(UserPos)=UserMAX
else
UserData(UserPos)=UserData(UserPos)-1
endif
gosub ReassembleAngle
goto UserEntryLoop
endif
If KeyBut<>3 then goto UserEntryLoopSkip
While KeyBut<>7:Gosub GetKey:Wend
UserPos=UserPos+1
If UserPos<5 then goto UserEntry
Return
End
There you go... with only 178 EEPROM statements you've got 36,000 points on your Sine graph.
Bookmarks