PDA

View Full Version : Code Outside of Main is Repeating - HELP



daniEEP
04-17-2007, 12:17 PM
Hello,

I'm new to the forums. This is my first project using Parallax hardware and BASIC in general. I'm using a BS2 PBASIC program to control electronic blinds and X10 as well as communicate with two other BASIC stamps. All are BS2p's. The code needs to be cleaned up and streamlined but that's beside the point--the concerning part is that somehow my variables are being reinitialized to the values they're set to in the declarations section of the code. Therefore the first test case in main ( IF (level = 22) ) should be true only for the start of the execution of the program, since a) "level" changes throughout the execution and would never be 22 except for at the start of the program and b) there is an infinite loop in main so there's no reason that first test case should ever be evaluated again. I suspect that somehow my code is getting restarted because as I view the debug terminal, with every iteration of the main loop the program execution somehow jumps back to that first test case and finds level to be equal to 22! Surely there must be an easy fix for this! Any response is greatly appreciated--my teammates and I are pulling out our hair!! Thank you in advance!!

--Danielle

------------------ Here's the code: ------------------

' {$STAMP BS2p}
' {$PBASIC 2.5}

'-----------Pins and Baud Rates---------------
' POD 1 uses 13 for data, 12 for flow control
' POD 2 uses 15 for data, 14 for flow control
POD1data PIN 13
FC1 PIN 12
POD2data PIN 15
FC2 PIN 14
'BAUD CON 16780 '9600 baud for BS2px
pinOut PIN 1 'used To talk To BLINDS.
BAUD CON 16624 '9600 baud for BS2p, used to talk to blinds
stamp_BAUD CON 17405 '2400 baud for BS2p, used to talk to other stamps

'-----------My Variables----------------------
temp VAR Byte ' measured temperature outside
temp2 VAR Byte ' measured temperature inside
status VAR Byte ' is it hotter, colder, or equal outside?
oldStatus VAR Byte
oldStatus = -1
eeAddr VAR Word ' pointer to current location in eeprom
eeAddr = 0
' X10 variables
zPin CON 8 ' Zero-crossing-detect pin from TW523 or PL513.
mPin CON 9 ' Modulation-control pin to TW523 or PL513.
houseA CON 4 ' House code: 0=A, 1=B... 15=P
Unit1 CON 4 ' Unit code: 0=1, 1=2... 15=16
' light sensor variables
light VAR Word
light2 VAR Word
level VAR Byte ' current light level of indoor lamp: can be from 0-19
level = 22 ' initialize to an invalid value
'tmp VAR Byte 'variable to hold new, desired light level
'x VAR Byte 'temp variable for calculating dim or bright level
blinds_pos VAR Byte
blinds_pos = 5
' 0 = open
' 1 = 90 degree tilt
' 2 = 45 degree tilt
' 3 = closed

'-----------User-set Variables----------------
desiredTemp VAR Byte ' user's set temperature
desiredTemp = 74

errorMargin VAR Byte ' temperature should be within this range.
errorMargin = 1

'for this iteration, we will assume that the user wants a level of 3 (high)
'desired_light VAR Byte
'desired_light = 3 'user setting for light levels. it's a combination of windows and lamp.
'0: off
'1: low
'2: medium
'3: high

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Main:
IF (level = 22) THEN
DEBUG "Level is ", DEC level, CR
GOSUB Lamp_On ' turn on the lamp for the first time
ENDIF

DO
DEBUG "Blinds pos is ", DEC blinds_pos, CR

GOSUB Get_Temperature_Light_1
GOSUB Get_Temperature_Light_2
'GOSUB Save_Temperature_Light_Pod1
'GOSUB Save_Temperature_Light_Pod2

GOSUB Act_On_Temperature
'PAUSE 1000*60*5 'wait five minutes
PAUSE 10000
DEBUG CR, "-----------------------------------", CR, CR
LOOP
END

Get_Temperature_Light_1:
'POD1 is the OUTSIDE Pod!
SERIN POD1DATA\FC1,stamp_BAUD,[DEC5 light, DEC2 temp] ' receive light and temp
'SERIN POD1data\FC1,stamp_BAUD,[DEC2 temp] ' receive temp
' for testing, let's set the levels here
'---outside levels----
'temp = 70
'light = 500
'---inside levels-----
'temp2 = 65
'light2 = 800


DEBUG "Outside (Pod 1) Light: ", DEC5 light, CR
DEBUG "Outside (Pod 1) Temp: ", DEC2 temp, CR
RETURN

Get_Temperature_Light_2:
'POD2 is the INSIDE Pod!
SERIN POD2data\FC2,stamp_BAUD,[DEC5 light2, DEC2 temp2] ' receive light and temp
'SERIN POD2data\FC2,stamp_BAUD,[DEC2 temp2] ' receive temp

DEBUG " Inside (Pod 2) Light: ", DEC5 light2, CR
DEBUG " Inside (Pod 2) Temp: ", DEC2 temp2, CR, CR
RETURN

Save_Temperature_Light_Pod1:
STORE 7
IF (eeAddr >= 2047) THEN ' out of space in eeprom bank
DEBUG CR, "Out of space.", CR
ELSE
WRITE eeAddr, 1 ' let everyone know that we're talking about pod1
eeAddr = eeAddr + 1
WRITE eeAddr, temp
eeAddr = eeAddr + 1 ' add one byte to the current location in eeprom
WRITE eeAddr, Word light
eeAddr = eeAddr + 2 ' add two bytes (one word) to the current location in eeprom
ENDIF
RETURN

Save_Temperature_Light_Pod2:
STORE 7
IF (eeAddr >= 2047) THEN ' out of space in eeprom bank
DEBUG CR, "Out of space.", CR
ELSE
WRITE eeAddr, 2 ' let everyone know that we're talking about pod2
eeAddr = eeAddr + 1
WRITE eeAddr, temp2
eeAddr = eeAddr + 1 ' add one byte to the current location in eeprom
WRITE eeAddr, Word light2
eeAddr = eeAddr + 2 ' add two bytes (one word) to the current location in eeprom
ENDIF
RETURN

Act_On_Temperature:
GOSUB Get_Status
'This case of not changing anything would not hold anymore since each status does different things based on light.
'IF (status = oldStatus) THEN ' nothing has changed so don't do anything
' status of temperature has not changed but the light outside may have changed
'GOSUB Adjust_Light
'RETURN
IF (status = 1) THEN ' it's COLDER outisde
GOSUB Colder_Outside
ELSEIF (status = 2) THEN ' it's HOTTER outside
GOSUB Hotter_Outside
ELSEIF (status = 0) THEN ' it's EQUAL inside to desired
GOSUB Equal_Temp
ENDIF
oldStatus = status
RETURN

Hotter_Outside:
DEBUG "Greater than ", DEC desiredTemp, " outside", CR

IF (light > light2) THEN ' it's BRIGHTER outside than inside
'DEBUG "It's brighter outside than inside.", CR
GOSUB Close_Blinds

ELSEIF (light = light2) THEN ' it's about equal outside and inside
'DEBUG "Light levels are about equal outside and inside.", CR
GOSUB Tilt_Blinds_45

ELSEIF (light < light2) THEN ' it's DARKER outside than inside
'DEBUG "It's darker outside than inside.", CR
GOSUB Tilt_Blinds
ENDIF

GOSUB Adjust_Light
RETURN

Equal_Temp:
DEBUG "Temperature outside is equal to temperature inside. Calling function Hotter_Outside.", CR
'it seems like if it's equal outside then there would still be solar radiation, therefore this case should be compounded with the previous case
'and we would add some margin of error to account for the radiation.

GOSUB Hotter_Outside

'IF (light > light2) THEN ' it's BRIGHTER outside than inside
'DEBUG "It's brighter outside than inside.", CR
'GOSUB Open_Blinds

'ELSEIF (light = light2) THEN ' it's about equal outside and inside
'DEBUG "It's brighter outside than inside.", CR
'do nothing to blinds

'ELSEIF (light < light2) THEN ' it's DARKER outside than inside
'DEBUG "It's darker outside than inside.", CR
' do nothing to blinds
'ENDIF
'GOSUB Adjust_Light
RETURN

Colder_Outside:
DEBUG "Less than ", DEC desiredTemp, " outside.", CR

'IF (light > light2) THEN ' it's BRIGHTER outside than inside
'DEBUG "It's brighter outside than inside.", CR
' GOSUB Open_Blinds

'ELSEIF (light = light2) THEN ' it's about equal outside and inside
'DEBUG "It's brighter outside than inside.", CR
' GOSUB Open_Blinds

'ELSEIF (light < light2) THEN ' it's DARKER outside than inside
'DEBUG "It's darker outside than inside.", CR
' why would we want to close the blinds in this case? even if it's darker we can still use the light!
' GOSUB Close_Blinds
'ENDIF

GOSUB Open_Blinds
GOSUB Adjust_Light
RETURN

Open_Blinds:
'Open all the way
IF (blinds_pos = 0) THEN ' blinds are already in this position
RETURN
ENDIF
DEBUG CR, "Opening blinds...", CR
SEROUT pinOut, BAUD, ["*1o00;"]
'PAUSE 60000 'give it 60 seconds to complete the command
GOSUB Stop_Blinds
blinds_pos = 0
RETURN

Close_Blinds:
'Close all the way
IF (blinds_pos = 3) THEN ' blinds are already in this position
RETURN
ENDIF
DEBUG CR, "Closing blinds...", CR
SEROUT pinOut, BAUD, ["*1c00;"]
IF (blinds_pos = 0) THEN 'blinds were all the way open so it will take a minute for them to close
PAUSE 60000 'give it 60 seconds to complete close command
ELSE
PAUSE 5000 'otherwise give it five seconds to complete close command (was tilted before)
ENDIF
blinds_pos = 3
RETURN

Tilt_Blinds:
'Tilt blinds to 180 degrees (horizontal)
IF (blinds_pos = 1) THEN ' blinds are already in this position
RETURN
ENDIF
IF (blinds_pos <> 3) THEN ' if not equal to closed, need to close blinds before we can tilt them
GOSUB Close_Blinds
ENDIF
DEBUG CR, "Tilting blinds...", CR
SEROUT pinOut, BAUD, ["*1o00015;"]
GOSUB Stop_Blinds
blinds_pos = 1
RETURN

Tilt_Blinds_45:
'Tilt blinds to a 45 degree angle from horizontal
IF (blinds_pos = 2) THEN ' blinds are already in this position
RETURN
ENDIF
IF (blinds_pos <> 3) THEN ' if not equal to closed, need to close blinds before we can tilt them
GOSUB Close_Blinds
ENDIF
'DEBUG CR, "Tilting blinds (45)...", CR
SEROUT pinOut, BAUD, ["*1o00015;"] ' need to determine the timing command
GOSUB Stop_Blinds
blinds_pos = 2
RETURN

Stop_Blinds:
'Stop all systems
'DEBUG CR, "Stopping blinds...", CR
SEROUT pinOut, BAUD, ["*1s00;"]
RETURN

Lamp_On:
DEBUG CR, "Turning lamp on...", CR
XOUT mPin,zPin,[houseA\Unit1] ' Talk to Unit 1.
XOUT mPin,zPin,[houseA\UNITON] ' Tell it to turn ON.
level = 19
RETURN

Lamp_Off:
'DEBUG CR, "Turning lamp off...", CR
XOUT mPin,zPin,[houseA\Unit1] ' Talk to Unit 1.
XOUT mPin,zPin,[houseA\UNITOFF] ' Tell it to turn OFF.
level = 0
RETURN

Lamp_Dim:
'IF (level = 0) THEN ' lamp is already off
' DEBUG "Lamp is off--cannot dim any more.", CR
'RETURN
'ENDIF
DEBUG "Dimming lamp...", CR
XOUT mPin,zPin,[houseA\Unit1] ' Talk to Unit 1. Not sure if we need this every time?
XOUT mPin, zPin,[houseA\DIM]
level = level - 1
DEBUG "level is ", DEC level, CR
RETURN

Lamp_Brighten:
IF (level = 19) THEN ' lamp is at brightest level
'DEBUG "Lamp is fully on--cannot brighten more.", CR
RETURN
ENDIF
'DEBUG "Brightening lamp...", CR
XOUT mPin,zPin,[houseA\Unit1] ' Talk to Unit 1. Not sure if we need this every time?
XOUT mPin, zPin,[houseA\BRIGHT]
level = level + 1
RETURN

''''Change_Lamp:
' apparently, the best way to dim is to turn the lamp fully off then on again and THEN dim it. should we do that!?
'DO
'DEBUG CLS
'STORE 8
'READ 100, level ' this is the current level
'tmp is the desired level
'DEBUG HOME, "Press 'q' at anytime to return to main screen..."
'DEBUG HOME, CR, CR,"Enter Desired Light Level on a scale of 0 to 19: ", CR, CLREOL
'DEBUGIN DEC tmp
'IF (tmp = "q") THEN
' DEBUG CLS
' GOTO Main
'''' DEBUG "Changing light level...", CR
'''' DEBUG "Current light level: ", DEC2 level, CR
'''' DEBUG " New, desired level: ", DEC2 tmp, CR

'''' IF (tmp = 0) THEN
'STORE 8
'WRITE 100, tmp
'''' XOUT mPin,zPin,[houseA\UNITOFF]
'''' ELSEIF (level = tmp) THEN
'''' DEBUG "Lights are already set to given level.", CR
'''' PAUSE 2000
'DEBUG CLS
'''' ELSEIF (level > 0) THEN
'''' IF (level = 19)THEN
'STORE 8
'WRITE 100, tmp
'DEBUG "Value Stored", CLREOL
'PAUSE 1000
'''' x = 19 - tmp
'''' XOUT mPin,zPin,[houseA\DIM\x]
'''' ELSEIF (level > tmp) THEN
'STORE 8
'WRITE 100, tmp
'''' x = level - tmp
'''' XOUT mPin, zPin,[houseA\DIM\x]
'''' ELSEIF (level < tmp) THEN
' STORE 8
'WRITE 100, tmp
'''' x = tmp - level
'''' XOUT mPin,zPin,[houseA\BRIGHT\x]
'''' ENDIF

'''' ELSEIF (level = 0) THEN
'STORE 8
'WRITE 100, tmp
'''' x = 19 - tmp
'''' XOUT mPin,zPin,[houseA\UNITOFF]
'''' XOUT mPin,zPin,[houseA\UNITON\2,houseA\DIM\x]
'''' ENDIF
'''' PAUSE 100
'DEBUG "looping...", CR
'LOOP
''''RETURN

Get_Status:
IF (temp < (desiredTemp - errorMargin)) THEN ' outside temperature is less than desired level
status = 1
ELSEIF (temp > (desiredTemp + errorMargin)) THEN ' outside temperature is greater than desired level
status = 2
ELSE ' outside temperature is within desired range
status = 0
ENDIF
'DEBUG "Temperature status: ", DEC1 status, CR
RETURN

Adjust_Light:
IF (light2 > 1029) THEN ' it's too dark inside
GOSUB Adjust_Light_Higher
ELSEIF (light2 < 790) THEN ' it's too light inside--want to save power
GOSUB Adjust_Light_Lower
ELSE ' just right
'DEBUG "Light level good.", CR
RETURN
ENDIF
RETURN

Adjust_Light_Higher:
' get inside light level and compare it to user set value. if it's lower, brighten the lamp via X10.
DO
IF (light2 > 1029) THEN ' it's too dark inside
IF (level = 19) THEN ' lamp is turned up all the way and it still isn't bright enough--bad
'DEBUG "Error: can't get light bright enough.", CR
RETURN
ENDIF
GOSUB Lamp_Brighten
PAUSE 3000
ELSE
RETURN
ENDIF
LOOP
END
RETURN

Adjust_Light_Lower:
' this is a power saving technique that lowers the indoor lamp until we're at lower end of user specified range
' get inside light level and compare it to user set value. if it's much higher, dim the lamp via X10.
DO
IF (light2 < 790) THEN ' it's too light inside... turn dowm lamp to save power
IF (level = 0) THEN ' lamp is turned down all the way--good
RETURN
ENDIF
GOSUB Lamp_Dim
'PAUSE 3000
ELSE
RETURN
ENDIF
LOOP
END
RETURN

' Smart house light levels:
'0 57000
'1 52700
'2 47900
'3 46500
'4 18900
'5 10400
'6 6500
'7 3100
'8 3000
'9 2220
'10 1890
'11 1410
'12 1200
'13 1110
'14 1030
'15 910
'16 830
'17 820
'18 790
'19 790

'0: off (X10 0-4) 18900+
'1: low (X10 5-9) 18899 - 2220
'2: medium (X10 10-14) 2219 - 1030
'3: high (X10 15+) 1029 - 0

' for this iteration, we will keep the light between 1029 and 790.

Bruce Bates
04-17-2007, 01:37 PM
Danielle -

I suspect the program is being reset or restarted. To prove that suspicion, add the following as the FIRST line of program code in your program:

DEBUG "STARTING"

You should NEVER see "starting" more than once in any iteration of your program. If you do, the Stamp is being reset, and·beginning execution right from the very beginning, as it's expected to.

If this IS the case, then the next bit of troubleshooting will be to determine why the reset is occuring. It may be a low voltage (brownout) situation, a loss of power situation, excess current draw somewhere, or possibly some mis-wiring.

Just as a sidenote, there are numerous reason why the program code you supplied won't even make it through the PBASIC syntax checker, and thus can not be loaded into your PBASIC Stamp.

Regards,

Bruce Bates

allanlane5
04-17-2007, 07:37 PM
Part of it could also be that it looks like you're writing to eeprom down to address 2047, but you're using eeprom for your code from $7FF down to $18F.

So, as soon as your program starts over-writing eeprom at location $18F, you're 'stepping' on your own code. If you call enough 'gosubs' without a return (because the return has been over-written) you're going to get a 'reset' and your program starts over.

I feel sure the BS2p has multiple eeprom banks, and that there's some way around this.

Oh, and here's an 'upload' version of your code, with formatting fixed a little.

Post Edited (allanlane5) : 4/17/2007 12:44:53 PM GMT

daniEEP
04-18-2007, 10:31 AM
Thanks for the help. I emailed the Parallax tech support and they suggested that I had reached the maximum number of nested GOSUB statements (4) and I had! I fixed that and now it works!

Bruce, you mentioned that the code wouldn't compile for you? I never had any problems with syntax, only with the restarting code. Thanks for everything!