Example code (compatible with LAB X1).
' DUAL-AXIS SOLAR TRACKING
'
' Version 7/16/2011
'
' Current version http://www.harbornet.com/sunflower/pvdish.html
' Serial port with notebook computer.
'************************************************* ***************
'* Name : sunrun.pbp *
'* Author : Sunflower *
'* Notice : Copyright (c) 2011 Sunflower *
'* : All Rights Reserved *
'* Date : 6/08/2011 *
'* Version : 1.0 *
'* Notes : 18F4620 PICmicro *
'* : *
'************************************************* ***************
' Objective: To point solar dish approximately at sun for safety when sun is not visible, and exactly at sun when sun is visible.
' Compiles with PIC BASIC PRO sold by melabs.com
' 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 "18F4620.INC" ; MPASM Header
' __CONFIG _CONFIG1H, _OSC_INTIO67_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
' Tiny PIC Bootloader = http://www.etc.ugal.ro/cchiculita/so...bootloader.htm
' Tiny modifications tinybld18F4620_zigbee.asm for bootloading with internal oscillator
'
' xtal EQU 4000000 ; set for 4 mhz you may want to change: _XT_OSC_1H _HS_OSC_1H _HSPLL_OSC_1H
' baud EQU 9600 ; the desired baud rate
'
' __CONFIG _CONFIG1H, _OSC_INTIO67_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
' __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_512_2H
' __CONFIG _CONFIG3H, _MCLRE_ON_3H & _PBADEN_OFF_3H ; & _CCP2MX_PORTBE_3H ; NOTE CCP2MX_PORTBE_3H COMMENT OUT
' movwf RCSTA
' (added after movwf RCSTA)
' movlw b'01100000' ;ADDED to set osccon to 4mhz internal
' movwf OSCCON
'
' http://www.picbasic.co.uk/forum/showthread.php?t=14434&
'
'
' Default Re: Port Variables act like Constants
'
'
' *** MUST DO THIS ***
'
' The PORTL and PORTH aliases are used for the PIN numbers (0-15)
' PORTL is 0-7 and PORTH is 8-15.
' Look in the .bas file for the chip you are using.
' If it's a 18F4620 then open c:\pbp\18F4620.bas
' PORTL VAR PORTB
' PORTH VAR PORTD
' TRISL VAR TRISB
' TRISH VAR TRISD
'
' PORTB AND PORTD can now be referenced by variables.
' http://www.picbasic.co.uk/forum/showthread.php?t=14493&
'
'
' Olimex PIC-P40 carrier board http://www.olimex.com/dev/pic-p40.html
' Connect CTS with RTS on MX232.
'
' Dual MC33926 Motor Driver HBridge http://www.pololu.com/catalog/product/1213
' Ground M1 PWM/D1 and ground M2 PWM/D1
'
' Physical pin connections: (all motor connections via HBridge)
'
' 1 - Push button ground to reset
' 2 - LED on carrier board
' 3 - 230 ohm resistor ~ Wind sensor + 0.1mf capacitor
' 10 - Olimex push button on board pulled high 10k
' 15 - Enable motors (EN)
' 16 - Altitude pwm (M2 PWM/D2)
' 17 - Azimuth pwm (M1 PWM/D2)
' 18 - DS1307 clock (I2C SCL pin), pull up 4.7k
' 19 - Azimuth motor (M1 IN1)
' 20 - Azimuth motor (M1 IN2)
' 21 - Altitude motor (M2 IN1)
' 22 - Altitude motor (M2 IN2)
' 23 - DS1307 clock (I2C SDA pin), pull up 4.7k
' 24 - Extra I/O pin
' 25 - Connect to MX232 RX
' 26 - Connect to MX232 TX
' 27 - 230 ohm resistor ~ then photoresistor parallel with 1mf capacitor to ground (azimuth)
' 28 - 230 ohm resistor ~ then photoresistor parallel with 1mf capacitor to ground (azimuth)
' 29 - 230 ohm resistor ~ then photoresistor parallel with 1mf capacitor to ground (altitude)
' 30 - 230 ohm resistor ~ then photoresistor parallel with 1mf capacitor to ground (altitude)
' 33 - Memsic 2125 accelerometer (azimuth)
' 34 - Memsic 2125 accelerometer (azimuth)
' 35 - Switch 2, pull up 10,000k
' 36 - Memsic 2125 accelerometer (altitude)
' 37 - Memsic 2125 accelerometer (altitude)
' 38 - Switch 1, pull up 10,000k
'
' Memsic 2125 accelerometers are installed on edge, like a rolling coin. The spin around the vertical post is translated to a
' horizontal axis containing the azimuth accelerometer (a cable wrapped around the post and around the horizontal drum).
'
' The 4 photoresistors should be +/- 20% of averaged value. The eye is constructed with a glass ball with the focus over a razor-like divider
' separating two sensors for each eye. One eye is for azimuth and the other eye is for altitude. Tracking sensitivity is < +/-0.004 degrees.
Code:
DEFINE LOADER_USED 1 ' Bootloader space
DEFINE OSC 4 ' Tell program 4 MHz timing
DEFINE PULSIN_MAX 1000 ' TIMEOUT LIMIT FOR RCTIME and PULSIN COUNT 10us units @ 4MHz 10ms timeout
define HSER_CLROERR ' Automatic clear communications error
ADCON1 = %00001111 ' Make AN0-AN12 digital
OSCCON = %01100000 ' Internal oscillator speed 4 MHz
WDTCON = 1 ' Enable watchdog
LED VAR PORTA.0
Wind_pin var PORTA.1 ' Wind sensor grounds charged capacitor at 25 mph.
' 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
sw1 var PORTB.2 'Switch1
' PORTB.3 Altitude Sensor A/B = 3 ' Rotate Y2 Accelerometer MEMSIC 2125
' PORTB.4 Altitude Sensor A/B = 4 ' Rotate X2 Accelerometer MEMSIC 2125
sw2 var PORTB.5 'Switch2 (Also programming pin LVP, disabled in configuration fuses)
' PORTB.6 Programming Pin
' PORTB.7 Programming Pin
'
Warm var PORTC.0 ' Motors HBridge enable/sleep, one enable for both motors.
' PORTC.1 HPWM channel 2 altitude motor speed
' PORTC.2 HPWM channel 1 azimuth motor speed
ClockPin var PORTC.3 ' I2C SCL ' I2C
DataPin var PORTC.4 ' I2C SDA ' I2C - DS1307 clock
' PORTC.5 Extra wire or second motor enable
' 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 ' RC Time photoresister parallel with 1 mf capacitor.
' PORTD.5 Azimuth Eye A/B = 13 ' RC Time photoresister parallel with 1 mf capacitor.
' PORTD.6 Altitude Eye A/B = 14 ' RC Time photoresister parallel with 1 mf capacitor.
' PORTD.7 Altitude Eye A/B = 15 ' RC Time photoresister parallel with 1 mf capacitor.
time VAR Word ' 1440 minutes per day
old_time var word ' Previous minute
days var word ' Number of days
declination VAR Byte ' +/- 17 Brads (+/- 24 degrees)
old_declination VAR BYTE ' Declination used as time stamp of old memory.
azMotor var byte ' For controlling forward/reverse pin assignments after istallation.
altMotor var byte ' Software rewires motors and sensors by optionally swapping A with B.
azSensor var byte
altSensor var byte
azEye var byte
altEye var byte
azMotor_A var byte
azMotor_B var byte
altMotor_A var byte
altMotor_B var byte
azSensor_A var byte
azSensor_B var byte
altSensor_A var byte
altSensor_B var byte
azEye_A var byte
azEye_B var byte
altEye_A var byte
altEye_B var byte
flag VAR word
SIGNa VAR FLAG.0
SIGNb VAR FLAG.1
solar_noon var flag.2
Azimuth_Stow var flag.3
Altitude_Stow var flag.4
flag_north var flag.5
display var flag.6
reboot var flag.7
azimuth_command VAR FLAG.8
altitude_command VAR FLAG.9
azimuth_go VAR FLAG.10
altitude_go VAR FLAG.11
azimuth_spin VAR FLAG.12
altitude_spin VAR FLAG.13
azimuth_on VAR FLAG.14
altitude_on VAR FLAG.15
flag2 var word
sun_overhead VAR flag2.0
cloudy VAR flag2.1
Focus VAR flag2.2
read_flag VAR flag2.3
write_flag VAR flag2.4
tropic_summer VAR flag2.5
dark VAR flag2.6
stow_write VAR flag2.7
MoreBits var byte
Fix var MoreBits.0
No_Stow var morebits.1
Down_Limit var morebits.2
Up_Limit var morebits.3
Flag_overhead var morebits.4
Time_overhead var word
test var byte ' Menu character
click var word ' Test clock
pointer VAR word
second var byte
previous_second var byte
smooth var byte
k var byte ' Scale constant derived from sensor installation
z var word ' Scale constant derived from sensor installation
f var word ' Scale constant derived from sensor installation
Azimuth_Memory VAR BYTE
Altitude_Memory VAR BYTE
Azimuth_sensor VAR Byte
Altitude_sensor VAR Byte
Azimuth_Path VAR BYTE ' Brads from solar position algorithm
Altitude_Path VAR BYTE ' Brads from solar position algorithm
Azimuth_Path_sense VAR BYTE
Altitude_Path_sense VAR BYTE
Azimuth_Destination VAR BYTE
Altitude_Destination VAR BYTE
dawn var byte ' Azimuth sensor location of calculated sunrise
AM VAR word ' Time that sun crosses from north to south
PM VAR 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 var byte ' Azimuth sensor value of Polaris star.
due_south var byte ' Azimuth sensor value of due south
due_up var byte ' Altitude sensor value straight up
minXY var byte ' Before due north in the west if in tropics.
maxXY var byte ' After due south in the northwest
minZ var byte ' Limit switch down
maxZ var byte ' Limit switch up
stow var byte ' Reason(s) for stow
Dwell VAR byte ' Wait after eye tracking before memory tracking
Azimuth_Motor VAR byte ' Number of minutes motor is on without detectable movement.
Altitude_Motor VAR byte ' Number of minutes motor is on without detectable movement.
Azimuth_Move VAR byte ' Last location of moving motor
Altitude_Move VAR byte ' Last location of moving motor
SpeedAz var byte ' Motor speed ~ duty cycle of PWM
SpeedAlt var byte ' Motor speed ~ duty cycle of PWM
work VAR Word
work1 VAR Word
work2 VAR Word
work3 VAR Word
work4 VAR Word
work5 VAR Word
work6 VAR WORD
work7 VAR WORD
work8 var word
WorkByte var byte
WB VAR BYTE
WB1 VAR BYTE
WB2 VAR BYTE
dummy var byte
lat var word ' Work variables for solar path algorithm
alt VAR word
az VAR word
h VAR BYTE
prior VAR BYTE
AMx VAR BYTE
PMx VAR BYTE
sec VAR BYTE ' Time variables
minute VAR BYTE
hour VAR BYTE
day VAR BYTE
date VAR BYTE
month VAR BYTE
year VAR BYTE
north VAR WORD 'Up Eye variables
south VAR WORD 'Down
east VAR WORD 'Left
west VAR WORD 'Right
xRaw VAR word ' Accelerometer data
yRaw VAR word ' Accelerometer data
dat2 VAR BYTE ' Memory dead reckoning variables.
dat1 VAR BYTE
azPast VAR BYTE
altPast VAR BYTE
azFuture VAR BYTE
altFuture VAR BYTE
yes con 1 ' English
no con 0
up CON 1
down CON 0
right CON 1
left CON 0
HiPulse CON 1
LoPulse CON 0
sun CON 50 ' Sunny if one eye sees sun.
sun2 CON 60 ' Sunny if both eyes see bright.
sun_Gap CON 2 ' If eye difference beyond gap then go
Azimuth_Gap CON 2 ' Accelerometer +/- error.
Altitude_Gap CON 2 ' Accelerometer +/- error.
ON_SUN CON 50 ' If both eyes < ON SUN then focused in clear sun, record position to memory
Too_Bright CON 16 ' Eye failure.
danger CON 20 ' Brads off calculated solar path and tracking the wrong way.
drift 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 CON 64 ' Brads of azimuth for night park.
safe CON 20 ' Brads of altitude for night park.
rampAz CON 8 ' Unit of azimuth motor speed increase per second
rampAlt CON 16 ' Unit of altitude motor speed increase per second
startAz CON 96 ' Minimum azimuth motor start speed
startAlt CON 112 ' Minimum altitude motor start speed
maxAz CON 208 ' Maximum azimuth motor speed, out of 255 units
maxAlt CON 255 ' Maximum altitude motor speed, out of 255 units
freq con 20000 ' PWM frequency, make high to avoid ultrasonic whine
dawn_up con 15 ' Brads up dark park waiting for dawn
dawn_over con 15 ' Brads counterclockwise park waiting for dawn
brads_overhead con 53 ' Overhead sun value, 64 directly up
' Top of the program
PAUSE 10
CLEAR ' Must clear all varibles on startup
PAUSE 1
HIGH LED ' LED
PAUSE 1
TRISD = %11110000 ' Motor HBridge inputs made low from outputs PortD.0 to PortD.3
TRISC = %11111000 ' Motor PWM and enable made low from outputs PortC.0 to PortC.2
IF sw1 = 0 THEN No_Stow = yes ' Dish will not stow for error or wind.
IF SW2 = 0 THEN display = yes ' If switch flipped before power up then serial display enabled.
' Hardware backdoor diagnostics. Enables communication.
' sw1 = 1 Switches pulled up default at power start-up (flipped away from wires). Flipped towards wires enables safety stow
' sw2 = 1 If not default switch setting at power up then serial display port RS232 enabled.
' *** Switch operation ***
'
' Power switch on flip towards wires.
' Use power switch for on/off before disconnecting / connecting power to prevent corruption of time clock data.
' Press push button to reset power. Also press within one second when flash bootloading.
'
' If both direction switches in default position (away from wires) before power on then default solar tracking running.
' If one switch flipped towards wires before power on then serial port enabled for communications. Program loop runs 2 seconds slower.
' If other switch flipped towards wires before power on then the dish operates without error and wind stow functions.
' If both switches are flipped to default position after power on then both motors running on automatic.
' If one or the other switch flipped after power on then altitude motor goes up or altitude motor goes down and azimuth motor off.
' If both switches are flipped off default position after power on then both motors off.
'
' After power on or after reset button then configuration switches control motors
' so after display communications and/or no-stow functions have been configured on power up then
' flip configuration switches to default position (away from wires) to enable motors for automatic tracking.
'
' Must reset power to clear stow flags or to enable / disable serial port display and to enable / disable no-stow functions.
Top:
read 1000, WORD lat, due_north, due_south, due_up, minxy, maxxy, minz, maxz, dummy, azmotor, altmotor, azsensor, altsensor, azeye, alteye
' Azimuth sensor starts >0 due north (>0 due west in equatorial latitudes) then increases clockwise and ends <255 north by nortwest.
' Altitude sensor starts at >0 horizon (should be something like 36) and ends <255 vertical (something like 100).
' Binary radians 256 Brads = 360 Degrees
' READ dish specific values entered during installation using the command Install Limits.
' Use Polaris or Google maps to determine true north and south.
' lat is site latitude in degrees times 10.
' due_north, due_south, due_up, calibrates dish position sensors.
' minxy, maxxy, minz, maxz, are travel limit switches.
' azMotor, altMotor, azSensor, altSensor, azEye, altEye, 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 ' Software will reverse wires if motor or sensor installed backwards. 0 to 7 = PORTB.0 to PORTB.7
azMotor_B = 9 ' Configured in Install subroutine. Used in Set_Motors HBridge subroutine. 8 to 15 = PORTD.0 to PORTD.7
if azMotor then
azMotor_A = 9
azMotor_B = 8
endif
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 = 3
if altsensor then
altsensor_a = 3
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
SPEEDAZ = 0 ' Stop motors on program startup
hpwm 1, SPEEDAZ, freq ' Set PMW to HBridge
pause 1
SPEEDALT = 0
hpwm 2,speedalt, freq ' Set PMW to HBridge
pause 1
low azmotor_a ' Brake azimuth motor
pause 1
low azmotor_b
azimuth_on = no
pause 1
low altmotor_a ' Brake altitude
pause 1
low altmotor_b
altitude_on = no
pause 1
low warm
pause 1
Latitude = (((ABS lat) ** 46602) + 5) / 10 ' 128/180*65535 +5 nearest integer
IF LAT.15 THEN Latitude = -Latitude ' If south of the equator.
k = due_up - 64 'Brad altitude = Sensor altitude - k, Sensor altitude = Brad altitude + k Due_up should be > = 80
f = (256 * 128) / (due_south - due_north) 'Brad azimuth = (sensor - due_north) */ f
z = (256 * (due_south - due_north)) / 128 'sensor azimuth = due_north + (brad azimuth */ z)
'If tropic_summer AND Azimuth_Path > 128 THEN sensor azimuth = due_north - ((256 - brad azimuth) */ z)
FIX = 1
reboot = 1 ' Manual drive and power reset flags
high wind_pin ' Charge capacitor connected to wind detector.
pauseus 100
INPUT wind_pin
pause 1
main: 'XXXXXXXXXXXXXXXXXXXXXX MAIN LOOP
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.
pauseus 100
INPUT wind_pin
old_time = time ' Clock ticking
Altitude_destination = 0 ' Will be zero when eyes command.
Azimuth_destination = 0 ' Will be zero when eyes command.
GOSUB Get_Sensors ' Dish position from accelerometers on edge rolling like a coin.
if Altitude_sensor < (maxZ - (Altitude_Gap * 2)) then up_limit = 0
if Altitude_sensor > (minZ + (Altitude_Gap * 2)) THEN down_limit = 0
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 ' 8 bit Brads
tropic_summer = 0
if declination.7 = 0 and declination >= Latitude THEN tropic_summer = 1 ' Sun always in north summer tropics.
work8 = time
gosub Get_flags_north ' Flags times of arctangent crossover from north to south and from south to north
time = work8
sun_overhead = no
if time_overhead and time >= time_overhead then sun_overhead = yes ' Used to disable azimuth tracking error detection during overhead sun.
gosub get_path ' Get current sun position.
flag_north = 1
IF time > AM AND time < PM THEN flag_north = 0 ' Sun in the south mid day.
if tropic_summer THEN flag_north = 1 ' Sun always in north in the tropic during summer.
IF flag_north = 1 THEN Azimuth_Path = PRIOR ' Azimuth_Path = arctangent, prior = the other arctangent ~ the one in the north.
wb = Altitude_Path + 1 ' Adding 1 covers sunrise just below the horizon. Below the horizon is 255.
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
endif
'goto skipps ' This routine between skipps fills tracking memory with test data
'for time = 120 to 1317 ' memory space 2 AM to 10 PM
' gosub get_path ' Solar position calculator
' 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
' IF flag_north = 1 THEN Azimuth_Path = PRIOR ' North arctangent
' if time < 120 or time > 1317 then skipping ' Memory space 2 AM to 10 PM
' IF Altitude_path > 68 THEN SKIPPING ' 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 - ((256-Azimuth_Path) */ z) ' If tropical sun crosses north zero going west.
' Altitude_Path_sense = Altitude_Path + k ' Converts calculated Path Brads to specific dish sensor type data.
' 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 'new one minute routines
gosub get_path 'load current PATH location
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
IF flag_north = 1 THEN Azimuth_Path = PRIOR ' North arctangent
if dark and time < 720 and Altitude_Path < 68 then dark = no ' Sunrise!
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 ' Countdown tranistion from eyes to memory tracking.
IF Azimuth_Motor THEN Azimuth_Motor = Azimuth_Motor + 1 ' Count minutes motor running
IF Altitude_Motor THEN Altitude_Motor = Altitude_Motor + 1 ' Count minutes motor running
IF Azimuth_Motor > 3 THEN ' = 4 could be as little as 2 minutes, start at end of minute 1 and end begining minute 4.
Azimuth_Motor = 1 ' reset motor counting for continuing motor checking.
wb = Azimuth_sensor - azimuth_move ' Distance moved
IF ABS wb <= Azimuth_Gap THEN ' If no movement within sensor error
stow.3 = 1 ' Azimuth motor failed to move tag ###########
Altitude_Stow = yes
ELSE
' Else movement detected, reset motor counting for continuing motor checking.
azimuth_move = Azimuth_sensor ' Reset start location for checking movement distance.
ENDIF
ENDIF
IF Altitude_Motor > 3 THEN ' = 4 could be as little as 2 minutes, start at end of minute 1 and end begining minute 4.
Altitude_Motor = 1 ' reset motor counting for continuing motor checking.
wb = Altitude_sensor - altitude_move ' Distance moved
IF ABS wb <= Altitude_Gap AND Altitude_sensor < (maxZ - (Altitude_Gap * 2)) AND Altitude_sensor > (minZ + (Altitude_Gap * 2)) THEN 'If no movement within sensor error * 2
stow.4 = 1 ' Altitude motor failed to move tag (check limit switches) ###########
Azimuth_Stow = yes
ELSE
altitude_move = Altitude_sensor ' Reload start location for checking movement distance.
ENDIF
IF ABS wb <= Altitude_Gap and Altitude_sensor >= (maxZ - (Altitude_Gap * 2)) then up_limit = 1
IF ABS wb <= Altitude_Gap and Altitude_sensor <= (minZ + (Altitude_Gap * 2)) THEN down_limit = 1
ENDIF
endif
if time.2 <> old_time.2 then ' New four minute routines
write_flag = 1 ' Enable memory write
read_flag = 0 ' Enable memory read
endif
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 - ((256-Azimuth_Path) */ z) ' If tropical sun azimuth crosses north 0 to 255 tracking towards west.
Altitude_Path_sense = Altitude_Path + k ' Converts calculated Path Brads to specific dish sensor type data.
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 No_Stow = no and Stow THEN Check_Stow
IF dark THEN park
IF cloudy THEN memory
Sunny: ' Eyes command and bypass Helm
IF Focus THEN ' Wait after eye tracking before memory tracking.
dwell = 8 ' Wait 8 minutes if dish was previously focused.
ELSE ' else
dwell = 2 ' Wait 2 minutes if previously tracking while sunny.
endif
GOSUB set_Motors
goto run2 ' Print and loop
Park:
'Altitude_destination = orientate + k ' orientate brad to sensor data. Fixed Park altitude not on horizon.
'Azimuth_destination = due_north + (safe */ z) ' safe brad to sensor data. Fixed Park azimuth.
Altitude_destination = k + dawn_up ' Horizon plus up
Azimuth_destination = dawn - (dawn_over */ z) ' Sunrise plus over right
GOTO Check_Stow
Memory:
IF Azimuth_Memory = 0 and altitude_memory = 0 THEN ' If no recent memory then
Altitude_destination = Altitude_Path_sense ' tell Helm to use chart from Path
Azimuth_destination = Azimuth_Path_sense '
else ' else
Altitude_destination = Altitude_memory ' tell Helm to use memory log book
Azimuth_destination = Azimuth_memory
ENDIF
'f = (256 * 128) / (due_south - due_north) 'Brad azimuth = (sensor - due_north) */ f
'z = (256 * (due_south - due_north)) / 128 'sensor azimuth = due_north + (brad azimuth */ z)
wb = abs (Azimuth_destination - Azimuth_sensor)
if wb */ f > 220 then ' Check for possible tropic sun overhead conflicts in partly cloudy weather
if Azimuth_destination < Azimuth_sensor and Azimuth_destination + (256 */ z) < 256 then ' Memeory of north sun with recent eye on south sun
Azimuth_destination = (256 */ z) + Azimuth_destination ' 360 degree adjustment to Azimuth_Destination
else
if Azimuth_destination > Azimuth_sensor and Azimuth_destination > (256 */ z) then Azimuth_destination = Azimuth_destination - 256 */ z
endif
endif
Check_Stow: if No_Stow = Yes then skip_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 ' Azimuth_destination = Azimuth_sensor will tell Helm to stop azimuth motor.
ENDIF
ENDIF
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 then Helm
Skip_Stow:
if dark THEN Helm ' Do not dwell
clouds:
IF dwell THEN ' If recently tracking sun then dwell before Memory or Path tracking.
azimuth_go = no
altitude_go = no
GOSUB set_motors
goto run2 ' Print and loop
ENDIF
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 ' If on target then turn motor off
azimuth_go = no
GOTO skipper
ENDIF
azimuth_go = yes ' Else motor on
IF Azimuth_sensor < Azimuth_destination THEN
azimuth_command = right ' Set direction
ELSE
azimuth_command = left
endif
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 ' If on target then turn motor off
altitude_go = no
GOTO skippy
ENDIF
altitude_go = yes ' Else motor on
IF Altitude_sensor < Altitude_destination THEN
altitude_command = up ' Set direction
ELSE
altitude_command = down
endif
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]
hserout ["Path brads ",dec Azimuth_Path, " ",dec Altitude_Path,10,13,10]
hserout ["Path sense ",dec Azimuth_Path_sense, " ",dec Altitude_Path_sense," ",Sdec declination,10,13]
hserout ["Memory ",dec Azimuth_Memory, " ",dec Altitude_Memory," ",Sdec old_declination,10,13,10]
hserout ["Sensor ",dec Azimuth_sensor, " ",dec Altitude_sensor,10,13]
hserout ["Destination ",dec Azimuth_Destination," ",dec Altitude_Destination,10,13," ** "]
if cloudy then hserout [" cloudy "]
if focus Then hserout [" focus "]
if dark then hserout [" dark "]
if stow then hserout [" stow ",bin8 stow]
if cloudy = no and dark = no then hserout [" sunny "]
'HSEROUT [" **"]
hserout [10,13,10," Press (E) for Exit "] ' Test choices.
' decNum = (bcdNum.NIB1 * 10) + bcdNum.NIB0 converts hex byte used for clock display into decimal value.
' bcdNum = (decNum / 10 << 4) + (decNum // 10) converts decimal byte into hex byte suitable for clock display.
'*********** only for test without clock connected.
' CLICK = (minute >> 4)*10 + (minute & $F) + 1 ' Convert test clock minute increments to decimal
' IF CLICK = 60 THEN
' CLICK = 0
' HOUR = ((hour >> 4)*10 + (hour & $F)) ' Convert test clock hour to decimal and increment for 60 minute carryover.
' HOUR = HOUR + 1
' HOUR = ((HOUR / 10) << 4) + (HOUR // 10) ' Convert test decimal hour back to clock display hex byte.
' ENDIF
' MINUTE = ((CLICK / 10) << 4) + (CLICK // 10) ' Convert test decimal minute back to clock display hex byte.
' click = click + 1 ' Increment test clock minute for next loop.
'**************
HSERIN 1,timeout,[TEST] ' Hold menu choice -- capital letter or number of displayed choices
pause 10
iF TEST = "E" THEN SET_CLOCK
Timeout:
endif
IF azimuth_on = no AND altitude_on = no AND DISPLAY = NO and no_stow = no AND sw1 and sw2 THEN
IF dark or stow THEN SLEEP 120
IF cloudy THEN SLEEP 10
NAP 7 ' Nap 2 seconds
else
pause 1000
ENDIF
IF DISPLAY THEN PAUSE 2000
TOGGLE LED
goto main ' Big Loop
ending: ' Never happens unless 'ending' is called.
end
'*********************
Get_Sensors: ' Tilt accelerometers on edge like a rolling coin, arctangent of x,y pins returns angle in brad circle 0 to 255.
work3 = 0 ' Azimuth sensor
work4 = 0 ' Azimuth sensor
FOR smooth = 1 TO 32
PULSIN azsensor_a, HiPulse, xRaw
work3 = work3 + xRaw
PULSIN azsensor_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.0 = 1 ' Azimuth sensor failure tag ###########
Altitude_Stow = yes
ENDIF
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 ' Altitude sensor
work4 = 0 ' 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 ' Altitude sensor failure tag ###########
Azimuth_Stow = yes
ENDIF
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
'*********************
Get_Time:
I2Cread datapin, clockpin, $d1, 0, [sec,minute,hour,day,date,month,year]
if display then hserout [12] ' Clear screen
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," Thermax",13,10,10]
pause 10
endif
If time = old_time and second = previous_second then
stow.2 = 1 ' Time failure tag ###########
Azimuth_Stow = no
Altitude_Stow = yes
ENDIF
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 ' 256 brads = 360 degrees 256/365 * 65536 = 45965
work = SIN work ' If work.bit15 = 1 then SIN (work) is negative
signa = work.BIT15 ' 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 ' If negative then declination is below equinox 256 (0)
declination = work ' Declination byte in brads used in Path routines.
return
'*********************
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 not 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.
time_overhead = 0
signb = 1 ' Flags sunrise calculation finished.
AMX = 127:PMX = 127 ' Variables to hold gap between two arctangent solutions .
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 altitude_path > brads_overhead and altitude_path < 75 and time_overhead = 0 then time_overhead = time
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 ' Do dawn just once when altitude path is 0, or almost 0.
endif
wb = Azimuth_Path - prior ' The two arctangent answers are held in Azimuth_Path and prior.
wb = ABS(wb)
IF time < 720 THEN ' AM
IF AMX > wb THEN
AMX = wb
AM = TIME
ENDIF
ELSE ' PM
IF PMX > wb THEN
PMX = wb
PM = TIME
ENDIF
ENDIF
NEXT TIME ' Next minute
OSCCON = %01100000 ' Slow down micro to 4 MHz, numbers are crunched.
return
'*********************
Get_Eyes: ' Low numbers mean bright eyes.
IF dark THEN RETURN
Eyes_after_dark:
north = 0
south = 0
east = 0
west = 0
work1 = 8
'OSCCON = %01110000 ' Speed up micro to 8 MHz to crunch these numbers.
FOR Smooth = 1 TO work1
HIGH alteye_a
PAUSE 1 ' Charge eye capacitor.
RCTIME alteye_a, 1, work ' Time to discharge capacitor through photoresistor eye.
IF work = 0 THEN work = 1000 ' Timeout after 5000 count, 50000us or 50ms.
north = north + work
HIGH alteye_b
PAUSE 1
RCTIME alteye_b, 1, work
IF work = 0 THEN work = 1000
south = south + work
HIGH azeye_a
PAUSE 1
RCTIME azeye_a, 1, work
IF work = 0 THEN work = 1000
east = east + work
HIGH azeye_b
PAUSE 1
RCTIME azeye_b, 1, work
IF work = 0 THEN work = 1000
west = west + work
NEXT smooth
'OSCCON = %01100000 ' Slow down micro to 4 MHz, numbers are crunched.
north = north / work1
south = south / work1
east = east / work1
west = west / work1
if display then
hserout [13,10]
hserout ["Eye left ",dec east," down ",dec south,13,10]
hserout ["Eye right ",dec west," up ",dec north,13,10]
HSEROUT [" ---------------------------",13,10]
hserout [" ",sdec (east - west)," ",sdec (south - north),13,10,10]
endif
if FIX = 0 then return ' No eye motor command if called from Set_Clock
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 + east) < (sun2 * 2)) AND (north < sun OR south < sun OR (north + south) < (sun2 * 2)) THEN
cloudy = no
ELSE
cloudy = yes
wb = Altitude_Path + 1 ' One brad below 0 horizon.
if wb > 68 THEN dark = yes ' If calculated sun position below horizon and cloudy then after sunset.
RETURN ' Done with eyes because of clouds.
ENDIF
if (west <= east and azimuth_command = left) or (west >= east and azimuth_command = right) then azimuth_go = no
IF ABS (west - east) > sun_gap THEN azimuth_go = yes
IF west < east THEN ' Eyes command motors directions.
azimuth_command = right
ELSE
azimuth_command = left
endif
if (north <= south and altitude_command = down) or (north >= south and altitude_command = up) then altitude_go = no
if abs (north - south) > sun_gap THEN altitude_go = yes
IF north < south THEN
altitude_command = up
ELSE
altitude_command = down
endif
IF north < on_sun AND south < on_sun AND west < on_sun AND east < on_sun AND azimuth_go = no AND altitude_go = no THEN
Focus = 1 ' If all eyes see bright sun and both motors off then the dish must be focused.
ELSE ' Focus is required before position memory is recorded.
Focus = 0 ' Dish could be pointed at sun with motors off but sun not bright enough for memory (focus on bright clouds).
endif
wb = altitude_path_sense - altitude_sensor ' Distance between dish pointing and solar position.
IF Altitude_go = yes AND ABS wb > danger THEN ' If distance large then if commanded by the eye to move in the wrong direction then tracking error.
IF (altitude_path_sense > altitude_sensor AND Altitude_command = down) OR (altitude_path_sense < altitude_sensor AND Altitude_command = up) THEN
stow.7 = 1 ' Altitude eye/sensor/clock error. Check all three. ###########
Azimuth_Stow = yes
RETURN
ENDIF
ENDIF
if altitude_path > brads_overhead and altitude_path < 75 then sun_overhead = yes
if sun_overhead then skip_solar_danger 'skip azimuth check after sun passes directly overhead.
wb = azimuth_path_sense - azimuth_sensor
IF azimuth_go = yes AND ABS wb > (danger */ z) THEN ' Distance between dish pointing and solar position, danger converted to azimuth sensor type data.
IF (azimuth_path_sense > azimuth_sensor AND azimuth_command = left) OR (azimuth_path_sense < azimuth_sensor AND azimuth_command = right) THEN
stow.6 = 1 ' Azimuth eye/sensor/clock error. Check all three. ###########
altitude_stow = yes
RETURN
eNDIF
ENDIF
skip_solar_danger:
IF Focus THEN
If altitude_sensor > brads_overhead and altitude_sensor < 75 then sun_overhead = yes
' if altitude_sensor - k > 60 and altitude_sensor - k < 75 then
' sun_overhead = yes ' Azimuth position not accurate nor needed when sun is directly overhead
' goto skip_solar_noon ' in the tropics a few days per year when declination = latitude.
' endif
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) > 60 THEN ' Then if clock is not within 60 minutes
stow = $0F ' Solar_noon clock/position error. ###########
altitude_stow = yes ' Then clock or eye or sensor do not agree - stow.
return
ENDIF
I2Cwrite datapin, clockpin, $D0, 1, [$00, $12]: Time = 720 ' Long term autonomy solar noon clock reset.
solar_noon = 0 ' Only write one solar noon per day
write_flag = 1 ' Enable memory write of Focus location.
ENDIF
skip_solar_noon:
IF write_flag THEN ' Write Focus dish position and solar declination once every 4 minutes.
' 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] ' Beep computer indicating EEPROM data write
ENDIF
ENDIF
return
'*********************
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 ' Time 120 to 1317 converted to pointer 0 to 897
if pointer > 897 then no_memory ' 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 ' Find distance between prior day solar declination and current solar declination.
IF ABS WB > drift or Altitude_Memory = $FF THEN Search_back ' If declination difference is greater than the value 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) ' Pointer 0 to 897
if pointer > 897 then no_memory ' Memory space 2 AM to 10 PM.
READ pointer, AzPast, AltPast, old_declination ' Read prior day focus position data at earlier time.
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) ' Pointer 0 to 897
if pointer > 897 then no_memory ' Memory space 2 AM to 10 PM.
READ pointer, AzFuture, AltFuture, old_declination ' Read prior day focus position data at later time.
wb = old_declination - declination
IF ABS WB > drift or altfuture = $FF THEN Search_forward ' If data too old then search further forward.
WB = abs (azFuture - azPast)
if wb */ f > 30 then no_memory ' North/South tropics zero shadow day cross over in memory.
Azimuth_Memory = (WB * dat1)/(dat1+dat2) ' Calculate scale and offset to dead reckon between
WB = altFuture - altPast
wb = abs wb
Altitude_Memory = (WB * dat1)/(dat1+dat2) ' earlier and later sun memory data.
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) ' To display age via declination of old data.
IF POINTER > 896 THEN RETURN
read pointer,wb,wb,old_declination
endif
return
'*********************
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 ' 0.17777 brads per minute*65536=11650
WORK1 = SIN Latitude
work = SIN declination
SIGNA = WORK1.15 ^ WORK.15 ' If one or the other but not both negative
alt = (ABS WORK1 * ABS WORK) / 127 ' alt = ((SIN Latitude) * ABS(SIN declination)) / 127
IF SIGNA THEN ALT = -ALT ' then negate result.
work = COS h
signA = work.BIT15 ' 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 ' then negate result.
alt = (alt + work)
work1 = (alt * alt) MIN 16129 ' There is no arcsine. Brad circles are 256 units. The radius 127. The Hypotenuse squared 16129.
work = SQR(16129 - work1) ' X = SQR ( H * H - Y * Y ) same as Cosine = ( 16129 - Sine * Sine ). Angle = Arctangent Sine/Cosine
Altitude_Path = work ATN alt ' Altitude brad angle = arctangent (Y/X) X ATN Y
work = COS Altitude_Path
az = ((COS declination) * (SIN h))
signA = work.BIT15 ^ az.BIT15 ' If one or the other but not both negative
az = (ABS az / ABS work) MIN 127
work1 = az*az
IF signA THEN az = -az ' then negate result.
work = SQR(16129 - work1) ' X = SQR ( H * H - Y * Y )
Azimuth_Path = (work ATN az) + 128 ' Altitude brad angle = arctangent (Y/X) X ATN Y
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 ' If both switches flipped then
azimuth_go = no ' stop azimuth motor
altitude_go = no ' stop altitude motor.
ENDIF
IF sw1 = 1 AND sw2 = 0 THEN ' If one switch flipped then altitude up and on.
altitude_go = yes
altitude_command = up
azimuth_go = no ' Azimuth motor off.
ENDIF
IF sw1 = 0 AND sw2 = 1 THEN ' If the other switch flipped then altitude down and on.
altitude_go = yes
altitude_command = down
azimuth_go = no ' Azimuth motor off.
ENDIF
If (up_limit and altitude_command = up) or (down_limit and altitude_command = down) then altitude_go = no
Motor_Switch_Bypass: ' Use when keyboard controls motors.
if azimuth_sensor <= minxy and azimuth_command = left then azimuth_go = no ' Limit azimuth left switch. Altitude drive has built in limit switches.
if azimuth_sensor >= maxxy and azimuth_command = right then azimuth_go = no ' Limit azimuth right switch.
IF azimuth_go = no AND altitude_go = NO AND azimuth_on = NO AND altitude_on = NO THEN
warm = no ' Sleep HBridge
goto No_Change
else
warm = yes ' Enable HBridge
endif
IF azimuth_on = yes AND (azimuth_command <> azimuth_spin or azimuth_go = no) THEN ' Stop before reverse.
do ' reduce speed to zero in less than a second
wb = speedaz
speedaz = wb - 2 ' Slow azimuth
if speedaz > wb then speedaz = 0 ' If azimuth speed crosses over from 0 to 255 then azimuth speed = 0
hpwm 1, SPEEDAZ, freq ' Set PMW to HBridge
pause 8
loop until speedaz = 0 ' Exit when motor speed is zero
low azmotor_a ' Brake azimuth motor
pause 1
low azmotor_b
azimuth_on = no
pause 8
endif
IF altitude_on = yes AND (altitude_command <> altitude_spin or altitude_go = no) THEN ' Stop before reverse.
do ' Reduce speed to zero in less than a second.
wb = speedalt
speedalt = wb - 2 ' Slow altitude.
if speedalt > wb then speedalt = 0 ' If altitude speed crosses over from 0 to 255 then altitude speed = 0
hpwm 2,speedalt, freq ' Set PMW to HBridge
pause 8
loop until speedalt = 0 ' Exit when motor speed is zero
low altmotor_a ' Brake altitude
pause 1
low altmotor_b
altitude_on = no
pause 8
endif
Azimuth:
if speedaz = maxaz or azimuth_go = no then altitude ' If maximum Azimuth speed or Azimuth motor off then no need to change speed.
if speedaz = 0 then speedaz = startaz ' If zero speed then starting speed
wb = speedaz + rampaz ' Increment flag speed.
if wb > maxaz or wb < speedaz then ' If flag speed > maximum speed or flag speed crossed over from 255 to 0
speedaz = maxaz ' then set speed to maximum speed
else ' else increment speed to flag speed.
speedaz = wb
endif
if azimuth_on <> azimuth_go then ' If off and and need to go on then set direction first.
if azimuth_command = right then high azmotor_a ' Both A and B were off from previous brake
if azimuth_command = left then high azmotor_b
pause 1
endif
hpwm 1, SPEEDAZ, freq 'set pwm ' Set azimuth speed.
Altitude:
if speedAlt = maxAlt or Altitude_go = no then good ' If maximum Altitude speed or Altitude motor off then no need to change speed.
if speedAlt = 0 then speedAlt = startAlt ' If zero speed then starting speed
wb = speedAlt + rampAlt ' Increment flag speed.
if wb > maxAlt or wb < speedAlt then ' If flag speed > maximum speed or flag speed crossed over from 255 to 0
speedAlt = maxAlt ' then set speed to maximum speed
else ' else increment speed to flag speed.
speedAlt = wb
endif
if altitude_on <> altitude_go then ' If off and and need to go on then set direction first.
if altitude_command = up then high altmotor_a ' Both A and B were off from previous brake
if altitude_command = down then high altmotor_b
pause 1
endif
hpwm 2,speedalt, freq 'set pwm
good:
IF azimuth_go AND azimuth_on = no THEN ' If azimuth motor goes from off to on then
Azimuth_Motor = 1 ' start counting azimuth motor on time
Azimuth_Move = Azimuth_sensor ' store current azimuth location.
ENDIF
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 ' If altitude motor goes from off to on then
Altitude_Motor = 1 ' start counting altitude motor on time
Altitude_Move = Altitude_sensor ' store current altitude location.
ENDIF
IF altitude_go = no THEN Altitude_Motor = 0 ' If altitude motor off then stop counting on time.
azimuth_on = azimuth_go ' Motors followed commands.
azimuth_spin = azimuth_command ' Motors status now reflect those commands.
altitude_on = altitude_go
altitude_spin = altitude_command
No_Change:
IF azimuth_go = no AND altitude_go = NO THEN warm = no ' Sleep HBridge
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 [" down -"]
else
hserout [" up "]
endif
else
hserout [" "]
endif
hserout [dec speedalt,10,13]
hserout [10,13]
endif
return
'*********************
Set_Clock: ' Set clock to standard time. Bright sun solar tracking will update clock to solar noon time.
FIX = 0 ' Stop eyes from controlling motors.
TEST = 0 ' Clear menu choice.
'display = 1 ' Enable serial port
azimuth_go = no ' Stop azimuth motor
altitude_go = no ' Stop altitude motor
GOSUB Motor_Switch_Bypass ' Stop switches from controlling motors
KEYPAD:
'hserout [12]
gosub get_time
hserout [10,13]
hserout [ " Clock set ",10,13 ]
hserout [ " Drive motors and read sensors ",10,13 ]
hserout [ " Memory Read or erase ",13,10]
hserout [ " Install limits ",13,10]
HSEROUT [ " Run Program ",13,10,10 ]
hserin [wb]
hserout [12]
if wb = "C" then Clock_set
IF WB = "D" THEN Drive
if wb = "M" then Read_Write
if wb = "I" then Install
IF WB = "R" THEN TOP
WB = 0
GOTO KEYPAD
Clock_set:
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] ' Set Clock
goto clock_set
RESET:
FOR smooth = 7 TO 0 ' Clear Clock DS1307 clock reset and start crystal
I2Cwrite datapin, clockpin, $d0, smooth, [0] ' Run when backup battery replacement
NEXT
GOTO clock_set
Drive:
HSEROUT [12]
GOSUB GET_SENSORS
GOSUB GET_TIME
hserout [13,10," Azimuth Altitude",10,13,10]
GOSUB Eyes_after_dark
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, Azimuth_Memory, Altitude_Memory, old_declination
WORK4 = (POINTER / 3 + 30) * 4 ' Converts memory location to time value.
WB1 = (Azimuth_Memory - DUE_NORTH) */ f ' Converts azimuth sensor data to brads.
WB2 = ALTITUDE_Memory - K ' 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 Dec Brad",13,10]
hserout ["ptr time az alt az alt",13,10]
Azimuth_Memory = 0
Altitude_Memory = 0
goto read_write
stow_data
HSEROUT [12]
for pointer = 900 to 996 step 4
read pointer, wb, stow, Azimuth_sensor, Altitude_sensor ' WB is stow time/10.
IF WB = $FF THEN NXT ' No print if altitude blank with $FF
WB1 = (Azimuth_SENSOR - DUE_NORTH) */ f ' 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 Sensor Brad",13,10]
hserout ["ptr time stow 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,"Erase Tracking data 0 to 899"]
HSEROUT [10,13," Stow data 900 to 999",10,13]
hserout [10,"begin location? "]
hserin [dec work1]:
if work1 > 999 then work1 = 999
hserout [10,13," end location? "]
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] ' Beep computer indicating EEPROM data write
HSEROUT [DEC POINTER,32]
next pointer
goto read_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] ' Use Polaris star to find true north.
HSEROUT ["3 Due South ",dec due_south,13,10]
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
Thanks for all the great support,
Doug


Menu

Coding practice High Level vs Assembler
usually like most of hobbyist I write my programs
jackberg1 Today, 17:20in basic high level instructions as shown in the programing manual
eg: For A = x to y
next A
so far my understanding of the compiler...