I have always found it interesting to consider the computer not only as an independent entity, but also able to control other equipment. It is possible to control the Commodore 64 User Port for this purpose: that is, to integrate the computer with the surrounding environment.
I had already done some experiments to connect the Commodore 64 to the home automation system: in that experiment, the User Port was in fact used to communicate with a WiFi modem.
In the experiment in this article, however, the PB0-PB7 pins of the Commodore 64 User Port are used directly to control two interface cards.
Commodore 64 User Port interface cards
There are different types of interfaces to connect to the Commodore 64 User Port. In this article I therefore describe:
- an output card with 4 relays, optically isolated;
- an input interface, with 4 optocouplers.
The interfaces are used to command loads and to acquire states. The card with 4 relays can be used to control high and low voltage loads. On the contrary, the opto-isolated input card can only be used to measure the presence of mains voltage. Of course, there are also low voltage versions.
User Port Inputs and Outputs
For fans of theory, here are some schemes! Of the Commodore 64 User Port, we will use only the 8 pins of port B: pins PB0, PB1, PB2, PB3, PB4, PB5, PB6 and PB7. For this they are abbreviated with PB0-PB7. The PB port is connected to the C, D, E, F, H, J, K and L pins of the User Port. Attention must be paid to the fact that on the blue connectors that are purchased to interface with the User Port (3.96mm edge type with 24 poles), the letters are not the same as those of the User Port. Therefore the pins must be identified manually.
The PB0-PB7 pins of the User Port, as can be seen from the diagram obtained from the Commodore 64 Service Manual, are directly connected to the CIA U2 chip of the Commodore 64: the MOS 6526, whose datasheet is attached at the end of this article.
The MOS 6526 is a chip in NMOS technology, so it is able to deliver a satisfactory current only on logic level 0. In other words, it is as if it behaves like a small switch to ground. On logic level 1 it is not possible to draw a satisfactory current, but it should be considerably amplified.
For this reason, the card with 4 relays (optically isolated) activates the outputs when the corresponding input is brought to ground, with a current of at least 2 mA. The Commodore can deliver 3 mA, so the current is sufficient.
Just to make sure, the relays are powered by an external 5V power source, thus not loading and thus not dirtying the Commodore 64 power supply. From the User Port, therefore, we only take the signals and not the power supply.
As for the opposite direction, i.e. allowing the Commodore to read states or the presence of a voltage, here too it is advantageous to use schede optoisolate open collector. If there is voltage at the input of the optocoupler, the output of the card (and therefore the input pin of the Commodore 64 User Port), goes to ground. If there is no voltage at the input of the optocoupler, the output of the board remains free and therefore the input pin of the User Port is free to go to logic level 1, by means of the pull-up resistor (and also other circuits) already present inside the CIA chip (MOS 6526) of the computer.
Pins PB0-PB7 can be individually configured as inputs or as outputs. For convenience, I used PB0-PB3 pins as outputs and PB4-PB7 as inputs.
Basic commands for Commodore 64 User Port outputs
To control the inputs and outputs of the User Port from the Commodore, you can use simple instructions in Basic.
Relative to uscite a relay, it is possible to activate a relay using the command:
POKE 56579, numero
The value number essentially represents the output pin (or pins) to be activated, to be calculated with the powers of 2: 2 ^ (relay_number – 1).
To activate relay 1, pin PB0, number = 2^(1 – 1) = 2^0 = 1:
POKE 56579, 1
Activate relay 2, pin PB1, number = 2^(2 – 1) = 2^1 = 2:
POKE 56579, 2
To activate relay 3, pin PB2, number = 2^(3 – 1) = 2^2 = 4:
POKE 56579, 4
Finally, to activate relay 4, pin PB3, number = 2^(4 – 1) = 2^3 = 8:
POKE 56579, 8
If several relays are to be activated at the same time, the previously calculated values must be added together. For example, to activate relay 2 and relay 4, the command is:
POKE 56579, 10
The deactivation of the relay is obtained simply by subtracting the corresponding number. At the limit, to turn off all the relays, you can type:
POKE 56579, 0
Warning! Actually the command POKE 56579, number is used to set the pin of the PB port as the output! As soon as it is set as an output, the corresponding pin immediately goes to logic level 0 (to ground), therefore activates the relay.
In addition, all 7 pins of the PB port can be used as outputs. For convenience, I have only used the PB0-PB3 pins as outputs.
Basic commands for User Port inputs
With regard to the entered optoisolati, to read the value corresponding to the status of the inputs, use the following command:
PRINT PEEK(56577)
The returned value ranges from 0 to 255. Each input, when there is voltage, it leads to mass, therefore the corresponding bit goes to 0. To check, therefore, if there is voltage at the input of the optocoupler, you can proceed as follows:
IF ( PEEK(56577) AND 2 ^ (numero_fotoaccoppiatore + 4 - 1) ) = 0 THEN ...
The sum number_photocoupler + 4 it is because, in this experiment, optocouplers 1, 2, 3 and 4 are connected on PB4, PB5, PB6 and PB7. I also remember that the pins of the PB port go to logic 1 in the event of a power failure. Therefore, to verify the absence of voltage, simply remove “= 0” from the command.
Check the presence of voltage in the optocoupler 1 input, pin PB4:
IF ( PEEK(56577) AND 2 ^ 16 ) = 0 THEN …
No voltage:
IF ( PEEK(56577) AND 2 ^ 16 ) THEN …
To check the presence of photocoupler 2 input voltage, pin PB5:
IF ( PEEK(56577) AND 2 ^ 32 ) = 0 THEN …
No voltage:
IF ( PEEK(56577) AND 2 ^ 32 ) THEN …
Check the presence of voltage in the photocoupler 3 input, pin PB6:
IF ( PEEK(56577) AND 2 ^ 64 ) = 0 THEN …
No voltage:
IF ( PEEK(56577) AND 2 ^ 64 ) THEN …
Finally, to check the presence of photocoupler 4 input voltage, pin PB7:
IF ( PEEK(56577) AND 2 ^ 128 ) = 0 THEN …
No voltage:
IF ( PEEK(56577) AND 2 ^ 128 ) THEN …
Using the inputs of the optocoupler card with alternating voltages, the situation is slightly complicated, as the corresponding PB pin oscillates between 1 and 0 with a certain frequency (for example 50Hz if you connect the input to the mains voltage).
In this case, it is necessary to carry out several readings, before discriminating the value of presence or absence of voltage.
As already mentioned, it is possible to use the entire PB port as an input, but, for convenience, I used only the PB4-PB7 pins as inputs.
Documentation
To conclude, I attach:
- il Commodore 64 Service Manual, where the User Port scheme is present
- il CIA chip datasheet: the MOS 6526 (by Markku Alén)
Finally someone who takes care of the User Port of the C 64
What can we still control through the user port of the C64, in addition to your projects so far?
Well, I would say that the scope is limited only by imagination! I connected the Fiat X1/9, the Christmas tree, the electric heater, the coffee machine... you can do anything with it!
Very interesting!
Can I know the specifications of the two cards (relays and photocouplers)?
If I wanted to do optoisolated bidirectional parallel communication with another device, should I limit myself to 4 opto input and 4 output or is there a way to exploit all 8 bits in I/O while still ensuring isolation?
Thank you (I'm a newbie)
Thank you! The ticket with the relays is on Amazon quietly, looking for "photocoupler relay for Arduino". With regard to the input card, we produce it in the company, but it is not for hobby use. I don't know if there are any ready-made. At the limit, you could use a relay card connected "in reverse": the outputs of the relay command the inputs of the Commodore. Building an 8 IN and 8 OUT card (but even more) is possible, but it is not as immediate as directly exploiting the User Port pins.