Here’s the starting point for a project I’ve been working on. It’s a calculator, written in uLisp, with an 8-digit 7-segment display. It lets you do something like:
(show (acos -1))
to display the result of the calculation, pi:
The display is a very low-cost 8-digit display with an SPI interface, available on sites such as AliExpress for under a dollar/pound; for example: MAX7219 8 Digit LED Display. The program will run on any uLisp platform, but to display floating-point calculations you need a 32-bit platform, such as the Adafruit ItsyBitsy M0.
Connecting the display
Connect the display using the appropriate SPI pins as follows:
Pin | Connection |
---|---|
VCC | +5V |
GND | GND |
DIN | MOSI |
CS | Enable |
CLK | SCK |
For details of which pins are used for the SPI interface on different processors see Language reference: with-spi.
You can use any suitable pin as the Enable pin; specify it as follows:
(defvar en 2)
Display command
The routine cmd writes a display command to the display, consisting of an address or command code followed by a data value:
(defun cmd (a d)
(with-spi (str en)
(write-byte a str)
(write-byte d str)))
Initialising the display
The following routine on turns on the display and sets the brightness; the parameter can be from 0 (dimmest) to 15 (brightest):
(defun on (bri)
(cmd #xF 0) ; Test mode off
(cmd #xB 7) ; 8 digits
(cmd #xC 1) ; Enable display
(cmd #xA bri))
Defining the segment definitions
The following list gives the segment definitions for the digits 0 to 9, the hexadecimal digits A to F, and space and minus:
(defvar seg '(#x7e #x30 #x6d #x79 #x33 #x5b #x5f #x70 #x7f
#x7b #x77 #x1f #x4e #x3d #x4f #x47 #x00 #x01))
Clearing the display
This routine clr clears the display:
(defun clr ()
(dotimes (d 8) (cmd d 0)))
Showing a value
Finally this routine show writes a value to the display:
(defun show (val)
(clr)
(let ((str (princ-to-string val))
(d 8) b)
(dotimes (i (length str))
(let ((c (char-code (char str i))))
(setq b
(cond
((= (char-code #\.) c)
(incf d)
(+ b #x80))
(t
(nth
(cond
((<= (char-code #\0) c (char-code #\9))
(- c (char-code #\0)))
((<= (char-code #\A) c (char-code #\F))
(+ (- c (char-code #\A)) 10))
((<= (char-code #\a) c (char-code #\f))
(+ (- c (char-code #\a)) 10))
((= (char-code #\-) c) 17)
(t 16))
seg)))))
(cmd d b)
(decf d))))
It works by converting the value to a string, using the uLisp function princ-to-string, converts each digit to the appropriate seven-segment pattern from the list seg, and then writes this to the appropriate display digit. If it encounters a decimal point in the value it sets the top bit of the previous digit, to display a decimal point after it.
With the addition of a small keypad this could form the basis of a custom scientific calculator, written in Lisp.