Well, take a look at this video. It is an Altair 8800 work-alike made from a CGColorMax2!
Thank you, Stringfellow!
Electronic Products for Creative Minds
Well, take a look at this video. It is an Altair 8800 work-alike made from a CGColorMax2!
Thank you, Stringfellow!
Code (BASIC) to control 16 relays
In the earlier parts, we set up the ColorMax (modern design retro computer) to make use of an Arduino relay shield. Now for the BASIC software that will control the start and stop times for 16 relays. The image below is the hardware.
The code starts with mapping the 16 relays to pins on the shield header on the top of the CGCOLORMAX board. Relays 1-4 map to pins 25-28. Other pins are set to 21 until such a time that more relay shields are added. A loop sets all of the defined relay pins to be outputs and then assigns them their initial values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
DIM RlyPin(32) RlyPin(0) = 25 RlyPin(1) = 26 RlyPin(2) = 27 RlyPin(3) = 28 RlyPin(4) = 21 RlyPin(5) = 21 RlyPin(6) = 21 RlyPin(7) = 21 RlyPin(8) = 21 RlyPin(9) = 21 RlyPin(10) = 21 RlyPin(11) = 21 RlyPin(12) = 21 RlyPin(13) = 21 RlyPin(14) = 21 RlyPin(15) = 21 FOR rloop = 0 to 15 SETPIN RlyPin(rloop), DoUt Pin(RlyPin(rloop)) = RelayState(rloop) NEXT rloop |
The relay state array is set up at the beginning of the code with initial values. The relay names are set up in a table. (code could be improved to make these names something that the user could edit.) And
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
DIM RelayState(15) RelayState(0) = 0 RelayState(1) = 0 RelayState(2) = 1 RelayState(3) = 1 RelayState(4) = 0 RelayState(5) = 0 RelayState(6) = 0 RelayState(7) = 0 RelayState(8) = 0 RelayState(9) = 0 RelayState(10) = 1 RelayState(11) = 1 RelayState(12) = 0 RelayState(13) = 0 RelayState(14) = 0 RelayState(15) = 0 DIM RelayName$(15) ' "******************" RelayName$(0) = "Relay One " RelayName$(1) = "Relay Two " RelayName$(2) = "Relay Three " RelayName$(3) = "Relay Four " RelayName$(4) = "Relay Five " RelayName$(5) = "Relay Six " RelayName$(6) = "Relay Seven " RelayName$(7) = "Relay Eight " RelayName$(8) = "Relay Nine " RelayName$(9) = "Relay Ten " RelayName$(10) = "Relay Eleven " RelayName$(11) = "Relay Twelve " RelayName$(12) = "Relay Thirteen " RelayName$(13) = "Relay Forteen " RelayName$(14) = "Kitchen Lamp " RelayName$(15) = "Warp Drive " ' "******************" DIM RlyTime$(32) RlyTime$(0) = "12:00:00" RlyTime$(1) = "12:00:00" RlyTime$(2) = "12:00:00" RlyTime$(3) = "12:00:00" RlyTime$(4) = "12:00:00" RlyTime$(5) = "12:00:00" RlyTime$(6) = "12:00:00" RlyTime$(7) = "12:00:00" RlyTime$(8) = "12:00:00" RlyTime$(9) = "12:00:00" RlyTime$(10) = "12:00:00" RlyTime$(11) = "12:00:00" RlyTime$(12) = "12:00:00" RlyTime$(13) = "12:00:00" RlyTime$(14) = "12:00:00" RlyTime$(15) = "12:00:00" RlyTime$(16) = "15:00:00" RlyTime$(17) = "15:00:00" RlyTime$(18) = "15:00:00" RlyTime$(19) = "15:00:00" RlyTime$(20) = "15:00:00" RlyTime$(21) = "15:00:00" RlyTime$(22) = "15:00:00" RlyTime$(23) = "15:00:00" RlyTime$(24) = "15:00:00" RlyTime$(25) = "15:00:00" RlyTime$(26) = "15:00:00" RlyTime$(27) = "15:00:00" RlyTime$(28) = "15:00:00" RlyTime$(29) = "15:00:00" RlyTime$(30) = "15:00:00" RlyTime$(31) = "15:00:00" |
Some flags and variables are set up before the main code is run. SelectedRelay has the values of 0 to 15 to select the relay for editing, and the odd value of 95 for disabling editing.
SelectStartStop is 0 for editing the start/on times, and 1 for editing the stop/off times.
Following that are flags that tell the software that the user has hit H for incrementing 10s of hours with the H key, 1s of hours for the h key, 10s and 1s of minutes and seconds with the M, m, S, and s keys.
1 2 3 4 5 6 7 8 |
SelectedRelay = 95 SelectStartStop = 0 H10 = 0 h1 = 0 M10 = 0 m1 = 0 S10 = 0 s1 = 0 |
Just before the main loop of code is run, the screen mode is set up, lines drawn on the screen, and then operating key information os printed on the bottom of the screen.
1 2 3 4 5 6 7 8 |
MODE 4 cls COLOR WHITE LINE (0,12)-(238,12) LINE (0,191)-(238,191) COLOR YELLOW PRINT @(0,194)"(R)elay# Star(t) Sto(p) (Q)uit edit" PRINT @(0,205)"(H/h)ours (M/m)inutes (S/s)econds " |
This is the main DO…LOOP for the code. If a key is pressed, a flag is set for processing in a subroutine.
The Update subroutine updates the center part of the display and the Activate subroutine sets the relays on or off.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
DO command$ = INKEY$ IF command$ = "" THEN 'Do nothing ELSEIF command$ = "z" THEN SAVEBMP "scrcap.bmp" ELSEIF command$ = "Q" OR command$ = "q" THEN SelectedRelay = 95 ELSEIF command$ = "R" OR command$ = "r" THEN SelectedRelay = (SelectedRelay + 1) MOD 16 ELSEIF SelectedRelay <> 95 THEN IF command$ = "T" THEN SelectStartStop = 0 ELSEIF command$ = "t" THEN SelectStartStop = 0 ELSEIF command$ = "P" THEN SelectStartStop = 1 ELSEIF command$ = "p" THEN SelectStartStop = 1 ELSEIF command$ = "H" THEN H10 = 1 ELSEIF command$ = "h" THEN h1 = 1 ELSEIF command$ = "M" THEN M10 = 1 ELSEIF command$ = "m" THEN m1 = 1 ELSEIF command$ = "S" THEN S10 = 1 ELSEIF command$ = "s" THEN s1 = 1 ENDIF ENDIF Update Activate LOOP |
The time is constantly updated.
When a relay is selected a “>” is located next to the relay name, and next to either the on or off times, depending on which needs to be edited. When relays are not selected or edited, the > disappears.
The bulk of the routine deals with incrementing the right data when a key is pressed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
'Update display SUB Update() 'Show current time COLOR CYAN PRINT @(190,0) TIME$ FOR rloop = 0 to 15 RlyArrow$ = " " : OnArrow$ = " " : OffArrow$ = " " IF RelayState(rloop) = 0 THEN COLOR RED ELSE COLOR GREEN IF SelectedRelay = rloop THEN RlyArrow$ = ">" IF SelectStartStop = 0 THEN OnArrow$ = ">" IF SelectStartStop = 1 THEN OffArrow$ = ">" ENDIF PRINT @(0,14+(rloop*11)) FORMAT$(rloop + 1, "%2g") RlyArrow$ RelayName$(rloop) OnArrow$ IF MID$(RlyTime$(rloop), 1, 1) = "0" THEN PRINT @(132,14+(rloop*11)) " " MID$(RlyTime$(rloop), 2, 7) OffArrow$ ELSE PRINT @(132,14+(rloop*11)) MID$(RlyTime$(rloop), 1, 8) OffArrow$ ENDIF IF MID$(RlyTime$(rloop+16), 1, 1) = "0" THEN PRINT @(186,14+(rloop*11)) " " MID$(RlyTime$(rloop+16), 2, 7) ELSE PRINT @(186,14+(rloop*11)) MID$(RlyTime$(rloop+16), 1, 8) ENDIF NEXT rloop IF SelectedRelay <> 95 THEN SRelay = SelectedRelay IF SelectStartStop = 1 THEN SRelay = SelectedRelay + 16 ENDIF IF H10 = 1 THEN H10 = 0 tmp = Val(MID$(RlyTime$(SRelay), 1, 1)) tmp = (tmp + 1) IF tmp = 3 THEN tmp = 0 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 1) + STR$(0) + MID$(RlyTime$(SRelay), 3, 6) ENDIF RlyTime$(SRelay) = STR$(tmp) + MID$(RlyTime$(SRelay), 2, 7) ENDIF IF h1 = 1 THEN h1 = 0 tmp = Val(MID$(RlyTime$(SRelay), 2, 1)) tmp = (tmp + 1) MOD 10 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 1) + STR$(tmp) + MID$(RlyTime$(SRelay), 3, 6) ENDIF IF M10 = 1 THEN M10 = 0 tmp = Val(MID$(RlyTime$(SRelay), 4, 1)) tmp = (tmp + 1) MOD 6 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 3) + STR$(tmp) + MID$(RlyTime$(SRelay), 5, 4) ENDIF IF m1 = 1 THEN m1 = 0 tmp = Val(MID$(RlyTime$(SRelay), 5, 1)) tmp = (tmp + 1) MOD 10 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 4) + STR$(tmp) + MID$(RlyTime$(SRelay), 6, 3) ENDIF IF S10 = 1 THEN S10 = 0 tmp = Val(MID$(RlyTime$(SRelay), 7, 1)) tmp = (tmp + 1) MOD 6 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 6) + STR$(tmp) + MID$(RlyTime$(SRelay), 8, 1) ENDIF IF s1 = 1 THEN s1 = 0 tmp = Val(MID$(RlyTime$(SRelay), 8, 1)) tmp = (tmp + 1) MOD 10 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 7) + STR$(tmp) ENDIF ENDIF END SUB |
The Activate subroutine compares current time against the on time and off time. The internal relay state as well as the actual activation output is set to on or off.
1 2 3 4 5 6 7 8 9 10 11 12 |
SUB Activate() FOR rloop = 0 to 15 IF TIME$ = RlyTime$(rloop) THEN Pin(RlyPin(rloop)) = 1 RelayState(rloop) = 1 ENDIF IF TIME$ = RlyTime$(rloop+16) THEN PIN(RlyPin(rloop)) = 0 RelayState(rloop) = 0 ENDIF NEXT rloop END SUB |
The relay is off…
And now on…
This example software doesn’t allow for user editing of the relay descriptions and it doesn’t save the times and states. But the SD card is there and that is straight-forward to add.
The full program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
'Initial information DIM RlyPin(15) RlyPin(0) = 25 RlyPin(1) = 26 RlyPin(2) = 27 RlyPin(3) = 28 RlyPin(4) = 21 RlyPin(5) = 21 RlyPin(6) = 21 RlyPin(7) = 21 RlyPin(8) = 21 RlyPin(9) = 21 RlyPin(10) = 21 RlyPin(11) = 21 RlyPin(12) = 21 RlyPin(13) = 21 RlyPin(14) = 21 RlyPin(15) = 21 DIM RelayState(15) RelayState(0) = 0 RelayState(1) = 0 RelayState(2) = 1 RelayState(3) = 1 RelayState(4) = 0 RelayState(5) = 0 RelayState(6) = 0 RelayState(7) = 0 RelayState(8) = 0 RelayState(9) = 0 RelayState(10) = 1 RelayState(11) = 1 RelayState(12) = 0 RelayState(13) = 0 RelayState(14) = 0 RelayState(15) = 0 DIM RelayName$(15) ' "******************" RelayName$(0) = "Relay One " RelayName$(1) = "Relay Two " RelayName$(2) = "Relay Three " RelayName$(3) = "Relay Four " RelayName$(4) = "Relay Five " RelayName$(5) = "Relay Six " RelayName$(6) = "Relay Seven " RelayName$(7) = "Relay Eight " RelayName$(8) = "Relay Nine " RelayName$(9) = "Relay Ten " RelayName$(10) = "Relay Eleven " RelayName$(11) = "Relay Twelve " RelayName$(12) = "Relay Thirteen " RelayName$(13) = "Relay Forteen " RelayName$(14) = "Kitchen Lamp " RelayName$(15) = "Warp Drive " ' "******************" DIM RlyTime$(32) RlyTime$(0) = "12:00:00" RlyTime$(1) = "12:00:00" RlyTime$(2) = "12:00:00" RlyTime$(3) = "12:00:00" RlyTime$(4) = "12:00:00" RlyTime$(5) = "12:00:00" RlyTime$(6) = "12:00:00" RlyTime$(7) = "12:00:00" RlyTime$(8) = "12:00:00" RlyTime$(9) = "12:00:00" RlyTime$(10) = "12:00:00" RlyTime$(11) = "12:00:00" RlyTime$(12) = "12:00:00" RlyTime$(13) = "12:00:00" RlyTime$(14) = "12:00:00" RlyTime$(15) = "12:00:00" RlyTime$(16) = "15:00:00" RlyTime$(17) = "15:00:00" RlyTime$(18) = "15:00:00" RlyTime$(19) = "15:00:00" RlyTime$(20) = "15:00:00" RlyTime$(21) = "15:00:00" RlyTime$(22) = "15:00:00" RlyTime$(23) = "15:00:00" RlyTime$(24) = "15:00:00" RlyTime$(25) = "15:00:00" RlyTime$(26) = "15:00:00" RlyTime$(27) = "15:00:00" RlyTime$(28) = "15:00:00" RlyTime$(29) = "15:00:00" RlyTime$(30) = "15:00:00" RlyTime$(31) = "15:00:00" SelectedRelay = 95 SelectStartStop = 0 H10 = 0 h1 = 0 M10 = 0 m1 = 0 S10 = 0 s1 = 0 MODE 4 cls COLOR WHITE LINE (0,12)-(238,12) LINE (0,191)-(238,191) COLOR YELLOW PRINT @(0,194)"(R)elay# Star(t) Sto(p) (Q)uit edit" PRINT @(0,205)"(H/h)ours (M/m)inutes (S/s)econds " FOR rloop = 0 to 15 SETPIN RlyPin(rloop), DoUt Pin(RlyPin(rloop)) = RelayState(rloop) NEXT rloop DO command$ = INKEY$ IF command$ = "" THEN 'Do nothing ELSEIF command$ = "z" THEN SAVEBMP "scrcap.bmp" ELSEIF command$ = "Q" OR command$ = "q" THEN SelectedRelay = 95 ELSEIF command$ = "R" OR command$ = "r" THEN SelectedRelay = (SelectedRelay + 1) MOD 16 ELSEIF SelectedRelay <> 95 THEN IF command$ = "T" THEN SelectStartStop = 0 ELSEIF command$ = "t" THEN SelectStartStop = 0 ELSEIF command$ = "P" THEN SelectStartStop = 1 ELSEIF command$ = "p" THEN SelectStartStop = 1 ELSEIF command$ = "H" THEN H10 = 1 ELSEIF command$ = "h" THEN h1 = 1 ELSEIF command$ = "M" THEN M10 = 1 ELSEIF command$ = "m" THEN m1 = 1 ELSEIF command$ = "S" THEN S10 = 1 ELSEIF command$ = "s" THEN s1 = 1 ENDIF ENDIF Update Activate LOOP 'Update display SUB Update() 'Show current time COLOR CYAN PRINT @(190,0) TIME$ FOR rloop = 0 to 15 RlyArrow$ = " " : OnArrow$ = " " : OffArrow$ = " " IF RelayState(rloop) = 0 THEN COLOR RED ELSE COLOR GREEN IF SelectedRelay = rloop THEN RlyArrow$ = ">" IF SelectStartStop = 0 THEN OnArrow$ = ">" IF SelectStartStop = 1 THEN OffArrow$ = ">" ENDIF PRINT @(0,14+(rloop*11)) FORMAT$(rloop + 1, "%2g") RlyArrow$ RelayName$(rloop) OnArrow$ IF MID$(RlyTime$(rloop), 1, 1) = "0" THEN PRINT @(132,14+(rloop*11)) " " MID$(RlyTime$(rloop), 2, 7) OffArrow$ ELSE PRINT @(132,14+(rloop*11)) MID$(RlyTime$(rloop), 1, 8) OffArrow$ ENDIF IF MID$(RlyTime$(rloop+16), 1, 1) = "0" THEN PRINT @(186,14+(rloop*11)) " " MID$(RlyTime$(rloop+16), 2, 7) ELSE PRINT @(186,14+(rloop*11)) MID$(RlyTime$(rloop+16), 1, 8) ENDIF NEXT rloop IF SelectedRelay <> 95 THEN SRelay = SelectedRelay IF SelectStartStop = 1 THEN SRelay = SelectedRelay + 16 ENDIF IF H10 = 1 THEN H10 = 0 tmp = Val(MID$(RlyTime$(SRelay), 1, 1)) tmp = (tmp + 1) IF tmp = 3 THEN tmp = 0 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 1) + STR$(0) + MID$(RlyTime$(SRelay), 3, 6) ENDIF RlyTime$(SRelay) = STR$(tmp) + MID$(RlyTime$(SRelay), 2, 7) ENDIF IF h1 = 1 THEN h1 = 0 tmp = Val(MID$(RlyTime$(SRelay), 2, 1)) tmp = (tmp + 1) MOD 10 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 1) + STR$(tmp) + MID$(RlyTime$(SRelay), 3, 6) ENDIF IF M10 = 1 THEN M10 = 0 tmp = Val(MID$(RlyTime$(SRelay), 4, 1)) tmp = (tmp + 1) MOD 6 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 3) + STR$(tmp) + MID$(RlyTime$(SRelay), 5, 4) ENDIF IF m1 = 1 THEN m1 = 0 tmp = Val(MID$(RlyTime$(SRelay), 5, 1)) tmp = (tmp + 1) MOD 10 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 4) + STR$(tmp) + MID$(RlyTime$(SRelay), 6, 3) ENDIF IF S10 = 1 THEN S10 = 0 tmp = Val(MID$(RlyTime$(SRelay), 7, 1)) tmp = (tmp + 1) MOD 6 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 6) + STR$(tmp) + MID$(RlyTime$(SRelay), 8, 1) ENDIF IF s1 = 1 THEN s1 = 0 tmp = Val(MID$(RlyTime$(SRelay), 8, 1)) tmp = (tmp + 1) MOD 10 RlyTime$(SRelay) = MID$(RlyTime$(SRelay), 1, 7) + STR$(tmp) ENDIF ENDIF END SUB SUB Activate() FOR rloop = 0 to 15 IF TIME$ = RlyTime$(rloop) THEN Pin(RlyPin(rloop)) = 1 RelayState(rloop) = 1 ENDIF IF TIME$ = RlyTime$(rloop+16) THEN PIN(RlyPin(rloop)) = 0 RelayState(rloop) = 0 ENDIF NEXT rloop END SUB |
Adding a relay interface shield to the ColorMax
In part 1 it was mentioned that the ColorMax is a great (modern design) retrocomputer for interfacing to the real world. Using the Arduino Shield area on top of the ColorMax, it is easy to interface to a relay module shield.
Pictured are two relay shields that I pulled from my collection. They both control 4 relays and they both use the same lines to do so. I had really hoped that they would use different lines so that I could stack them and control 8 (or even 16) relays total. It would have been great if the design of the relay board could have included some option to select other control lines.
The front board uses “D4 through D7” (Arduino nomenclature) to turn the relays on and off. Translating to the ColorMax pin numbers, the control lines are 25, 26, 27, and 28. The “translation” from Arduino numbering to ColorMax numbering is here: https://circuitgizmos.com/documentation/hardware-datasheets/cgcolormax2-technical-information/cgcolormax2-pin-outs-and-functions/
So here is my setup for this article. A VGA monitor and a small PS2 keyboard attached to a ColorMax (on an anti-static platform). The Arduino Shield footprint on the ColorMax is populated with headers to accept the Relay Shield. The ColorMax is powered by a 12V supply and connected to a PC via USB.
With the ColorMax bare naked, the relay board is installed onto the headers. That leaves the relay board ready for control by BASIC.
The simplest way to check out the operation of the relays is to use the immediate mode of basic (and the VGA display with PS2 keyboard) to set the control line direction to output and then write a 1 to turn the relay on and 0 to turn it off. At the basic prompt on the VGA
1 |
SETPIN 25,8 |
The relay turned on with:
1 |
PIN(25) = 1 |
And turned off with:
1 |
PIN(25) = 0 |
Next blog: PC control.