Top Banner

of 65

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript

' SOLAR TRACKING PIC ' ' Version 03/09/2011 ' ' Current version tests code logic without peripherals connected to pins. ' Serial communications with notebook computer.

'**************************************************************** '* Name : sunrun.pbp '* Author : Sunflower '* Notice : Copyright (c) 2011 Sunflower '* : All Rights Reserved * * * * * * * *

'* Date : 2/23/2011 '* Version : 1.0 '* Notes : 18F4620 PICmicro '* :

'**************************************************************** ' ' Compiles with PIC BASIC PRO sold by melabs.com Compatible with LAB X1

' melabs.com Programmer (meProg) Options/More Options/Low Voltage Erase + Options/More Options/Program not Data ' (preserves old dish-data during reprogramming)

' Changes for internal oscillator, if desired. 'INCLUDE "P18F4620.INC" ; MPASM Header

'

__CONFIG _CONFIG1H, _OSC_INTIO67_1H & _FCMEN_OFF_1H & _IESO_OFF_1H

' Tiny PIC Bootloader = http://www.etc.ugal.ro/cchiculita/software/picbootloader.htm ' Tiny modifications tinybld18F4620_zigbee.asm for bootloading with internal oscillator ' __CONFIG _CONFIG1H, _OSC_INTIO67_1H & _FCMEN_OFF_1H & _IESO_OFF_1H ; set for 4 mhz you may want to change: _XT_OSC_1H _HS_OSC_1H

' xtal EQU 4000000 _HSPLL_OSC_1H ' baud EQU 9600

; the desired baud rate

'

movwf RCSTA

' (added after movwf RCSTA) ' ' ' ' http://www.picbasic.co.uk/forum/showthread.php?t=14434&s=de0290749fc5ff853a59643b070c910c ' ' ' ' ' ' ' ' The PORTL and PORTH aliases are used for the PIN numbers (0-15) ' PORTL is 0-7 and PORTH is 8-15. *** MUST DO THIS *** Default Re: Port Variables act like Constants movlw b'01100000' movwf OSCCON ;ADDED to set osccon to 4mhz internal

' Look in the .bas file for the chip you are using. ' If it's a 18F4620 then open c:\pbp\18F4620.bas

' PORTL VAR ' PORTH VAR ' TRISL VAR ' TRISH VAR '

PORTB PORTD TRISB TRISD

' PORTB AND PORTD can now be referenced by variables. ' http://www.picbasic.co.uk/forum/showthread.php?t=14493&s=de0290749fc5ff853a59643b070c910c

Define LOADER_USED 1 DEFINE OSC 4

' Bootloader space

' Tell program 4 MHz timing

define PULSIN_MAX 5000 ' TIMEOUT LIMIT FOR RCTIME and PULSIN COUNT 10us units @ 4MHz 50ms timeout

ADCON1 = %00001111 OSCCON = %01100000

' Make AN0-AN12 digital 'Internal oscillator speed 4 MHz

' Right_pin ' Left_pin

' HBridge motor controller

' CCP1_pin pwm ' Enable_Azimuth_pin

' Up_pin ' Down_pin ' CCP2_pin pwm ' Enable_Altitude_pin ' ' A/B pins reversible -' ' ' ' ' ' ' ' PORTB.0 Azimuth Sensor A/B = 0 ' Rotate X1 Accelerometer MEMSIC 2125 PORTB.1 Azimuth Sensor A/B = 1 ' Rotate Y1 Accelerometer MEMSIC 2125 PORTB.2 PORTB.3 Programming Pin PORTB.4 Altitude Sensor A/B = 4 ' Rotate X2 Accelerometer MEMSIC 2125 PORTB.5 Altitude Sensor A/B = 5 ' Rotate Y2 Accelerometer MEMSIC 2125 PORTB.6 Programming Pin PORTB.7 Programming Pin

' ' spkr ClockPin DataPin ' ' '

PORTC.1 HPWM channel 2 altitude motor speed PORTC.2 HPWM channel 1 azimuth motor speed Var var var PORTC.2 ' Alias speaker pin on LAB-X1 board PORTC.3 ' I2C SCL ' I2C PORTC.4 ' I2C SDA ' I2C - DS1307 clock

PORTC.6 PORTC.6 TX HSEROUT RS232 PORTC.7 RX HSERIN RS232

' ' ' ' ' ' ' '

PORTD.0 Azimuth Motor A/B = 8 PORTD.1 Azimuth Motor A/B = 9 PORTD.2 Altitude Motor A/B = 10 PORTD.3 Altitude Motor A/B = 11 PORTD.4 Azimuth Eye A/B = 12 PORTD.5 Azimuth Eye A/B = 13 PORTD.6 Altitude Eye A/B = 14 PORTD.7 Altitude Eye A/B = 15 ' RC Time photoresister parallel with 1 mf capacitor. ' RC Time photoresister parallel with 1 mf capacitor. ' RC Time photoresister parallel with 1 mf capacitor. ' RC Time photoresister parallel with 1 mf capacitor.

sw1 sw2

var var

byte ' Port Switch 1 byte ' Port Switch 2

time old_time days declination

VAR var var

Word ' 1440 minutes per day word ' Last minute word ' Number of days Byte ' +/- 17 Brads (+/- 24 degrees) BYTE ' Declination used as time stamp of old memory.

VAR

old_declination VAR

azMotor altMotor azSensor altSensor azEye altEye azMotor_A

var var var var var var

byte ' For controlling forward/reverse pin assignments after istallation. byte ' Software rewires motors and sensors by optionally swapping A with B. byte byte byte byte

var

byte

azMotor_B altMotor_A altMotor_B azSensor_A azSensor_B altSensor_A altSensor_B azEye_A azEye_B altEye_A altEye_B

var var var var var var var var var var var

byte byte byte byte byte byte byte byte byte byte byte

flag SIGNa SIGNb

VAR VAR VAR

word FLAG.0 FLAG.1 flag.2 flag.3 flag.4 flag.5 flag.6 flag.7

solar_noon

var

Azimuth_Stow var Altitude_Stow var flag_north display reboot var var var

azimuth_command altitude_command azimuth_go

VAR VAR

FLAG.8 FLAG.9

VAR

FLAG.10

altitude_go

VAR

FLAG.11

azimuth_spin altitude_spin azimuth_on altitude_on

VAR VAR VAR VAR

FLAG.12 FLAG.13 FLAG.14 FLAG.15

flag2

var

word flag2.0

sun_overhead VAR cloudy Focus read_flag write_flag VAR VAR VAR VAR

flag2.1 flag2.2 flag2.3 flag2.4 flag2.5

tropic_summer VAR dark VAR

flag2.6 flag2.7

stow_write

VAR

MoreBits Fix var

var

byte

MoreBits.0

test click pointer second

var var

byte ' Menu character word ' Test clock word byte byte

VAR var

previous_second var

smooth k z f var var var

var

byte

byte ' Scale constant derived from sensor installation word ' Scale constant derived from sensor installation word ' Scale constant derived from sensor installation

Azimuth_Memory VAR Altitude_Memory VAR Azimuth_sensor VAR Altitude_sensor VAR Azimuth_Path VAR Altitude_Path VAR

BYTE BYTE Byte

Byte BYTE ' Brads from solar position algorithm BYTE ' Brads from solar position algorithm BYTE BYTE BYTE BYTE

Azimuth_Path_sense VAR Altitude_Path_sense VAR Azimuth_Destination VAR Altitude_Destination VAR

dawn AM PM

var VAR VAR

byte ' Azimuth sensor location of calculated sunrise word ' Time that sun crosses from north to south word ' Time that sun crosses from south to north

Latitude var byte ' 18.5 degrees Pune = 13 brads '47 degrees Tacoma = 33 brads (binary radians 0-255 in 256 circle) due_north due_south due_up minXY var var var var byte ' Azimuth sensor value of Polaris star. byte ' Azimuth sensor value of due south byte ' Altitude sensor value straight up byte ' Before due north in the west if in tropics.

maxXY minZ maxZ

var var var

byte ' After due south in the northwest byte ' Limit switch down byte ' Limit switch up

stow Dwell

var VAR

byte ' Reason(s) for stow byte ' Wait after eye tracking before memory tracking byte ' Number of minutes motor is on without detectable movement. byte ' Number of minutes motor is on without detectable movement. byte ' Last location of moving motor byte ' Last location of moving motor

Azimuth_Motor VAR Altitude_Motor VAR Azimuth_Move VAR Altitude_Move VAR SpeedAz SpeedAlt var var

byte ' Motor speed ~ duty cycle of PWM byte ' Motor speed ~ duty cycle of PWM

work work1 work2 work3 work4 work5 work6 work7 work8

VAR VAR VAR VAR VAR VAR VAR VAR var

Word Word Word Word Word Word WORD WORD word

WorkByte WB

var VAR

byte BYTE

WB1 WB2 dummy

VAR VAR var

BYTE BYTE byte

lat alt az h prior AMx PMx

var VAR VAR VAR VAR VAR VAR

word word word BYTE BYTE BYTE BYTE

' Work variables for solar path algorithm

sec minute hour day date month year

VAR VAR VAR VAR VAR VAR VAR

BYTE BYTE BYTE BYTE BYTE BYTE BYTE

' Time variables

north south east west

VAR VAR VAR VAR

WORD 'Up

Eye variables

WORD 'Down WORD 'Left WORD 'Right

xRaw yRaw

VAR VAR

word ' Accelerometer data word ' Accelerometer data

dat2 dat1 azPast altPast azFuture altFuture

VAR VAR VAR VAR VAR VAR

BYTE ' Memory dead reckoning variables. BYTE BYTE BYTE BYTE BYTE

yes no up down right left HiPulse LoPulse

con con CON CON CON CON CON CON

1 ' English 0 1 0 1 0 1 0

sun sun2 sun_Gap

CON CON CON

650 ' Sunny if one eye sees sun. 1300 ' Sunny if both eyes see bright. 100 ' If eye difference within gap then stop 2 2 ' Accelerometer +/- error. ' Accelerometer +/- error.

Azimuth_Gap

CON

Altitude_Gap CON ON_SUN memory CON

700 ' If both eyes < ON SUN then focused in clear sun, record position to

Too_Bright danger drift

CON CON

20 12

' Eye failure. ' Brads off calculated solar path and tracking the wrong way.

CON

2

' Value difference of old declination indicating memory too old to use

Search CON 8 ' Number of 4 minute units to search forward and backwards for memory dead reckoning memory gaps. orientate safe rampAz rampAlt startAz startAlt maxAz maxAlt freq CON CON CON CON CON CON CON CON con 64 20 4 16 96 96 ' Brads of azimuth for night park. ' Brads of altitude for night park. ' Unit of azimuth motor speed increase per second ' Unit of altitude motor speed increase per second ' Minimum azimuth motor start speed ' Minimum altitude motor start speed

208 ' Maximum azimuth motor speed, out of 255 units 208 ' Maximum altitude motor speed, out of 255 units 500 '20000 ' PWM frequency, make high to avoid ultrasonic whine

Top: ' Top of the program

PAUSE 10 SOUND SPKR,[113,4,118,4,120,4] ' Sound if speaker onboard.

CLEAR

' Must clear all varibles on startup

'high wind_pin 'pause 1 'low wind_pin

' Charge capacitor connected to wind detector.

sw1 = 1 '! Switches pulled up default at power start-up. All test statements followed by '! sw2 = 1 '! If not default switch setting at power up then serial display port enabled.

IF SW1 = 0 OR SW2 = 0 THEN DISPLAY = 1 ' If any switch flipped before power up then serial display enabled. IF sw1=0 AND sw2=0 THEN goto Set_Clock ' Hardware backdoor diagnostics. Enables communication. ' Configuration at power up to enable serial port. FIX = 1 reboot = 1 display = 1 '! Display forced on to test code without switches.

' *** Switch operation *** ' ' If both switches in default position before power on then silent running. ' If one or both switches flipped before power on then serial port enabled for communications. ' If both switches flipped before power on then hardware clock set. Flip switches and cycle power to exit. ' ' If both switches in default position after power on then silent running. ' If one or the other switch flipped after power on then altitude motor goes up or down and azimuth motor off. ' If both switches are flipped after power on then both motors off. ' ' Must cycle power to clear stow flags or to enable serial port display.

read 1000, WORD lat, due_north, due_south, due_up, minxy, maxxy, minz, maxz, dummy, azmotor, altmotor, azsensor, altsensor, azeye, alteye

' Values entered during installation. ' Use Polaris to determine true north and south. ' lat is site latitude in degrees times 10. ' Binary radians 256 Brads = 360 Degrees ' azMotor, altMotor, azSensor, altSensor are stored flags that reverse wires on pins as needed. ' ' Solar algorithm output --

' Horizontal is 0 brads. ' Vertical is 64 brads.

' Due north is 0 brads or Due north is 128 brads for negative latitudes. ' Due east is 64 brads. ' Due south is 128 brads or Due south is 0 brads for negative latitudes. ' Due west is 192 brads.

azMotor_A = 8 PORTB.7 azMotor_B = 9 to PORTD.7 if azMotor then azMotor_A = 9 azMotor_B = 8 endif

' Software will reverse wires if motor or sensor installed backwards.

PORTB.0 to

' Configured in Install subroutine. Used in Set_Motors HBridge subroutine. PORTD.0

altMotor_A = 10 altMotor_B = 11 if altMotor then altMotor_A = 11 altMotor_B = 10 endif

azSensor_a = 0 azSensor_B = 1 if azSensor then azSensor_a = 1 azSensor_B = 0 endif

altsensor_a = 4 altsensor_b = 5 if altsensor then altsensor_a = 5 altsensor_b = 4 endif

azeye_a = 12 azeye_b = 13 if azeye then

azeye_a = 13 azeye_b = 12 endif

altEye_a = 14 alteye_b = 15 if alteye then alteye_a = 15 alteye_b = 14 endif

Latitude = (((ABS lat) ** 46602) + 5) / 10 IF LAT.15 THEN Latitude = -Latitude

' 128/180*65535 +5 nearest integer ' If south of the equator.

k = due_up - 64 Due_up should be > = 80

'Brad altitude = Sensor altitude - k, Sensor altitude = Brad altitude + k

f = (256 * 128) / (due_south - due_north) z = (256 * (due_south - due_north)) / 128

'Brad azimuth = (sensor - due_north) */ f 'sensor azimuth = due_north + (brad azimuth */ z)

'If tropic_summer AND Azimuth_Path > 128 THEN sensor azimuth = due_north - ((256 - brad azimuth) */ z)

' Sample test data commented with post script '! ' Startup test eye data EAST = 825 '! eyes test data WEST = 775 '! NORTH = 825 '!

SOUTH = 775 '!

Azimuth_sensor = 180 '! starting position test data ALTITUDE_SENSOR = 70 '!

' month/day/year test data ' sec =$45: minute = $58:hour = $12:month = $7:date = $29:year = $11 '! 7/29/2011 For loading memory with test data. '{GOTO skipps} sec =$45: minute = $58:hour = $12:month = $8:date = $05:year = $11 '! 8/05/2011 For test run.

' sec =$45: minute = $58:hour = $12:month = $2:date = $05:year = $11 '! 2/05/2011 For test run. ' sec =$45: minute = $58:hour = $12:month = $10:date = $05:year = $11 '! 10/05/2011 For test run. ' sec =$45: minute = $58:hour = $11:month = $12:date = $21:year = $11 '! 12/21/2011 For test run. ' sec =$45: minute = $58:hour = $11:month = $06:date = $21:year = $11 '! 06/21/2011 For test run. ' sec =$45: minute = $58:hour = $11:month = $03:date = $21:year = $11 '! 03/21/2011 For test run. ' sec =$45: minute = $58:hour = $14:month = $03:date = $21:year = $11 '! 03/21/2011 For test run.

main:

'IF wind_pin = 0 then ' If wind detector discharged capacitor then stow 'stow = $FF 'altitude_stow = yes 'endif

'high wind_pin

' Charge capacitor connected to wind detector.

'pause 1 'low wind_pin

old_time = time Altitude_destination = 0 Azimuth_destination = 0

' Total minutes. ' Will be zero when eyes command. ' Will be zero when eyes command.

if display then hserout [12] 'Clear screen

GOSUB Get_Sensors ' Dish position from accelerometers on edge rolling like a coin. GOSUB Get_Time ' Number of minutes since midnight, and number of days since January 1

If old_time > time or reboot = 1 then ' New day routines below, once daily or when reboot.

gosub Get_Declination tropic_summer = 0

' 8 bit Brads

if declination.7 = 0 and declination >= Latitude THEN tropic_summer = 1 ' Sun always in north summer tropics.

work8 = time gosub Get_flags_north south to north time = work8 ' Flags times of arctangent crossover from north to south and from

gosub get_path flag_north = 1

' Get current sun position.

IF time > AM AND time < PM THEN flag_north = 0 if tropic_summer THEN flag_north = 1 IF flag_north = 1 THEN Azimuth_Path = PRIOR arctangent ~ the one in the north. wb = Altitude_Path + 1 horizon is 255.

' Sun in the south mid day.

' Sun always in north in the tropic during summer. ' Azimuth_Path = arctangent, prior = the other

' Adding 1 covers sunrise just below the horizon. Below the

if dark and time < 720 and wb < 68 then dark = no ' Sunrise! WB not big, like 255.

solar_noon = 1 ' Time adjust to solar noon open for automatic update when sun due south or due north. Clock is solar noon time, not clock time. reboot = 0 ' Reboot done

sun_overhead = no if Altitude_Path > 60 and Altitude_Path < 68 then sun_overhead = yes ' Used to disable azimuth tracking error detection during overhead sun. endif

goto skipps

' This routine between skipps fills tracking memory with test data ' memory space 2 AM to 10 PM ' Solar position calculator

for time = 120 to 1317 gosub get_path flag_north = 1

IF time > AM AND time < PM THEN flag_north = 0 ' Sun in the south if tropic_summer THEN flag_north = 1 ' Sun always in north ' North arctangent

IF flag_north = 1 THEN Azimuth_Path = PRIOR if time < 120 or time > 1317 then skipping IF Altitude_path > 68 THEN SKIPPING

' Memory space 2 AM to 10 PM ' No fake tracking data below the horizon

Azimuth_Path_sense = due_north + (Azimuth_Path */ z) ' Converts calculated Path Brads to specific dish sensor type data. if tropic_summer and Azimuth_Path > 127 then Azimuth_Path_sense = due_north - ((256Azimuth_Path) */ z) ' If tropical sun crosses north zero going west. Altitude_Path_sense = Altitude_Path + k sensor type data. ' Converts calculated Path Brads to specific dish

Pointer = ((Time / 4 )-30)*3

'EEPROM locations 0 to 899

WRITE pointer, Azimuth_path_sense, Altitude_path_sense, declination

hserout [7] skipping: next time goto ending ' END skipps:

if time.0 old_time.0 then gosub get_path flag_north = 1

'new one minute routines

'load current PATH location

IF time > AM AND time < PM THEN flag_north = 0 if tropic_summer THEN flag_north = 1 IF flag_north = 1 THEN Azimuth_Path = PRIOR

' Sun in the south ' Sun always in north ' North arctangent ' Sunrise!

if dark and time < 720 and Altitude_Path < 68 then dark = no

if Altitude_Path > 60 and Altitude_Path < 68 then sun_overhead = yes ' Used to disable azimuth tracking error detection during and after overhead sun. if dwell then dwell = dwell - 1 tracking. ' Countdown tranistion from eyes to memory

IF Azimuth_Motor THEN Azimuth_Motor = Azimuth_Motor + 1 IF Altitude_Motor THEN Altitude_Motor = Altitude_Motor + 1

' Count minutes motor running ' Count minutes motor running

IF Azimuth_Motor = 4 THEN end begining minute 4.

' = 4 could be as little as 2 minutes, start at end of minute 1 and

wb = Azimuth_sensor - azimuth_move ' Distance moved IF ABS wb 127 then Azimuth_Path_sense = due_north - ((256Azimuth_Path) */ z) ' If tropical sun azimuth crosses north 0 to 255 tracking towards west. Altitude_Path_sense = Altitude_Path + k type data. ' Converts calculated Path Brads to specific dish sensor

GOSUB Get_Eyes

' Eyes +/- 0.004 degrees. Creates motor commands. Closed loop

GOSUB Get_Memory ' Memory of past sun tracking, returns zeros if memory too old. Open loop

IF Stow THEN Check_Stow IF dark THEN park IF cloudy THEN memory

Sunny: ' Eyes command and bypass Helm

IF Focus THEN dwell = 8 ELSE dwell = 2 endif

' Wait after eye tracking before memory tracking. ' Wait 8 minutes if dish was previously focused.

' else ' Wait 2 minutes if previously tracking while sunny.

GOSUB set_Motors

goto run2 ' Print and loop

Park:

'Altitude_destination = orientate + k horizon.

' orientate brad to sensor data. Fixed Park altitude not on

'Azimuth_destination = due_north + (safe */ z) ' safe brad to sensor data. Fixed Park azimuth.

Altitude_destination = k Azimuth_destination = dawn

' Horizon ' Sunrise

GOTO Check_Stow

Memory:

IF Azimuth_Memory = 0 and altitude_memory = 0 THEN ' If no recent memory then Altitude_destination = Altitude_Path_sense Azimuth_destination = Azimuth_Path_sense else ' else ' tell Helm to use log book ' tell Helm to use map from Path '

Altitude_destination = Altitude_memory Azimuth_destination = Azimuth_memory ENDIF

Check_Stow:

IF Altitude_Stow THEN Altitude_destination = due_up - Altitude_Gap ' Point dish up minus sensor error IF Azimuth_Stow = no THEN Azimuth_destination = Azimuth_sensor stop azimuth motor. ENDIF ENDIF ' Azimuth_destination = Azimuth_sensor will tell Helm to

IF Azimuth_Stow THEN Azimuth_destination = due_north ' Point dish north

IF Altitude_Stow = no THEN Altitude_destination = Altitude_sensor 'Altitude_destination = Altitude_sensor will tell Helm to stop altitude motor. ENDIF ENDIF

IF stow AND stow_write = 0 THEN

' Write stow tag only once. Must cycle power to clear stow flags.

FOR pointer = 900 TO 992 STEP 4 ' Search for empty location to store stow data READ pointer, wb IF wb = $ff THEN EXIT NEXT pointer

wb = time/10

' Byte size of time/10

WRITE pointer, wb, stow, Azimuth_sensor, Altitude_sensor ' Record time, cause, dish position stow_write = 1 if display then hserout [7] ' Beep computer indicating EEPROM data write

ENDIF

IF Azimuth_Stow OR Altitude_Stow OR dark THEN Helm ' Do not dwell

clouds: IF dwell THEN azimuth_go = no altitude_go = no GOSUB set_motors ' If recently tracking sun then dwell before Memory or Path tracking.

goto run2 ENDIF

' Print and loop

Helm: ' Sets direction and go / no-go for each motor by comparing existing position with desired destination.

wb = Azimuth_sensor - Azimuth_destination

' Azimuth...

IF ABS wb < Azimuth_Gap AND azimuth_go = no THEN skipper ' If within sensor error and motor is off then leave motor off.

IF Azimuth_sensor = Azimuth_destination THEN azimuth_go = no GOTO skipper ENDIF

' If on target then turn motor off

azimuth_go = yes

' Else motor on

IF Azimuth_sensor < Azimuth_destination THEN azimuth_command = right ELSE azimuth_command = left endif ' Set direction

skipper: wb = Altitude_sensor - Altitude_destination ' Altitude...

IF ABS wb < Altitude_Gap AND altitude_go = no THEN skippy ' If within sensor error and motor is off then leave motor off.

IF Altitude_sensor = Altitude_destination THEN altitude_go = no GOTO skippy ENDIF

' If on target then turn motor off

altitude_go = yes

' Else motor on

IF Altitude_sensor < Altitude_destination THEN altitude_command = up ELSE altitude_command = down endif ' Set direction

skippy: GOSUB Set_Motors goto run2 ' Print and loop.

run2:

if display then

test = 0 ' Holds menu choice.

hserout ["

Azimuth

Altitude Dec",10,13,10] " ",dec Altitude_Path,10,13,10]

hserout ["Path brads ",dec Azimuth_Path,

hserout ["Path sense ",dec Azimuth_Path_sense, " declination,10,13] hserout ["Memory ",dec Azimuth_Memory, old_declination,10,13,10] hserout ["Sensor ",dec Azimuth_sensor, " "

",dec Altitude_Path_sense,"

",Sdec

",dec Altitude_Memory,"

",Sdec

",dec Altitude_sensor,10,13,10] ",dec Altitude_Destination," ** "]

hserout ["Destination ",dec Azimuth_Destination," if cloudy then hserout ["cloudy"] if focus Then hserout ["focus"] if stow then hserout ["stow ",bin8 stow] if dark then hserout ["dark"]

if cloudy = no and focus = no and stow = no and dark = no then hserout ["sunny"] HSEROUT [" **"] hserout [10,13,10,"Left Right Up Down Cloud Sun Exit "]

' decNum = (bcdNum.NIB1 * 10) + bcdNum.NIB0 decimal value.

converts hex byte used for clock display into

' bcdNum = (decNum / 10 > 4)*10 + (minute & $F) + 1 ' Convert test clock minute increments to decimal IF CLICK = 60 THEN CLICK = 0

HOUR = ((hour >> 4)*10 + (hour & $F)) minute carryover. HOUR = HOUR + 1

' Convert test clock hour to decimal and increment for 60

HOUR = ((HOUR / 10) 680 OR work4 < 320 OR work4 > 680 THEN STOW.0 = 1 Altitude_Stow = yes ENDIF ' Azimuth sensor failure tag ###########

xRaw = work3 MAX 373 MIN 627 xRaw = xRaw - 500 yRaw = work4 MAX 373 MIN 627

yRaw = yRaw - 500 Azimuth_sensor = xRaw ATN yRaw ' Arctangent

work3 = 0 work4 = 0

'Altitude sensor 'Altitude sensor

FOR smooth = 1 TO 32 PULSIN altsensor_a, HiPulse, xRaw work3 = work3 + xRaw PULSIN altsensor_b, HiPulse, yRaw work4 = work4 + yRaw NEXT smooth

work3 = work3 / 32 work4 = work4 / 32

IF work3 < 320 OR work3 > 680 OR work4 < 320 OR work4 > 680 THEN STOW.1 = 1 Azimuth_Stow = yes ENDIF ' Altitude sensor failure tag ###########

xRaw = work3 MAX 373 MIN 627 xRaw = xRaw - 500 yRaw = work4 MAX 373 MIN 627 yRaw = yRaw - 500

Altitude_sensor = xRaw ATN yRaw ' Arctangent

return

TESTED: IF SPEEDAZ AND AZIMUTH_COMMAND = LEFT THEN Azimuth_sensor = Azimuth_sensor - 1 Increment test sensor if motor is on. IF SPEEDAZ AND AZIMUTH_COMMAND = RIGHT THEN Azimuth_sensor = Azimuth_sensor + 1 IF SPEEDALT AND Altitude_COMMAND = DOWN THEN Altitude_sensor = Altitude_sensor - 1 IF SPEEDALT AND Altitude_COMMAND = UP THEN Altitude_sensor = Altitude_sensor + 1 return '

'********************* Get_Time:

'I2Cread datapin, clockpin, $d1, 0, [sec,minute,hour,day,date,month,year]

if display then hserout [hex2 month," / ",hex2 date," / 20",hex2 year," ",hex hour,":",hex2 minute,":",hex2 sec]

' Hex decimal numbers for clock display, must be converted to decimal to be useful.

second = (sec >> 4)*10 + (sec & $F)

' second = (sec.HIGHNIB*10+sec.LOWNIB)

time = ((hour >> 4)*10 + (hour & $F))*60 + (minute >> 4)*10 + (minute & $F) ' Number of minutes since midnight.

days = (((month >> 4)*10 + (month & $F) - 1) * 305/10 + (date >> 4)*10 + (date & $F)) min 365 ' Number of days since January 1

if display then hserout [" TIME = ",dec time,13,10,10] pause 10 endif

If time = old_time and second = previous_second then stow.2 = 1 Azimuth_Stow = no Altitude_Stow = yes ENDIF ' Time failure tag ###########

previous_second = second

' For checking clock ticking

return

'********************* Get_Declination:

work = 284 + days

' D=23.45 degrees*sin(360 degrees*(284+N)/365)= Declination

IF work > 365 THEN work = work - 365 ' Fraction of circle less than 1 work = work ** 45965 work = SIN work signa = work.BIT15 ' 256 brads = 360 degrees 256/365 * 65536 = 45965 ' If work.bit15 = 1 then SIN (work) is negative ' d = ABS work * 16.675 / 127

work = ((ABS work */ 4269)+64) / 127 ' 23.45/360*256=16.675 16.675*256=4269 +64 round up 0.5 IF signa THEN work = 256 - work declination = work return ' If negative then declination is below equinox 256 (0)

' Declination byte in brads used in Path routines.

'********************* Get_flags_north: ' Looks at every minute of today's date and calculates arctangent of azimuth. The are two answers so to ' determine which is correct ~ the difference between both is measured minute by minute and the crossover ' is assumed to be near the minimum distance between both answers (occurs East and West). The clock times of these ' twice daily occurances are recorded in variables AM and PM. The sun does not crossover to the north between ' fall equinox and spring equinox for all locations. The sun does crossover to the south for tropic ' locations when the solar declination is equal or greater than site latitude. ' OSCCON = %01110000 ' Speed up micro to 8 MHz to crunch these numbers.

sound spkr,[100,83]

signb = 1

' Flags sunrise calculation finished. ' Variables to hold gap between two arctangent solutions .

AMX = 127:PMX = 127

FOR time = 120 TO 1320 STEP 1 ' For 2:00 AM to 10:00 PM. GOSUB get_PATH ' Solar position algorithm accepts time and declination. Returns two azimuths and one altitude.

if signb and altitude_path < 20 then

' Sunrise likely zero but definitely not 255 just below horizon.

dawn = due_north + (Azimuth_Path */ z) ' Azimuth location at sunrise. signb = 0 endif ' Do dawn just once when altitude path is 0, or almost 0.

wb = Azimuth_Path - prior prior. wb = ABS(wb) IF time < 720 THEN IF AMX > wb THEN AMX = wb AM = TIME ENDIF ELSE IF PMX > wb THEN PMX = wb PM = TIME ENDIF ' PM

' The two arctangent answers are held in Azimuth_Path and

' AM

ENDIF NEXT TIME ' Next minute

OSCCON = %01100000 sound spkr,[ 100,83 ] return

' Slow down micro to 4 MHz, numbers are crunched.

'********************* Get_Eyes: ' Low numbers mean bright eyes.

IF dark THEN RETURN

GOTO TESTING '! Skip eyes for desk top emulation

north = 0 south = 0 east = 0 west = 0

FOR Smooth = 0 TO 7

HIGH alteye_a

PAUSE 1

' Charge eye capacitor. ' Time to discharge capacitor through photoresistor eye. ' Timeout after 5000 count, 50000us or 50ms.

RCTIME alteye_a, 1, work IF work = 0 THEN work = 5000

north = north + (work * 13 / 8) ' 13 = 10.us/0.75us = PIC/BS2p 8 = smooth loop count.

HIGH alteye_b PAUSE 1 RCTIME alteye_b, 1, work IF work = 0 THEN work = 5000 south = south + (work * 13 / 8)

HIGH azeye_a PAUSE 1 RCTIME azeye_a, 1, work IF work = 0 THEN work = 5000 east = east + (work * 13 / 8)

HIGH azeye_b PAUSE 1 RCTIME azeye_b, 1, work IF work = 0 THEN work = 5000 west = west + (work * 13 / 8)

NEXT smooth

goto blink

TESTING:

if tEST ="L" THEN EAST = EAST - 25 WEST = WEST + 25 ENDIF

if TEST ="R" THEN EAST = EAST + 25 WEST = WEST - 25 ENDIF

IF TEST = "U" THEN NORTH = NORTH - 25 SOUTH = SOUTH + 25 ENDIF

IF TEST = "D" THEN NORTH = NORTH + 25 SOUTH = SOUTH - 25 ENDIF

IF TEST = "C" THEN

NORTH = NORTH + 100 SOUTH = SOUTH + 100 EAST = EAST + 100 WEST = WEST + 100 ENDIF

IF TEST = "S" THEN NORTH = NORTH - 100 SOUTH = SOUTH - 100 EAST = EAST - 100 WEST = WEST - 100 ENDIF

Blink: if display then hserout [13,10] hserout ["Eye hserout ["Eye HSEROUT [" hserout [" endif if FIX = 0 then return ' No eye motor command if called from Set_Clock left ",dec east," right ",dec west," down ",dec south,13,10] up ",dec north,13,10]

---------------------------",13,10] ",sdec (east - west)," ",sdec (south - north),13,10,10]

IF north < Too_Bright OR south < Too_Bright OR east < Too_Bright OR west < Too_Bright THEN stow.5 = 1 ' Eye failure tag ###########

Altitude_Stow = yes Azimuth_Stow = yes ENDIF ' If one side of both eyes see sun or both sides of both eyes see sun2 then it must be sunny. IF (west < sun OR east < sun OR (west azimuth_sensor AND azimuth_command = left) OR (azimuth_path_sense < azimuth_sensor AND azimuth_command = right) THEN stow.6 = 1 altitude_stow = yes RETURN eNDIF ENDIF skip_for_emulation: ' Skip above if interfers with testing code by sending sun to illogical positions. ' Azimuth eye/sensor/clock error. Check all three. ###########

IF Focus THEN

if altitude_sensor - k > 60 and altitude_sensor - k < 68 then sun_overhead = yes directly overhead goto skip_solar_noon latitude. endif ' Azimuth position not accurate nor needed when sun is

' in the tropics a few days per year when declination =

IF solar_noon and (Azimuth_sensor = due_south or Azimuth_sensor = due_north) THEN ' If focused on sun directly south or north

IF ABS(Time - 720) > 40 THEN stow = $0F

' Then if clock is not within 40 minutes

' Solar_noon clock/position error. ########### ' Then clock or eye or sensor do not agree -

altitude_stow = yes stow. return ENDIF

I2Cwrite datapin, clockpin, $D0, 1, [$00, $12]: Time = 720 clock reset.

' Long term autonomy solar noon

solar_noon = 0 write_flag = 1 ENDIF skip_solar_noon:

' Only write one solar noon per day ' Enable memory write of Focus location.

IF write_flag THEN minutes.

' Write Focus dish position and solar declination once every 4

' Overwites older data if tracking bright sun. if time < 120 or time > 1317 then return ' Memory space 2 AM to 10 PM

Pointer = ((Time / 4 ) - 30) * 3

' EEPROM DATA locations 0 to 899

WRITE pointer, Azimuth_sensor, Altitude_sensor, declination write_flag = 0 if display then hserout [7] ENDIF ENDIF return ' Beep computer indicating EEPROM data write

'********************* Get_Memory:

if read_flag then return

' Read memory only once every four minutes.

dat1 = 0 dat2 = 0 read_flag = 1

Pointer = ((Time / 4 ) - 30) * 3 if pointer > 897 then no_memory

' Time 120 to 1317 converted to pointer 0 to 897 ' time = 120 to 1317 memory space 2 AM to 10 PM

READ pointer, Azimuth_Memory, Altitude_Memory, old_declination ' Read prior day focus position data at current time.

wb = old_declination - declination and current solar declination.

' Find distance between prior day solar declination

IF ABS WB > drift or Altitude_Memory = $FF THEN Search_back ' If declination difference is greater than the constant drift then look at times before and after current time. GOTO Remember ' Else memory satisfied.

Search_back:

dat1 = dat1 + 1 IF dat1 > Search THEN no_memory ' If searched too far back then no memory.

Pointer = ((Time / 4 ) - 30) * 3 - (3 * DAT1) if pointer > 897 then no_memory

' Pointer 0 to 897 ' Memory space 2 AM to 10 PM.

READ pointer, AzPast, AltPast, old_declination time.

' Read prior day focus position data at earlier

wb = old_declination - declination IF ABS WB > drift or altpast = $FF THEN Search_back ' If data too old then search further back.

Search_forward:

dat2 = dat2 + 1 IF dat2 > Search THEN no_memory ' If searched too far forward then no memory.

Pointer = ((Time / 4 ) - 30) * 3 + (3 * DAT2) if pointer > 897 then no_memory

' Pointer 0 to 897 ' Memory space 2 AM to 10 PM.

READ pointer, AzFuture, AltFuture, old_declination time.

' Read prior day focus position data at later

wb = old_declination - declination IF ABS WB > drift or altfuture = $FF THEN Search_forward forward. ' If data too old then search further

WB = azFuture - azPast Azimuth_Memory = (ABS WB * dat1)/(dat1+dat2) between WB = altFuture - altPast Altitude_Memory = (ABS WB * dat1)/(dat1+dat2) ' earlier and later sun memory data. ' Calculate scale and offset to dead reckon

IF azPast > azFuture THEN Azimuth_Memory = azPast - Azimuth_Memory ELSE Azimuth_Memory = azPast + Azimuth_Memory ENDIF IF altPast > altFuture THEN Altitude_Memory = altPast - Altitude_Memory ELSE

Altitude_Memory = altPast + Altitude_Memory ENDIF

GOTO Remember

no_memory: Azimuth_Memory = 0 Altitude_Memory = 0

Remember: if display then Pointer = ((Time / 4 )-30)*3 + (3 * DAT1) read pointer,wb,wb,old_declination endif return ' To display age via declination of old data.

'********************* Get_Path:

' N=days H=+/-hours*15 degrees

Day of year Hours from solar noon

' D=23.45 degrees*sin(360*(284+N)/365 Declination ' ALT=arcsin(sinL*sinD+cosL*cosD*cosH)

' AZ=arcsin(cosD*sinH/cosALT)

h = (time ** 11650) - 128 WORK1 = SIN Latitude work = SIN declination SIGNA = WORK1.15 ^ WORK.15

' 0.17777 brads per minute*65536=11650

' If one or the other but not both negative ' alt = ((SIN Latitude) * ABS(SIN declination)) / 127

alt = (ABS WORK1 * ABS WORK) / 127 IF SIGNA THEN ALT = -ALT work = COS h signA = work.BIT15

' then negate result.

' If cos (h) negative

work = (ABS WORK) * (COS declination) / 127 * (COS Latitude) / 127 ' COS declination and COS Latitude always positive. IF signA THEN work = -work alt = (alt + work) work1 = (alt * alt) MIN 16129 Hypotenuse squared 16129. work = SQR(16129 - work1) Angle = Arctangent Sine/Cosine Altitude_Path = work ATN alt work = COS Altitude_Path az = ((COS declination) * (SIN h)) signA = work.BIT15 ^ az.BIT15 az = (ABS az / ABS work) MIN 127 work1 = az*az IF signA THEN az = -az work = SQR(16129 - work1) ' then negate result. ' X = SQR ( H * H - Y * Y ) ' Altitude brad angle = arctangent (Y/X) X ATN Y ' If one or the other but not both negative ' There is no arcsine. Brad circles are 256 units. The radius 127. The ' then negate result.

' X = SQR ( H * H - Y * Y ) same as Cosine = ( 16129 - Sine * Sine ).

' Altitude brad angle = arctangent (Y/X) X ATN Y

Azimuth_Path = (work ATN az) + 128

prior = (-work ATN az) + 128 ' X=SQR(H*H-Y*Y) has two solutions X and -X. 'prior' holds the second solution. The program flags the correct solution. return

'********************* Set_Motors:

IF sw1 = 0 AND sw2 = 0 THEN azimuth_go = no altitude_go = no ENDIF

' If both switches flipped then ' stop azimuth motor ' stop altitude motor.

IF sw1 = 1 AND sw2 = 0 THEN altitude_go = yes altitude_command = up azimuth_go = no ENDIF

' If one switch flipped then altitude up and on.

' Azimuth motor off.

IF sw1 = 0 AND sw2 = 1 THEN altitude_go = yes altitude_command = down azimuth_go = no ENDIF

' If the other switch flipped then altitude down and on.

' Azimuth motor off.

Motor_Switch_Bypass:

' Use when keyboard controls motors.

if azimuth_sensor = maxxy and azimuth_command = right then azimuth_go = no right switch.

' Limit azimuth left

' Limit azimuth

IF azimuth_on = yes AND (azimuth_command azimuth_spin or azimuth_go = no) THEN ' Stop before reverse.

do wb = speedaz speedaz = wb - 4

' reduce speed to zero in less than a second

' Slow azimuth

if speedaz > wb then speedaz = 0 255 then azimuth speed = 0

' If azimuth speed crosses over from 0 to

hpwm 1, SPEEDAZ, freq pause 16 loop until speedaz = 0

' Set PMW to HBridge

' Exit when motor speed is zero

low azmotor_a pause 1 low azmotor_b azimuth_on = no pause 16

' Brake azimuth motor

'Motor1_sleep_pin endif

' Sleep HBridge motor1 to save power

IF altitude_on = yes AND (altitude_command altitude_spin or altitude_go = no) THEN ' Stop before reverse.

do wb = speedalt speedalt = wb - 4

' Reduce speed to zero in less than a second.

' Slow altitude.

if speedalt > wb then speedalt = 0 255 then altitude speed = 0

' If altitude speed crosses over from 0 to

'hpwm 2,speedalt, freq pause 16 loop until speedalt = 0

' Set PMW to HBridge

' Exit when motor speed is zero

low altmotor_a pause 1 low altmotor_b altitude_on = no pause 16 'Motor2_sleep_pin endif

' Brake altitude

' Sleep HBridge motor1 to save power

Azimuth: if speedaz = maxaz or azimuth_go = no then altitude Azimuth motor off then no need to change speed. if speedaz = 0 then speedaz = startaz wb = speedaz + rampaz ' If maximum Azimuth speed or

' If zero speed then starting speed ' Increment flag speed.

if wb > maxaz or wb < speedaz then speed crossed over from 255 to 0 speedaz = maxaz else speedaz = wb endif

' If flag speed > maximum speed or flag

' then set speed to maximum speed ' else increment speed to flag speed.

if azimuth_on azimuth_go then direction first. if azimuth_command = right then high azmotor_a previous brake if azimuth_command = left then high azmotor_b pause 1 'Motor1_sleep_pin off pause 1 endif hpwm 1, SPEEDAZ, freq 'set pwm

' If off and and need to go on then set

' Both A and B were off from

' Wakeup azimuth motor.

' Set azimuth speed.

Altitude: if speedAlt = maxAlt or Altitude_go = no then good Altitude motor off then no need to change speed. if speedAlt = 0 then speedAlt = startAlt wb = speedAlt + rampAlt ' If maximum Altitude speed or

' If zero speed then starting speed ' Increment flag speed.

if wb > maxAlt or wb < speedAlt then speed crossed over from 255 to 0 speedAlt = maxAlt else speedAlt = wb endif if altitude_on altitude_go then direction first. if altitude_command = up then high altmotor_a previous brake if altitude_command = down then high altmotor_b pause 1 'Motor2_sleep_pin off pause 1 endif 'hpwm 2,speedalt, freq 'set pwm

' If flag speed > maximum speed or flag

' then set speed to maximum speed ' else increment speed to flag speed.

' If off and and need to go on then set

' Both A and B were off from

' Set altitude speed

' Set azimuth speed.

good:

IF azimuth_go AND azimuth_on = no THEN Azimuth_Motor = 1

' If azimuth motor goes from off to on then

' start counting azimuth motor on time

Azimuth_Move = Azimuth_sensor ENDIF

' store current azimuth location.

IF azimuth_go = no THEN Azimuth_Motor = 0

' If azimuth motor off then stop counting on time.

IF altitude_go AND altitude_on = no THEN Altitude_Motor = 1 Altitude_Move = Altitude_sensor ENDIF

' If altitude motor goes from off to on then

' start counting altitude motor on time ' store current altitude location.

IF altitude_go = no THEN Altitude_Motor = 0

' If altitude motor off then stop counting on time.

azimuth_on = azimuth_go azimuth_spin = azimuth_command altitude_on = altitude_go altitude_spin = altitude_command

' Motors followed commands. ' Motors status now reflect those commands.

if display then hserout [10,13,"Motors "] if azimuth_on then if azimuth_spin = left then hserout [ " left -"] else hserout [" right "] endif

else hserout [" endif hserout [dec speedaz] "]

if altitude_on then if altitude_spin = down then hserout [" else hserout [" endif else hserout [" endif hserout [dec speedalt,10,13] hserout [10,13] "] up "] down -"]

endif return

'********************* Set_Clock: noon time. ' Set clock to standard time. Bright sun solar tracking will update clock to solar

FIX = 0 TEST = 0 display = 1

' Stop eyes from controlling motors. ' Clear menu choice. ' Enable serial port

azimuth_go = no altitude_go = no

' Stop azimuth motor ' Stop altitude motor ' Stop switches from controlling motors

GOSUB Motor_Switch_Bypass

KEYPAD:

hserout [12] gosub get_time hserout [10,13] hserout [ " Clock set ",10,13 ] hserout [ " Drive motors and read sensors ",10,13 ] hserout [ " Read or erase memory ",13,10] hserout [ " Install limits ",13,10] HSEROUT [ " Exit and Run ",13,10,10 ]

hserin [wb]

hserout [12] if wb = "C" then Clock_set

IF WB = "D" THEN Drive if wb = "R" then Read_Write if wb = "I" then Install IF WB = "E" THEN TOP

WB = 0 GOTO KEYPAD

Clock_set: HSEROUT [12] GOSUB GET_TIME

hserout [ "0 second ",hex sec,13,10] hserout [ "1 minute ",hex minute,13,10] hserout [ "2 hour ",hex hour,13,10] hserout [ "3 day ",hex day,13,10] hserout [ "4 date ",hex date,13,10] hserout [ "5 month ",hex month,13,10] hserout [ "6 year ",hex year,13,10] hserout [ "7 reset ",13,10] hserout [ "8 exit ",13,10] hserin [dec1 wb]

IF wb = 7 THEN reset if wb > 7 then keypad

hserout [10,13,DEC wb," value? "] hserin [hex2 wb1] HSEROUT [13,10,10]

I2Cwrite datapin, clockpin, $d0, wb, [wb1] goto clock_set

' Set Clock

RESET: FOR smooth = 7 TO 0 ' Clear Clock DS1307 clock reset and start crystal ' Run when backup battery replacement

I2Cwrite datapin, clockpin, $d0, smooth, [0] NEXT

GOTO clock_set

Drive: HSEROUT [12] GOSUB GET_SENSORS GOSUB GET_TIME hserout [13,10," Azimuth Altitude",10,13,10]

GOSUB GET_EYES

hserout ["Sensor

",dec Azimuth_sensor,

"

",dec Altitude_sensor,10,13]

GOSUB Motor_Switch_Bypass HSEROUT [13,10] hserout ["Left Right XYstop Up Down Zstop",13,10,10] HSEROUT ["Exit"] hserin [wb]

if wb = "E" then set_clock

if wb = "L" then azimuth_command = left azimuth_go = yes endif

if wb = "R" then azimuth_command = right azimuth_go = yes endif

if wb = "X" then azimuth_go = no

if wb = "U" then altitude_command = up altitude_go = yes endif

if wb = "D" then altitude_command = DOWN altitude_go = yes endif

if wb = "Z" then altitude_go = no

goto drive

Read_Write: ' EEPROM DATA locations: 0 to 899 tracking memory, 900 to 999 stow data, 1000 to 1016 sensor calibration, 1017 to 1024 available.

HSErout [13,10,"Read Write Exit",13,10,10] hserin [wb] if wb = "E" then keypad if wb = "R" then reads if wb = "W" then writes goto read_write

Reads: hserout [10,13,10," end? = 0 to see Stow data",13,10] hserout [10,13,"begin? "] hserin [dec work1]: if work1 > 899 then work1 = 899 hserout [10,13," end? "]

hserin [dec work2]: if work2 = 0 then stow_data if work2 > 899 then work2 = 899 WORK1 = WORK1/3*3 hserout [10,13,dec work1," to ",dec work2,10,13]

FOR POINTER = WORK1 TO WORK2 STEP 3 READ POINTER, WB,WB1,WB2 READ pointer, Azimuth_Memory, Altitude_Memory, old_declination WORK4 = (POINTER / 3 + 30) * 4 WB1 = (Azimuth_Memory - DUE_NORTH) */ f WB2 = ALTITUDE_Memory - K ' Converts memory location to time value. ' Converts azimuth sensor data to brads. ' Converts altitude sensor data to brads.

Hserout [dec pointer,32,dec work4," ",dec Azimuth_Memory," ",dec Altitude_Memory," ",DEC old_declination," ", DEC WB1," ",DEC WB2,13,10] next pointer hserout ["pointer Sensor hserout ["ptr time az alt Dec Brad",13,10] az alt",13,10]

goto read_write

stow_data HSEROUT [12] for pointer = 900 to 996 step 4 read pointer, wb, stow, Azimuth_sensor, Altitude_sensor IF WB = $FF THEN NXT WB1 = (Azimuth_SENSOR - DUE_NORTH) */ f ' WB is stow time/10.

' No print if altitude blank with $FF ' Converts azimuth sensor data to brads.

WB2 = ALTITUDE_SENSOR - K

' Converts altitude sensor data to brads.

hserout [dec pointer,32,dec4 wb*10,32,32,bin8 stow," ", DEC Azimuth_sensor,32, DEC Altitude_sensor," "] hserout [DEC WB1,32,DEC WB2,13,10] NXT: next pointer hserout [10,13,"pointer tag hserout ["ptr time stow Sensor Brad",13,10]

az alt

az alt",13,10,10]

hserout [ "00000001 Azimuth Sensor",13,10] hserout [ "00000010 Altitude Sensor",13,10] hserout [ "00000100 Clock time",13,10] hserout [ "00001000 Azimuth Motor",13,10] hserout [ "00010000 Altitude Motor",13,10] hserout [ "00100000 Eyes",13,10] hserout [ "01000000 Azimuth sensor/eye/time",13,10] hserout [ "10000000 Altitude sensor/eye/time",13,10] hserout [ "00001111 Solar noon Clock",13,10] hserout [ "11110000 Water pressure",13,10] hserout [ "11111111 Wind",13,10]

goto read_write

Writes:

' Clears EEPROM segment and writes $FF

hserout [10,13,"begin? "] hserin [dec work1]:

if work1 > 999 then work1 = 999 hserout [10,13," end? "] hserin [dec work2]: if work2 > 999 then work2 = 999 hserout [10,13,dec work1," to ",dec work2,10,13," Yes? "] hserin [wb] if wb "Y" then goto read_write wb = $FF FOR POINTER = WORK1 TO WORK2 write pointer,wb hserout [7] HSEROUT [DEC POINTER,32] next pointer goto read_write ' Beep computer indicating EEPROM data write

Install: read 1000, WORD lat, due_north, due_south, due_up, minxy, maxxy, minz, maxz, dummy, azmotor, altmotor, azsensor, altsensor, azeye, alteye

HSEROUT [12] HSEROUT [" Latitude degrees times 10",10,13," Example: Seattle = 475",13,10," Other values are dish sensor data",13,10,10] ' Negative Latitude below equator. HSEROUT ["0 Latitude ",Sdec lat,13,10] HSEROUT ["2 Due North ",dec due_north,13,10] HSEROUT ["3 Due South ",dec due_south,13,10] ' Use Polaris star to find true north.

HSEROUT ["4 Due Up

",dec due_up,13,10]

HSEROUT ["5 Minimum XY ",dec minxy,13,10] HSEROUT ["6 Maximum XY ",dec maxxy,13,10] HSEROUT ["7 Minumum Z ",dec minz ,13,10] HSEROUT ["8 Maximum Z ",dec maxz ,13,10] HSEROUT ["9 Exit ",13,10] HSEROUT [10," Reverse direction 1 or 0", 13,10,10] HSEROUT ["A Azimuth Motor ",DEC AZMOTOR, 13,10] HSEROUT ["B Altitude Motor ",DEC ALTMOTOR, 13,10] HSEROUT ["C Azimuth Sensor ",DEC AZSENSOR, 13,10] HSEROUT ["D Altitude Sensor ",DEC ALTSENSOR,13,10] hserout ["E Azimuth Eye ",dec azeye,13,10]

hserout ["F Altitude Eye ",Dec alteye,13,10]

hserin [hex1 wb]

IF WB > $0F THEN INSTALL HSEROUT [ 10,13,10,hex WB," = "] if wb = 9 then keypad IF WB = 1 THEN INSTALL

hserin [dec3 work] wb1 = work

if wb = 0 then

write 1000, word work else write 1000 + wb, wb1 ' Write to EEPROM install values. endif hserout [7] ' Beep computer indicating EEPROM data write

goto install

goto ending