Casio Interface to PC version 2.0 (with bug fixes)

Written by Bob Parish
Those of you who have used the circuit diagram below and instructions prior to May, 7, 1996 should replace the 5V1 zener diode with 5.6V zener diode which is (BZX79C5V6). I have read on the newsnet that the Casio interface to connect to a PC is a universal circuit. This I cannot confirm or deny, but if it is the case the following may be of interest to other Casio owners.

I own an FX7700 Power Graphic Calculator. I was astonished at the cost of the 'official' Casio interface (about double the calculator cost !!) and so began an investigation with a college.

Connection to the calculator is via a 2.5 mm stereo jack plug.

The connections are:

     /\   .... Tip       :    Transmit data from calc.
     ==   .... Middle    :    Receive data into calc.
     ==   .... Bottom    :    0V or Ground.
    [  ]
    [__]

I made a cable up (about 1/2m length) where tip and middle are reversed (tip of A to middle of B etc.).

In the rear of my PC I have COM2, a 25w 'D' type connector. This was wired as per the instruction manual for the calculator.

Two problems existed.

  1. The logic levels/polarity.
  2. Powering the adaptor.
The first was easily solved. A MAX232 ic was used. This is powered by a single 5V supply and generates the +/-12V signals required by the RS232 port. On the other side of this ic it accepts/generates TTL level signals with inverted polarity to the RS232. This is precisely what is required by the Casio. The Maxim ic incorporates two RS232->TTL and two TTL->RS232 adaptors, but only one of each is used.

To power the Maxim ic I used the RTS/CTS lines which are tied together. These generate around +12V. If memory serves I used a series diode and small electrolytic capacitor to ensure the supply didn't drop out. This raw +12V was passed through a 5V regulator. Whilst this would not be recommended normally, the power drawn by this circuit is negligible, even when communicating.

The below cicuit was built onto a tiny proto-board and fitted inside the 'D' type back shell, with just a 2.5mm stereo jack socket protruding from the rear.


The curcuit

Those of you who have used this diagram and instructions prior to May, 7, 1996 should replace the 5V1 zener diode with 5.6V zener diode which is (BZX79C5V6). Below circuit powered off by serial port of PC:
                                  NPN  (BC549)
                              c        e
              ------o-----o-------\ /-------o-------------o----------
     13 o     |     |     |       ---       |             |         |
          o   |+    |    | |       |        |+            |         |
     12 o    ===    |    | | 1k    |b      ===            |        ---
          o  ---    |    |_|       |       ---            |        ===
     11 o     |     |     |        |        |             |        +|
          o   |     |     o--------o        |             |         |
     10 o    ___    |     |        |       ___      ------------    |
          o  ///    |     |  |     |       ///   ---|1   16    |    |
      9 o           |  -------    ---100n        |+ |          |    |
          o         |  | / \ 5.6V ---           === |          |    |
      8 o-----------o   /___\      |            --- |         2|-----
          o---------o     |        |             |  |          |
  PC  7 o----\      |     |        |             ---|3        6|-----
          o   \-----|-----o---o-----             ---|4         |    |
 'D'  6 o___________|         |                  |+ |          |   ---
 type     o                  ___                === |  MAX232  |   ===
      5 o____                ///                --- |          |   +|
          o  |                                   |  |          |   ___
      4 o____|                                   ---|5         |   ///
          o                                         |          |
      3 o___________________________________________|7       10|___ Middle
          o                <- Rx                    |          |
      2 o___________________________________________|8        9|___ Tip   2.5mm
          o                   Tx ->                 |          |          jack
      1 o                                           |    15    |  _ Base  socket
                                                    ------------ |
                                                          |      |
                                                         ___    ___
                                                         ///    ///

Note: Unless otherwise stated, all caps are 22uF 16V electrolytic. NPN transistor is TO92 general purpose. (What I had available). Connections to pins 6 and 2 of the ic are deliberately reversed, these being the +10V and -10V charge pump generated supplies.
As regards software, I have a programme written in Microsoft Quick Basic. This is sufficiently fast to allow comms at the highest baud rate of the calculator.

There are two protocols for data transfer, single programmes or block mode (all programmes stored within the calculator). I only implemented the first.

In the following, Tx is the calculator and Rx the PC. All data is hexadecimal.

When you press the send key on the calculator the following happens in the single programme transfer mode.

  1. Tx sends 16h and waits a short time. Rx responds with 13h if ready. If no response is received the Tx displays an error message.
  2. If Rx responds correctly Tx then sends a header block of 40 characters. A checksum is calculated on this block. This should add to 3Ah. If not an error has occurred and Rx sends 2Bh, else 06h.

    Note: When sending from PC to calculator if the slot in the calculator is full then it responds to the header block with 21h instead of the usual 06h or 2Bh. In this situation the PC must ask the user to continue or not. If not the PC sends 15h otherwise 06h.

  3. Assuming no checksum error the programme length is calculated from the 5th and 6th bytes of the header block. Length is 256*5th byte + 6th byte. Rx now receives this many bytes, the programme. A checksum is performed on this data, with the same assumptions on result and messages between Rx and Tx.
When sending from PC to calculator, the PC simply calculates the header block as follows.
       Byte No.          Data
          1              3Ah
          2              50h
          3              31h + slot number (programme memory no.)
          4              00h
          5              High byte of prog length
          6              Low byte of prog length
          7              00h
          8              00h
          9-39           FFh
          40             Checksum byte
Bytes 4,7 and 8 are not known, but are believed to relate to the calculator mode the programme is operating in. (eg Matrix, Regression etc.)

For simply storing and retrieving programmes on a computer this information is not required.

However. The calculator only allows upper case characters to be typed. The character set contains ALL ASCII characters, so a programme could be written/modified on your PC and then downloaded to the calculator with lower case characters (or indeed other ASCIIs) for a 'different' look. This would require the checksum to be recalculated for the programme, and if the programme length changed the header would also need modification.

The Microsoft Quick Basic programme I wrote now follows. The software performs its function but is a little fragile. Situations can occur where 'finger' trouble can cause the programme to hang in a loop waiting for the calculator to send data, if the data has already been sent before the pc was ready. I began to incorporate timeout delays but other projects have taken a higher priority.

Credits to Pete Lawrence who helped with the protocol used by the calculator.


GOSUB initialise

DO
        DO
        GOSUB display
                IF select$ = "R" THEN GOSUB rdprg
                IF select$ = "T" THEN GOSUB wriprg
                IF select$ = "V" THEN GOSUB show
                IF select$ = "E" THEN GOSUB edit
                IF select$ = "L" THEN GOSUB lprog
                IF select$ = "S" THEN GOSUB sprog
                IF select$ = "C" THEN GOSUB catalogue
                IF select$ = "D" THEN GOSUB delete

                LOOP WHILE select$ <> "Q"
                PRINT
                PRINT
                PRINT TAB(10); "Really Quit....Data Backed up ?  Quit..(Y)es/(N)o ";
                GOSUB yorn
                LOOP WHILE question$ <> "Y"
        CHDIR "c:\"

        CLS
END


initialise:
        CHDIR "c:\qbasic\calculat"
        file$ = ""
        timeout = 100000
        num = 7
        max = 4095
        DIM header(39), cast$(255), valid(num), prglen(num), prgname$(num)
        DIM prog(max, num)   AS INTEGER
        FOR lp = 0 TO num
                valid(lp) = -1
                NEXT

        FOR lp = 0 TO 255
                IF lp < 127 AND lp > 31 THEN
                        cast$(lp) = CHR$(lp)
                        IF lp = 92 THEN cast$(lp) = CHR$(157)
                ELSE
                        READ cast$(lp)
                        IF cast$(lp) = "x2" THEN cast$(lp) = CHR$(253)
                        IF cast$(lp) = "x3" THEN cast$(lp) = CHR$(254)
                        IF cast$(lp) = "^0.5" THEN cast$(lp) = CHR$(251)
                        IF cast$(lp) = "^1/3" THEN cast$(lp) = CHR$(254) + CHR$(251)
                        IF cast$(lp) = "Sigma x" THEN cast$(lp) = CHR$(228) + "x"
                        IF cast$(lp) = "Sigma x2" THEN cast$(lp) = CHR$(228) + "x" + CHR$(253)
                        IF cast$(lp) = "Sigma y" THEN cast$(lp) = CHR$(228) + "y"
                        IF cast$(lp) = "Sigma y2" THEN cast$(lp) = CHR$(228) + "y" + CHR$(253)
                        IF cast$(lp) = " divide" THEN cast$(lp) = CHR$(246)
                        IF cast$(lp) = "theta" THEN cast$(lp) = CHR$(233)
                        IF cast$(lp) = "pi" THEN cast$(lp) = CHR$(227)
                        IF cast$(lp) = "=<" THEN cast$(lp) = CHR$(243)
                        IF cast$(lp) = ">=" THEN cast$(lp) = CHR$(242)
                        IF cast$(lp) = "=>" THEN cast$(lp) = CHR$(175)
                        IF cast$(lp) = " degrees" THEN cast$(lp) = CHR$(248)
                        END IF
                NEXT lp
RETURN

display:
        CLS
        PRINT TAB(25); "Fx7700 Interface Software"
        PRINT TAB(25); "-------------------------"
        PRINT
        PRINT TAB(5); "(R)x a programme from the Calculator"; TAB(45); "(L)oad a programme from disk"
        PRINT TAB(5); "(T)x a programme to the Calculator"; TAB(45); "(S)ave a programme to disk"
        PRINT TAB(5); "(D)elete a programme"; TAB(45); "(E)dit/create a programme"
        PRINT TAB(5); "(V)iew a programme"; TAB(45); "(Q)uit the programme"
        PRINT TAB(25); "(C)atalogue files"
        PRINT
        FOR row = 0 TO 1
                FOR col = 0 TO 3
                        PRINT TAB(col * 17 + 5); row * 4 + col; ": ";
                        PRINT prgname$(row * 4 + col);
                        NEXT
                        PRINT
                NEXT
        PRINT
        PRINT TAB(30); "Select: ";
        DO
                select$ = INKEY$
                LOOP WHILE select$ = ""
                select$ = UCASE$(select$)
RETURN

catalogue:
        PRINT
        FILES "*.fxp"
        GOSUB continue
RETURN

rdprg:
        PRINT TAB(15); "Receive a programme from the Fx7700"
        GOSUB whereto
        IF question$ = "N" THEN RETURN
        PRINT TAB(16); "Awaiting data"

        OPEN "COM2:9600,N,8,2" FOR RANDOM AS #1 LEN = 256

        DO
                LOOP WHILE EOF(1)

        IF count = timeout THEN RETURN

        DO
                'Put timeout counter here
                in$ = INPUT$(LOC(1), #1)
                LOOP WHILE ASC(in$) <> 22

        PRINT #1, CHR$(19);
        PRINT TAB(16); "Waiting for header ";
        FOR lp = 0 TO 39
        DO
                LOOP WHILE EOF(1)
                in$ = INPUT$(LOC(1), #1)
                header(lp) = ASC(in$)
                NEXT

        chksum = 0
        FOR lp = 0 TO 39
                chksum = (chksum + header(lp)) MOD 256
                NEXT

        length = header(4) * 256 + header(5)
        IF chksum <> 58 THEN
                GOSUB chksum
                RETURN
        ELSE
                PRINT ".....Checked"
                PRINT #1, CHR$(6);
        END IF

        PRINT TAB(16); "Waiting for programme"
        prglen(slot) = length

        FOR lp = 0 TO length - 1
        DO
                LOOP WHILE EOF(1)
                in$ = INPUT$(LOC(1), #1)
                prog(lp, slot) = ASC(in$)
                NEXT

        IF chksum MOD 256 <> 58 THEN
                        GOSUB chksum
                ELSE
                        PRINT #1, CHR$(6);
                        valid(slot) = 0
                DO
                        PRINT
                        PRINT TAB(16); "Transmission finished         "
                        PRINT TAB(16); "Call file ";
                        INPUT file$
                        LOOP WHILE LEN(file$) > 8
                        prgname$(slot) = file$
                END IF
        CLOSE #1
RETURN



wriprg:
        PRINT TAB(15); "Transmit a programme to the Fx7700"
        GOSUB wherefrom
        OPEN "COM2:9600,N,8,2" FOR RANDOM AS #1 LEN = 256

        IF valid(slot) = -1 THEN RETURN
        chksum = 0
        FOR lp = 0 TO prglen(slot)
                chksum = chksum + prog(lp, slot)
        NEXT

        header(0) = 58
        header(1) = 80
        header(2) = 49 + slot
        header(3) = 0
        header(4) = INT(prglen(slot) / 256)
        header(5) = prglen(slot) MOD 256
        header(6) = 0
        header(7) = 0

        FOR lp = 8 TO 38
                header(lp) = 255
                NEXT

        chksum = 0
        FOR lp = 0 TO 38
                chksum = chksum + header(lp)
                NEXT

        header(39) = 58 - chksum MOD 256

        IF header(39) < 0 THEN
                header(39) = header(39) + 256
                END IF

        PRINT #1, CHR$(22);
        GOSUB find
        IF response <> 19 THEN
                BEEP
                PRINT TAB(16); "CHECKSUM ERROR!!       "
                GOSUB continue
                RETURN
                END IF

        PRINT TAB(16); "Sending Header.....";
        FOR lp = 0 TO 39
                PRINT #1, CHR$(header(lp));
                NEXT

        GOSUB find
        IF response = 43 THEN
                BEEP
                PRINT TAB(16); "CHECKSUM ERROR!!       "
                GOSUB continue
                RETURN
                END IF

        PRINT ".....Checked"

        IF response = 33 THEN
                con$ = "Y"
                BEEP
                PRINT TAB(16); "Programme area is full."
                PRINT TAB(17); "CONTINUE (Y)es/(N)o ";
                GOSUB yorn
                IF question$ = "N" THEN
                                PRINT #1, CHR$(21);
                                RETURN
                        ELSE
                                PRINT #1, CHR$(6);
                                GOSUB find
                                END IF
                END IF

        PRINT TAB(16); "Sending programme"

        FOR lp = 0 TO prglen(slot) - 1
                PRINT #1, CHR$(prog(lp, slot));
                NEXT

        GOSUB find
        IF response <> 6 THEN
                BEEP
                PRINT TAB(16); "CHECKSUM ERROR !!     "
        ELSE
                PRINT TAB(16); "Transmission finished         "
                PRINT TAB(17);
        END IF
        GOSUB continue
CLOSE #1
RETURN



find:
        DO
                LOOP WHILE EOF(1)
                in$ = INPUT$(LOC(1), #1)
                response = ASC(in$)
RETURN


edit:
        PRINT TAB(15); "Edit a programme"
RETURN


lprog:
        PRINT TAB(15); "Load a programme from disk"
        GOSUB whereto
        IF question$ <> "N" THEN
                FILES "*.fxp"
                PRINT TAB(17);
                INPUT "Filename to Load"; prgname$(slot)
                file$ = prgname$(slot) + ".fxp"
                OPEN file$ FOR INPUT AS #1
                INPUT #1, prglen(slot)
                FOR c = 0 TO prglen(slot)
                        INPUT #1, prog(c, slot)
                        NEXT
                CLOSE #1
                valid(slot) = 0
                END IF
RETURN


sprog:
        PRINT TAB(15); "Save a programme to disk"
        GOSUB wherefrom
        IF question$ <> "N" THEN
                file$ = prgname$(slot) + ".fxp"
                OPEN file$ FOR OUTPUT AS #1
                PRINT #1, prglen(slot)
                FOR c = 0 TO prglen(slot)
                        PRINT #1, prog(c, slot)
                        NEXT
                CLOSE #1
                END IF
RETURN


whereto:
        DO
                PRINT TAB(16); "Into which memory slot 0 -"; num; " : ";
                DO
                        slot$ = INKEY$
                        LOOP WHILE slot$ = ""
                slot = ASC(slot$) - 48
                LOOP WHILE slot < 0 OR slot > num
        PRINT slot
        question$ = "Y"
        IF valid(slot) = 0 THEN
                BEEP
                PRINT TAB(17); "That slot is already full ";
                PRINT "Overwrite (Y)es/(N)o ";
                GOSUB yorn
                END IF

RETURN


wherefrom:
        DO
                PRINT TAB(16); "From which memory slot 0 -"; num; " : ";
                DO
                        slot$ = INKEY$
                        LOOP WHILE slot$ = ""
                slot = ASC(slot$) - 48
                LOOP WHILE slot < 0 OR slot > num
        PRINT slot
        IF valid(slot) = -1 THEN
                BEEP
                PRINT
                question$ = "N"
                PRINT TAB(16); "That slot is empty  to Continue ";
                INPUT q$
                END IF

RETURN

chksum:
        PRINT #1, CHR$(43);
        BEEP
        PRINT TAB(17); "CHECKSUM ERROR !!"
        GOSUB continue
RETURN


delete:
        PRINT TAB(15); "Delete a programme"
        GOSUB wherefrom
        valid(slot) = -1
        prgname$(slot) = " "
RETURN

show:
        PRINT TAB(15); "Display Programme"
        GOSUB wherefrom
        IF valid(slot) = 0 THEN
                count = 0
                FOR lp = 0 TO prglen(slot) - 2
                sym$ = cast$(prog(lp, slot))
                IF sym$ = "cr" OR sym$ = " - Disp -" OR sym$ = "END" THEN
                                IF sym$ = "cr" THEN
                                        PRINT
                                        count = count + 1
                                ELSE
                                        IF sym$ = "END" THEN
                                                PRINT
                                                END IF
                                        PRINT sym$
                                        count = count + 1
                                        END IF
                        ELSE
                                PRINT sym$;
                                END IF
                        IF count = 22 THEN
                                GOSUB continue
                                count = 0
                                END IF
                        NEXT
                        PRINT
                        INPUT " when ready"; temp$
                ELSE
                        FOR c = 0 TO 3000: NEXT
                END IF
RETURN

yorn:
                DO
                        DO
                                question$ = INKEY$
                                LOOP WHILE question$ = ""
                                question$ = UCASE$(question$)
                        LOOP WHILE question$ <> "Y" AND question$ <> "N"
RETURN

continue:
                PRINT " to Continue "
                DO
                        LOOP WHILE INKEY$ = ""
RETURN

DATA "@","femto","pico","nano","micro","milli","kilo","mega"
DATA "giga","tera","peta","exa"," - Disp -","cr","->","exp"
DATA "=<","<>",">=","=>","f1","f2","f3","f4","f5","f6","A"
DATA "B","C","D","E","F"
DATA "@","Pol(","sin","cos","tan","h","ln","^0.5","(-)","P"
DATA "+","xnor","x2","[]","Integral(","Mo","Sigma x2","Pol("
DATA "sin-1","cos-1","tan-1","d","log","^1/3","Abs","C","-"
DATA " xor","-1"," degrees","Integral(","Med","Sigma x","Rec("
DATA "sinh","cosh","tanh","o","e","Int","Not","x^y"," x (times)"
DATA " or","!","r (radians)","Integral(","Min","n","Rec("
DATA "sinh-1","cosh-1","tanh-1","b","10^","Frac","Neg","^1/x"
DATA " divide"," and","_|","g (gradians)","Integral(","Max"
DATA "Sigma y2","Ans","Ran#","mean x","mean y","xon","xon-1"
DATA "yon","yon-1","A","B","r","peak x","peak y","r","theta"
DATA "Sigma y","pi","Cls","Mcl","Rnd","Dec","Hex","Bin","Oct"
DATA "Scl","Norm","Deg","Rnd","Gra","Eng","Intg","Sigma xy"
DATA "Plot","Line","Lbl","Fix","Sci","Defm","CL","DT","Dsz"
DATA "Isz","Factor","Range","Goto","Prog","Graph Y="
DATA "Graph Integral","Graph Y>","Graph Y<","Graph Y>="
DATA "Graph Y <=","Graph r=","Graph (X,Y)=","@","@","@","@"
DATA "@","P(","Q(","R(","t(","END"