BS2 Timer - Best Approach Request
knightofoldcode
Posts: 233
Board,
I'm having a hard time figuring out the best way to proceed.
I need to be able to design some type of unit that will turn on a relay for x seconds. The number of seconds is semi-variable, ie a setting that needs to be changed when the BS2 is programmed.
I could need up to 8+ relays. Timing is not extremely critical. Timing is somewhere in the range of 5 seconds to 1 hour, maybe more.
But if the BS2 triggers relay 1 for 5 minutes, it may need to trigger relay 2 in 2 minutes...so the code can't tie down the BS2.
I can't really figure out the best way to do this... I could use a 555 timer for each and every relay, but that seems rather pointless, and seems to increase the chip count way above what it needs to be.
I know exactly how to do it in Visual Basic, and PHP.... just not in pBasic. [noparse];)[/noparse]
All I can come up with is a loop that waits 1 second, then we add up the seconds, but again that seems wasteful... I would be willing to use a RTC (Real Time Chip) but this seems overkill for this situation.
Any suggestions?
MUCH TIA,
Knight.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
This message transmitted with 100% recycled electrons.
-=-=-=-=-=-
Gravity doesn't exist. The Earth sucks.
-=-=-=-=-=-
Make a man a fire, and he will be warm for the night.
Light the man on fire, and he will be warm for the rest of his life.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
I'm having a hard time figuring out the best way to proceed.
I need to be able to design some type of unit that will turn on a relay for x seconds. The number of seconds is semi-variable, ie a setting that needs to be changed when the BS2 is programmed.
I could need up to 8+ relays. Timing is not extremely critical. Timing is somewhere in the range of 5 seconds to 1 hour, maybe more.
But if the BS2 triggers relay 1 for 5 minutes, it may need to trigger relay 2 in 2 minutes...so the code can't tie down the BS2.
I can't really figure out the best way to do this... I could use a 555 timer for each and every relay, but that seems rather pointless, and seems to increase the chip count way above what it needs to be.
I know exactly how to do it in Visual Basic, and PHP.... just not in pBasic. [noparse];)[/noparse]
All I can come up with is a loop that waits 1 second, then we add up the seconds, but again that seems wasteful... I would be willing to use a RTC (Real Time Chip) but this seems overkill for this situation.
Any suggestions?
MUCH TIA,
Knight.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
This message transmitted with 100% recycled electrons.
-=-=-=-=-=-
Gravity doesn't exist. The Earth sucks.
-=-=-=-=-=-
Make a man a fire, and he will be warm for the night.
Light the man on fire, and he will be warm for the rest of his life.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
Comments
Now in your program, make a subroutine something like this:
Now all you have to do is make sure that the sub Handle_Timer is run at least 4-6 times per second and you'll get a pretty accurate counting clock. If your main loop is very fast, you can run it all the time. If you have routines that are slow within the loop, you might want to sprinkle calls to the sub throughout your program to make sure you don't miss the change in edge from the 2hz pulse.
To use it, you can either capture and store the current timer count and compare, or just wait for pre-determined intervals if timing is not critical, etc.:
There are also lots of cool ways you can extend and divide and use the timer for reasonably accurate time intervals. You can do a timer that will count full seconds by looking at BIT1 of the timer, or you can do stuff like
Now all that said, I use the SQWOUT pin from an RTC for doing this (like the DS1307) --- the RTC gives me a rock steady 1hz output, and I don't have the overhead of requesting seconds, mins, hours, and parsing them unless I actually need real clock time.
Does this make sense?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
In these examples, I'll use generic units of time. This should be the resolution of your timing. Bear in mind one hour is only 3600 seconds, and that while processing time is tiny, it can add up if you do too much. The smaller a unit is, the more precise you can make the timing, but the shorter the maximum time can be (due to the limits of variables). The larger a unit is, the more accurate you can make the timing (since the pause is a known time, and the other processing isn't known). A good unit size is essentially the greatest common factor among all your times.
Before programming:
1. Figure out the length of 1 unit.
2. Determine the timing for each relay, in units
When running:
1. Load the times, in units, into words (or if the units are large enough, like 2 units per minute, bytes) of RAM. I'd use an array, so I could use a for loop in step 3.
2. Begin a loop until all timing variables are 0.
3. For each of the memory spaces:
4. If the number is 1, TRIGGER.
5. If the number is not 0, decrease the memory value by one.
6. Go to the next variable (loop back to step 3).
7. Pause for 1 unit's time, in milliseconds.
8. Loop back to step 2.
That's basically it. That's a nice, straightforward way to do the timing, at the expense of destructively using a word (or byte) of RAM per relay.
But you didn't ask for a simple way. You asked for the best way. So here's a way that requires the destructive use of only two bytes of RAM at minimum (t and y) to control any number of relays:
Before programming:
1. Figure out the length of 1 unit.
2. Determine the timing for each relay, in units
3. Use a DATA statement to store the timing data into the EEPROM sequentially.
4. Use a constant (Offset) to store the offset of the timing data in EEPROM. This is 0 if you have no other DATA statements.
6. Use the "word" prefix as necessary with DATA and READ statements
When running:
1. Begin a loop.
2. Increase a timer variable t by one.
3. Read the data at (Offset) into a temporary variable y.
4. if t = y, TRIGGER.
5. Read the data at (Offset+1) into y.
6. if t = y, TRIGGER.
7. Read the data at (Offset+2) into y.
8. if t = y, TRIGGER.
...
9. pause for 1 unit's time
10. Loop back to step 1.
At the expense of another variable (probably a nibble will do), here called x, you can substitute a for loop as follows:
When running:
1. Begin a loop.
2. Increase a timer variable t by one.
3. for x = 0 to n
3. Read the data at (Offset + x) into a temporary variable y.
4. if t = y, TRIGGER.
5. NEXT x
6. pause for 1 unit's time
7. Loop back to step 1.
You're on a BS2. You have 16 words of RAM that can be used, 12 words of which can be used easily. Obviously, if you choose your unit length so that nothing will ever exceed 255, you can store your data in bytes and save RAM.
EDIT: As mentioned in the post above, adjust the PAUSE statements to compensate for processing time, if it's more that half a millisecond.
Also, I apologize for the crappy formatting of this post (the lack of code blocks)... I knew it'd be long, so I typed it up in notepad.
Post Edited (Sarten-X) : 3/25/2007 3:00:36 AM GMT
Yes, I have successfully attached relay's to my BS's using a transistor... I like to use the darlington arrays with built in diodes, when I have this many relays, or even if I have 2-3 relays. But I appreciate the warning!
I think I'm likely to go with a RTC, even though I originally stated against it. I just felt that using a RTC to calculate a small 5-10 second relay doesn't seem like a decent idea, that's why I went ahead and asked for help on the forums. I intend to use the RTC to activate relays at a set time, 1:00 AM.
*1) I need to activate a servo at 1:00 AM.
*2) I need to activate a relay for 15 minutes when a contact switch is pressed.
*3) I need to monitor how long a line is held high. (Monitor how long a motor is turn on and running.)
On some gasoline generators, I've seen a analog meter that says how long the generator has ran in it's entire life. Kind of like a odometer for a generator, I need to duplicate this in the third need. I figure I'll use some form of timing method that everyone has presented already for this requirement.
The application is a 50-60 gallon air compressor. I need to purge out the condensation in the bottom of the tank. (First need) Also I need to engage a solenoid (using a relay) to turn on the flow of air when a user needs to use the air, that's the second need.
I actually asked the question fairly vague, because I wanted the answer to work for about three projects...and it has. Both suggestions are going to be implemented.
As for the solutions presented:
Both Mike and Sarten,
I greatly appreciate the information you provided, while it didn't help me in figuring out this project, it did help me in some other parts of a different project. [noparse]:D[/noparse] Where I'll need slightly more precision. (Around 1-2 seconds, again, lots of leeway.)
I think that solution would require me to time my routines and adjust my pause statements to reflect the amount of time that my subroutines take...that sounds like alot of trial and error, and I'm a really lazy kinda person.
Since I'm going to go with a RTC anyways, for the 1:00 AM call, I think it'd be best to do what Zoot suggested and use a 555 or my RTC to provide a 1hz signal that a subroutine looks at.
Zoot,
It actually made perfect sense. I think because I already had something like this in my mind, I just didn't know how to implement it.
As for the connection to the SWQOUT pin, I own a Parallax PDB, I assume I could just connect directly the SQW line directly into a pin on the stamp without any passive components, is that correct?... I assume I should also use a pull-up or pull-down resistor, but other then that, nothing else should be needed right? I havn't actually looked at the data sheet yet for the DS1307.
Knight.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
This message transmitted with 100% recycled electrons.
-=-=-=-=-=-
Gravity doesn't exist. The Earth sucks.
-=-=-=-=-=-
Make a man a fire, and he will be warm for the night.
Light the man on fire, and he will be warm for the rest of his life.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
The reason I wanted the odometer is more for function... I need the BS2 to detect a runaway motor, but I don't really care about how long it's ran for it's lifetime, I was just using the generator's as a example. I do appreciate the simplicity of a manual odometer though... no eeprom writes, and no problems with battery backup... I read somewhere though that with a brand new CR2032 battery, a DS1307 would exhaust usable power from the battery in something like ten years... I don't think that'll be an issue for it, and I'll use the scratchpad memory on the DS1307 for the odometer readings, so I won't have to worry about killing my EEProm. But again, thanx.
Much thanx, Zoot, I'll just read the datasheet.
Knight.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-
This message transmitted with 100% recycled electrons.
-=-=-=-=-=-
Gravity doesn't exist. The Earth sucks.
-=-=-=-=-=-
Make a man a fire, and he will be warm for the night.
Light the man on fire, and he will be warm for the rest of his life.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-