Flags

TJF1960

Active Member
I have a number of subroutines that I want to run every XX seconds and want them to run only once per time schedule. So I have been messing around with the programming and have pieced together a couple of examples you all have been kind enough to share. For simplicity I have simplified the below example to just 1 test subroutine.
As far as specifics I need a time frame of 2 seconds, 15 seconds, 30 seconds, 1 minute and 5 minutes but have the below example timing at 4 seconds for testing.
 
I haven't been able to figure out the easiest/best way to unmark the flag one per timing cycle.
 
Here is what I have so far:

START
DELAY 5000
LOOP:
ROTR CTS 2 VAR1
ANDB VAR1 1 VAR1
ANDB VAR2 256
CZ TEST1
GOTO LOOP
END
TEST1:
ORB VAR2 256 VAR2
ADD VAR5 1 VAR5
RET

Var1 varies between 0 and 1 for 4 seconds each. Bit 8 of var2 is the test1 flag. Test1 runs once and the flag is set. Can't figure out the proper method to turn the flag off once per timing cycle (in this case every 4 seconds).
 
Any help and or suggestions or opinions would be appreciated.
Thanks,
tim
 
Can you post more about why you need these delays aka what they are for?  What does "once per time schedule" mean?
 
OK, try this.  It isn't tested, but I have written this to do something once every 30 seconds, and every 60 seconds.  You can continue to add more blocks or modify the 30 and 60 to other times.  For each extra block, you use the next over bit in ram1.  The concept is that when you divide cts by the interval you are looking for, the remainder will be 0 for one whole second at the top of that interval.  During that one second, the subroutine gets called multiple times.  But it aborts all but the first time because I have set a flag in ram1 on the first pass that forces an abort on all other passes.  Once you have gotten out of the that 1 second at the top of each time block, the remainder will now be non-0, and the flag gets reset to allow it to run on the first pass at the top of the next time block.
 
START
MOD CTS 30            **divides current total seconds by 30, if the remainder is 0 (it is on the 30 second mark) it sets the zero bit to 0, otherwise zero bit is 1
CNZ EVERY30A        **during the 29 seconds it is not remainder 0, it calls sub 
CZ EVERY30            **if zero bit is 0, then you are in the midst of the 1 second of remainder 0 that happens every 30 seconds
MOD CTS 60
CNZ EVERY60A
CZ EVERY60
END
 
EVERY30:
ANDB 1 RAM1           **checks if first bit of ram1 is 1, this is used to check if it is the first run during each remainder 0, or a subsequent run
BNZ ABORT              **if it is, abort so it only runs once during the 1 second every 30 that remainder is 0
ORB 1 RAM1 RAM1    **set RAM1 first bit to 1 (since this sub gets called many times during the 1 sec) and thus the sub aborts on those extra calls
whatever other stuff
RET
 
EVERY30A:
ANDB 0XFFFFFFFE RAM1 RAM1             **this gets called when no longer on the 30 sec mark and resets first bit of ram1 to 0 so EVERY30 doesn't get aborted on the first pass of each 30 second block
TSTEQ 1 1      **makes certain zero bit still not 0 when returns to main body
RET
 
EVERY60:
ANDB 2 RAM1          **for 60 second block, using second bit of ram1 instead of first bit
BNZ ABORT
ORB 2 RAM1 RAM1
whatever other stuff
RET
 
EVERY60A:
ANDB 0XFFFFFFFD RAM1 RAM1
TSTEQ 1 1
RET
 
ABORT:
RET
 
I edited it a little.  Made sure the clock was set prior to running and eliminated the "TSTEQ 1 1" lines.
 
START
SET RAM1 128       **sets the 8th bit to 1 so that RAM1 never is zero, so zero bit on RAM1 in the "EVERYxxA" subs doesn't need the TSTEQ 1 1 to ensure the zero bit is 1.  This bit can't be used for anything else.
TSTLT CY 2013
GOTO START
LOOP:
MOD CTS 30            **divides current total seconds by 30, if the remainder is 0 (it is on the 30 second mark) it sets the zero bit to 0, otherwise zero bit is 1
CNZ EVERY30A        **during the 29 seconds it is not remainder 0, it calls sub 
CZ EVERY30            **if zero bit is 0, then you are in the midst of the 1 second of remainder 0 that happens every 30 seconds
MOD CTS 60
CNZ EVERY60A
CZ EVERY60
GOTO LOOP
END
 
EVERY30:
ANDB 1 RAM1           **checks if first bit of ram1 is 1, this is used to check if it is the first run during each remainder 0, or a subsequent run
BNZ ABORT              **if it is, abort so it only runs once during the 1 second every 30 that remainder is 0
ORB 1 RAM1 RAM1    **set RAM1 first bit to 1 (since this sub gets called many times during the 1 sec) and thus the sub aborts on those extra calls
whatever other stuff
RET
 
EVERY30A:
ANDB 0XFFFFFFFE RAM1 RAM1             **this gets called when no longer on the 30 sec mark and resets first bit of ram1 to 0 so EVERY30 doesn't get aborted on the first pass of each 30 second block
RET
 
EVERY60:
ANDB 2 RAM1          **for 60 second block, using second bit of ram1 instead of first bit
BNZ ABORT
ORB 2 RAM1 RAM1
whatever other stuff
RET
 
EVERY60A:
ANDB 0XFFFFFFFD RAM1 RAM1
RET
 
ABORT:
RET
 
Lou, thank you so much for the time you spent with both of these programs! I coded the 2nd one up and it works perfectly. My next step is to understand it! Thank you also for the explanations. I really do appreciate it.
 
Question Lou,
When I add another block the timing gets for the first block gets messed up. I found if I upped the 3rd block ANDB and ORB bits by one it corrected the problem. But then adding a 4th block messes the timings up again. I haven't figured out why yet, hoping you might have an idea where I went wrong.
 
START   
 SET RAM1 128 
 SET RAM2 0 
 SET RAM3 0 
 SET RAM4 0 
 SET RAM5 0 
 SET RAM6 0 
 SET RAM7 0 
 SET RAM8 0 
 TSTLT CYEAR 2013 
 GOTO START  
LOOP:
 MOD CTS 2 
 CNZ  EVERY2A 
 CZ  EVERY2 
 MOD CTS 15 
 CNZ  EVERY15A 
 CZ  EVERY15 
 MOD CTS 30 
 CNZ  EVERY30A 
 CZ  EVERY30 
 GOTO LOOP  
 END   
EVERY2:
 ANDB 1 RAM1 
 BNZ  ABORT 
 ORB 1 RAM1 RAM1
 ADD VAR1 1 VAR1
 RET   
EVERY2A:
 ANDB -2 RAM1 RAM1
 RET   
EVERY15:
 ANDB 2 RAM1 
 BNZ  ABORT 
 ORB 2 RAM1 RAM1
 ADD VAR2 1 VAR2
 RET   
EVERY15A:
 ANDB -3 RAM1 RAM1
 RET   
EVERY30:
 ANDB 4 RAM1 
 BNZ  ABORT 
 ORB 4 RAM1 RAM1
 ADD VAR3 1 VAR3
 RET   
EVERY30A:
 ANDB -5 RAM1 RAM1
 RET   
ABORT:
 RET   
 
So I had some more time to play with it and I think I figured it out with the calc.,  I need to learn hex. But I am getting there! 
For some reason the plc code changes the hex  0XFFFFFFFE to -2 which was throwing me off.
So in the 3rd block the hex should be 0XFFFFFFFB. And the 4th block it should be 0XFFFFFFF7. Right?
 
Thanks.
 
Use this website to convert.
 
http://www.mathsisfun.com/binary-decimal-hexadecimal-converter.html
 
or this one
 
http://www.binaryconvert.com/convert_signed_int.html
 
The ANDB is used to turn a bit off.  It will be 32 "1's" except for the bit you are turning off which will be a "0"
 
The ORB is used to turn a bit on.  It will be all "0's" except for the bit you are turning on which will be a "1"  Unlike the ANDB situation, you don't need to include the leaading "0's" since a blank is the same thing as a zero.
 
For example, turn off the third bit
11111111111111111111111111111011 binary  = 0xFFFFFFFB hex = -5 decimal
ANDB RAM1 0XFFFFFFFB RAM1
or
ANDB RAM1 -5 RAM1
 
turn on the thrid bit
100 binary = 4 decimal = 0x4 hex
ORB RAM1 4 RAM1
or
ORB RAM1 0x4 RAM1
 
Thank you for the links and the extra information. I did run into a snag after recoding, a little research and the extra info you provided led me right to my mistake. It is running as expected now.
 
Thanks again,
Tim
 
Lou Apo said:
I edited it a little.  Made sure the clock was set prior to running and eliminated the "TSTEQ 1 1" lines.
 
START
SET RAM1 128       **sets the 8th bit to 1 so that RAM1 never is zero, so zero bit on RAM1 in the "EVERYxxA" subs doesn't need the TSTEQ 1 1 to ensure the zero bit is 1.  This bit can't be used for anything else.
Can I move this to any bit location for instance bit 30 or 31 without issue?
Can I use all the unused bits of RAM1 as flags (or whatever) for other areas? So basically in your program example above with 2 blocks (2 flags) plus the bit used to assure RAM1 is never 0, that leaves 29 bits for other flags or whatever, right?
 
One last question from your post above:
"For example, turn off the third bit
11111111111111111111111111111011 binary  = 0xFFFFFFFB hex = -5 decimal
ANDB RAM1 0XFFFFFFFB RAM1
or
ANDB RAM1 -5 RAM1"
 
I am unclear as to why that command does not set all the bits to 1 (not just the third bit)  regardless of what their state was before? I think I just realized the answer, is it because of the AND logic table result (1 and 0 =0, 1 and 1 =1)?
 
Thanks,
Tim
 
TJF1960 said:
Can I move this to any bit location for instance bit 30 or 31 without issue?
Can I use all the unused bits of RAM1 as flags (or whatever) for other areas? So basically in your program example above with 2 blocks (2 flags) plus the bit used to assure RAM1 is never 0, that leaves 29 bits for other flags or whatever, right?
 
One last question from your post above:
"For example, turn off the third bit
11111111111111111111111111111011 binary  = 0xFFFFFFFB hex = -5 decimal
ANDB RAM1 0XFFFFFFFB RAM1
or
ANDB RAM1 -5 RAM1"
 
I am unclear as to why that command does not set all the bits to 1 (not just the third bit)  regardless of what their state was before? I think I just realized the answer, is it because of the AND logic table result (1 and 0 =0, 1 and 1 =1)?
 
Thanks,
Tim
 
Yes to part one, you can set any of the 32 bits to 1 to keep it always not zero (just be sure not to use that bit for something else).
 
Yes to part two, ANDB works how you said.  Also, ANDB 0 0 = 0.  So ANDB with 1 leaves it unchanged, ANDB with 0 turns it off (or keeps it off).
 
Maybe there should be some commands added to do this:

SETB 0 RAM1 ;sets bit 0
GETB 0 RAM1 RAM2 ;gets bit 0 and stores it in RAM2
CLRB 0 RAM1 ;clears bit 0
TSTB 0 RAM1 ;sets the zero bit to the value of bit 0, also skips the next line of code if 0
 
This would just be to make it more human readable and easier for novices.
 
Thanks Lou!!!
 
 
az1324 said:
Maybe there should be some commands added to do this:

SETB 0 RAM1 ;sets bit 0
GETB 0 RAM1 RAM2 ;gets bit 0 and stores it in RAM2
CLRB 0 RAM1 ;clears bit 0
TSTB 0 RAM1 ;sets the zero bit to the value of bit 0, also skips the next line of code if 0
 
This would just be to make it more human readable and easier for novices.
 
As I have been absorbing and learning, and trying to code I was wishing there were commands as you suggested. It would make some things a lot easier for novices.  
 
Thanks to both of you,
Tim
 
In the phrase "Zero Bit Updated" is it bit 0 of the ram or var specified? In other words take ANDB RAM1 0XFFFFFFF9 RAM1 which will set bit 1 and bit 2 to 0, is it bit 0 of ram1 which gets updated?
 
No, the zero bit is a totally different bit that stands on its own.  It is used for the BZ, CZ, BNZ, CNZ instructions (and in the latest firmware can be read directly as ZBIT).
 
Back
Top