![]() |
Forum Index : Microcontroller and PC projects : How to drive 13 relays.
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
I hope that everyone here had an enjoyable Christmas! I need to drive 13 relays at a distance of about 20 feet. The relays are on the 8 relay boards commonly available from China, complete with optocouplers and driver circuits. Each board has 8 input pins which could be driven directly by 8 uM digital output pins plus pins for a separate 5v or 12v power supply and ground. I am running out of output pins on the uM E100 board. The required interface speed is very slow. All 13 relays only need to be updated about twice every second. I would like to try to send a serial bit stream to two daisy chained shift registers with latching outputs on a support board about 20 feet from the E100 uM board and let the shift registers outputs control the relay board inputs. I suppose either the TPIC6B595 or the 74HC495B would be applicable. My first problem is that I am not sure if the SPI functions will work. SPI was intended for short distance communication. At a distance of 20 feet I believe the bit stream might get scrambled. So, will SPI work over a 20 foot distance and how slow should the SPI clock speed be set? My second problem is that I am not sure what the best substitute for the SPI protocol would be. I could program a separate 44 pin uM to read s string from a serial buffer and then extract individual characters from the string using MID$() and use them to set each of 13 individual output pins. But, I don't really want to use a programmed uM in an inaccessible location where it would be inconvenient to load or modify the program. So, should I switch to using uni-directional buffered serial sent blind with no acknowledgement or handshaking to a second uM 44 pin chip running an MMbasic program? My third problem is that I can't see an easy way to set individual bits in a 13 bit (or 16 bit) word (like &B 0000 0000 0000 0000) in response to the state of 13 individual MMbasic Boolean variables. I don't believe that MMbasic provides any way to set or clear an individual bit in a string variable (probably 2 characters long). If I pre-define an array to contain every possible combination and select one there will be 2^13 choices or 8192. Similarly I don't believe there is any MMbasic procedure which will evaluate or expand a string like "0101010101010101" into a binary number like &B0101010101010101. So, how do I get those 13 individual Boolean variables into the bit string? Paul in NY |
||||
Zonker![]() Guru ![]() Joined: 18/08/2012 Location: United StatesPosts: 767 |
Humm... I think I would like the "Remote MM' approach.. That way you could set it up with a simple ASCII type protocol, possibly using Rs-485, and use it for input and output port IO.. If needed, you could also set it up with a known startup pattern of on and off settings for the relay outputs... ![]() |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3282 |
For example, to set bit six: nbr% = nbr% OR (1<<6) Geoff Graham - http://geoffg.net |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
There is no direct way to manipulate a character in a string. You could use a left$ and right$ to get the parts left and right of the 'bit' that you want to change and then add them together again. I remember Visual Basic had a MID statement which could replace characters in a string by giving the location and optional length. Might be a nice addition to consider. Microblocks. Build with logic. |
||||
robert.rozee Guru ![]() Joined: 31/12/2012 Location: New ZealandPosts: 2429 |
pascal/delphi uses square bracketed references to access individual characters. translating into mmbasic-talk: a$[5] is the 5th character in a$ a$[0] is the length of a$ a$[7] = chr$(65) would change the 7th character of a$ into an "A" print a$[7] would be equivalent to print mid$(a$,7), while a$[7] = chr$(65) would be equivalent to a$ = left$(a$,6)+chr$(65)+mid$(a$,8) another approach would be to allow assignments to len(a$) and mid$(a$, n) to change length and any single character respectively. geoff: how easy would either approach be to implement? and how palatable as an extension to the language? cheers, rob :-) |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
@Geoff - Thanks, but I don't understand your example of bitwise manipulation. Where old.nbr%=&B0000 0000 0000 0000 1 << 6 means you shift &B0000 0000 0000 0001 left six places to become &B0000 0000 0100 0000 Then you OR (bitwise multiplication) it with old.nbr% 1<<6 = &B0000 0000 0100 0000 old.nbr% = &B0000 0000 0000 0000 new.nbr% = &B0000 0000 0000 0000 You made no change in old.nbr%. And where old.nbr%=&B0000 0000 0100 0000 When you OR 1<<6 with old.nbr% 1<<6 = &B0000 0000 0100 0000 oldnbr% = &B0000 0000 0100 0000 newnbr% = &B0000 0000 0100 0000 Again, you made no change in old.nbr%. I must be dense but I don't get it. Paul_L |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9589 |
You're not dense. Bit manipulation confuses the hell out of me too. ![]() ![]() I'll be interested in the replies to this - maybe I can learn something too. ![]() Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6269 |
Paul, are you testing this with recent version of MMBasic. V4.5 or earlier doesn't have integers so the precision required for 16 bits is not there. The above was run on a V5.2 micromite (my MMEdit test server which you can access from the comfort of your couch while watching the cricket. Jim VK7JH MMedit |
||||
bigmik![]() Guru ![]() Joined: 20/06/2011 Location: AustraliaPosts: 2949 |
Hi Paul, As most would know, I am not really any good at software coding but I would approach this along this line.. Set your relays as you need them (0=off or 1=on) Rly1=1 Rly2=0 Rly3=0 . . . . Rly13=1 Then call a subroutine (I would use GOSUB but the programmers would probably use a function or SUB. GOSUB Set_Rlys: Set_Rlys: New_Byte=(Rly13 * 8192)+(Rly12 * 4096)+(Rly11 * 2048) ........... + (Rly2 * 2) + Rly1 RETURN If the total exceeds the max line length then split into 2 or 3 lines Kind Regards, (and apologies if not a good method) Mick Mick's uMite Stuff can be found >>> HERE (Kindly hosted by Dontronics) <<< |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
@Zonker - I like the idea of using a second MM as well, I could pass it this string A$="nnnYnnnY...Y-" indicating that relays 4, 8 and 12 were to be pulled in. I could then test A$ with MID$()to find the "Y"s. BUT .... the second MM will be inaccessible stuck up between joists in the basement. If it malfunctions somehow and requires re-programming it will be a real pain. It would be lovely if I could somehow remotely modify or re-load its program but I don't know how that could be done. Any suggestions. @MicroBlocks -- @robert.rozee -- I don't regard the lack of a MID statement or pascal/delphi's square brackets as being terribly inconvenient because we can easily build a transmission string to control 13 pumps from an array like this: buildTRstring: 'receives boolean globals p1 through p13, sets global tr$ LOCAL A$(13) LENGTH 1 ' the variables, set elsewhere, which control the pumps are now set if p1 then A$(1)="Y" ' set each A$(2..12) here if p13 then A$(13)="Y" tr$="": for i=1 to 13 : tr$=tr$+A$(i) : next endsub 'buildTRstring decodeTRstring: 'receives global tr$, operates pumps LOCAL pins(13)=nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn ' output pins to pump relays for i=1 to 13 if tr$(i)="Y" then PIN(pins(i))=1 else PIN(pins(i))=0 endif next endsub 'decodeTRstring Have you got any suggestions about easy ways to re-program the remote uM? Paul in NY |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
Jim, you're right, I'm wrong. I'm doing bitwise boolean in my head. I don't have a uM here. I got it backwards. A bitwise AND multiplies the bits together like this 0000000000000000 AND 0000000001000000 gives 0000000000000000 A bitwise OR does a logical inclusive OR on each pair of bits so that the result is 0 if both bits are 0 otherwise the result is 1 like this 0000000000000000 OR 0000000001000000 gives 0000000001000000 I think I've got it. I think I've got it. This might make it possible to use the shift register approach instead of a remote uM with the attendant programming difficulties. Thanks! What about my other reservations about communicating with the shift register. At a distance of 20 feet I believe that an SPI bit stream might get scrambled. Will SPI work over a 20 foot distance if I set the SPI clock speed very low? Or can I send a buffered serial stream blind with no acknowledgement or handshaking to the shift register and somehow clock the shift register? How do I access your test server from the comfort of my couch? It would be great to be able to test these things myself. Just when you got me straightened out you had to bring up cricket again, didn't you. Now I can't decide whether to sign off as Paul or Pavel Artur Jan Waclaw Lepkowski. I don't want anyone to confuse me with the other Paul, so I'll just say .... Paul in NY |
||||
Zonker![]() Guru ![]() Joined: 18/08/2012 Location: United StatesPosts: 767 |
Hep Paul... I don't think a remote MM, even if it's hard to get at is that big of a deal... The simplest way is to just string a USB cable to it and leave it "hang down" so you could get to it if needed... You could "get fancy" and add either a Blue-tooth or WiFi adapter to the console port and get access through the radio... You could then transmit out current status updates... You could also add a relay feedback circuit that checks if the relay is following your commands... If it becomes defective, (open coil, stuck contacts, ect..) the MM would report the defect back to the controller... Just some thoughts and head scratchin... ![]() |
||||
VK2MCT Senior Member ![]() Joined: 30/03/2012 Location: AustraliaPosts: 120 |
I like the idea of a remote MM (Micromite has enough control pins) Suggest using RS232. (via buffers maybe) I'd go for 4 bits of a word being for which relay and another bit for on/off. I would send each command thrice. The remote MM needs to get the same 3 consecutive words before activating a relay. (noise immunity) You will also need to consider pullups/downs so that startup is elegant. How much current for control do the relay boards need? John B VK2MCT |
||||
Paul_L Guru ![]() Joined: 03/03/2016 Location: United StatesPosts: 769 |
Hi John B If I do decide to use a remote uM I would probably just send a character string and forget about bit manipulation. Repeating each command sounds like a good idea. The relay boards are the cheap ones with the integrated opto-couplers and driver circuits so the input current is minimal. Paul in NY |
||||
robert.rozee Guru ![]() Joined: 31/12/2012 Location: New ZealandPosts: 2429 |
you could just connect up to the console, leaving the remote micromite sitting at the command prompt, and send text commands of the form: PIN(n) = value no programming at the remote end is required, and even an MX150 would do the job just fine. cheers, rob :-) |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3282 |
There are some MMBasic bit manipulation functions here: http://fruitoftheshed.com/MMBasic.Bit-Manipulation-Functions.ashx EDIT: I have just noticed that the parameters and functions in that library entry should be declared integers, as follows: FUNCTION BitSet(value AS INTEGER, bit AS INTEGER) AS INTEGER BitSet=value OR (2^bit) END FUNCTION FUNCTION BitRes(value AS INTEGER, bit AS INTEGER) AS INTEGER BitRes=(value OR (2^bit)) XOR (2^bit) END FUNCTION FUNCTION BitTest(value AS INTEGER, bit AS INTEGER) AS INTEGER BitTest=SGN(value AND (2^bit)) END FUNCTION Geoff Geoff Graham - http://geoffg.net |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
corrected - cheers |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
You could also use an array to hold the on/off state of a relay. Changing any relay can be done by using its index in de array. If you want to have them combined in a single string you can then append each value from the array to that string. Microblocks. Build with logic. |
||||
VK2MCT Senior Member ![]() Joined: 30/03/2012 Location: AustraliaPosts: 120 |
The 74HC495B option would require 3 wires plus power to the remote. The 3 wires can be easily programmed, manipulating MM pins 'manually' rather than SPI. John B |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6269 |
Paul, 6 meters (I use metric to confuse you) is short for RS232. I use MAX2323 modules at each end to give better noise immunity than TTL. If you use the console port on the 'remote' micromite, you can easily get to the 'local' end and switch it from the master micromite to a USB adapter and program it without having to pull the house apart. You just have to be careful that your program doesn't send a ctrl-C while running. Jim VK7JH MMedit |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |