Ho sempre trovato interessante considerare il computer non solo come un'entità indipendente, ma bensì in grado di controllare altre apparecchiature. E' possibile controllare la User Port del Commodore 64 per questo scopo: cioè integrare il computer con l'ambiente circostante.

I had already done some experiments to connect the Commodore 64 all'impianto domotico di casa: in quell'esperimento, la User Port veniva infatti utilizzata per comunicare con un modem WiFi.
Nell'esperimento di questo articolo, invece, i pin PB0-PB7 della User Port del Commodore 64 vengono utilizzati direttamente per comandare due schede di interfaccia.

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;
- un'interfaccia di ingresso, con 4 optoisolatori.

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
Per gli appassionati di teoria, ecco un po' di schemi! Della User Port del Commodore 64, andremo ad utilizzare solo gli 8 pin della porta B: i pin PB0, PB1, PB2, PB3, PB4, PB5, PB6 e PB7. Per questo si abbreviano con PB0-PB7. La porta PB è collegata ai piedini C, D, E, F, H, J, K e L della User Port. C'è da prestare attenzione al fatto che 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, non caricando e non sporcando quindi l'alimentazione del Commodore 64. Dalla User Port, quindi, preleviamo solo i segnali e non l'alimentazione.

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. Se è presente tensione all'ingresso del fotoaccoppiatore, la uscita della scheda (e quindi il pin di ingresso della User Port del Commodore 64), va a massa. Se non è presente tensione all'ingresso del fotoaccoppiatore, l'uscita della scheda rimane libera e quindi il pin di ingresso della User Port è libero di andare a livello logico 1, per mezzo del resistore di pull-up (ed anche altri circuiti) già presenti all'interno del chip CIA (MOS 6526) del 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 In essence, it represents the PIN (or PIN) of exit to be activated, to be calculated with the powers of 2: 2 ^ (number_relay - 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. Per verificare, quindi, se all'ingresso del fotoaccoppiatore è presente tensione, si può procedere in questo modo:
IF ( PEEK(56577) AND 2 ^ (numero_fotoaccoppiatore + 4 - 1) ) = 0 THEN ...
The sum number_photocoupler + 4 è perché, in questo esperimento, i fotoaccoppiatori 1, 2, 3 e 4 sono collegati su PB4, PB5, PB6 e PB7. Ricordo, anche, che i piedini della porta PB si portano a 1 logico in caso di assenza di tensione. Per verificare, quindi, l'assenza della tensione, è sufficiente togliere "= 0" dal comando.
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 …
Utilizzando gli ingressi della scheda fotoaccoppiatori con tensioni alternate, la situazione si complica leggermente, in quanto il piedino PB corrispondente oscilla tra 1 e 0 con una determinata frequenza (ad esempio 50Hz se si collega l'ingresso alla tensione della rete elettrica).
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?
Beh, direi che il campo di applicazione è limitato solo dalla fantasia! Ho collegato la Fiat X1/9, l'albero di natale, la stufetta elettrica, la macchina del caffè... ci puoi fare di tutto!
Very interesting!
Can I know the specifications of the two cards (relays and photocouplers)?
Se volessi fare una comunicazione parallela bidirezionale optoisolata con un altro dispositivo, dovrei limitarmi a 4 opto in ingresso e 4 in uscita o c'è un modo per sfruttare tutti gli 8 bit in I/O garantendo comunque l'isolamento?
Thank you (I'm a newbie)
Grazie! La schedina con i relay si trova su Amazon tranquillamente, cercando "relay fotoaccoppiatore per Arduino". Relativamente alla scheda ingressi, quella la produciamo in ditta, ma non è per uso hobbistico. Non so se ne esistano di già pronte. Al limite, potresti utilizzare una scheda relay collegata "al contrario": le uscite del relay comandano gli ingressi del Commodore. Costruire una scheda 8 IN e 8 OUT (ma anche di più) è possibile, ma non è immediato come sfruttare direttamente i pin della User Port.