uLisp 點亮 TM1637 四位元七段顯示器
點亮一個四位數的七段顯示器很複雜也很簡單,簡單的是直接用 Arduino 的範例去做就好,複雜的是自己想要自己生一個 lisp 驅動的程式…
1. 目標
建立 Arduino UNO 使用 uLisp 驅動的四位數七段顯示器的 API 。
2. TM1637 IC 介紹
TM1637 是一種帶鍵盤掃描接口的 LED(發光二極管顯示器)驅動控制專用電路,內部集成了 MCU 數字接口、數據鎖存、LED 高壓驅動和鍵盤掃描。 由於 TM1637 的傳輸介面並非正規的 \(I^2C\) ,所以要特別建立與 uLisp 溝通的方式。 TM1637 Datasheet
3. 使用介面
自製 common lisp 與 Arduino UNO 開發板連接的程式, cl-connect-arduino 。
4. TODO API 製作
4.1. DONE cl-connect-arduino 與 Arduino UNO 連接
4.2. DONE 確認電子模組與 Arduino UNO 連接方式
模組 | Arduino UNO |
---|---|
CLK | Pin 2 |
DIO | Pin 3 |
VCC | 5V |
GND | GND |
5. common lisp
5.1. ulisp-led-4-bit-display.asd
;;;;-*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- (in-package :cl-user) (asdf:defsystem #:ulisp-led-4-bit-display :description "uLisp control 4-bit display" :author "Colin Lu" :License "GPL" :version "0.0.1" :depends-on ("cl-connect-arduino") :serial t :components ((:file "packages") (:file "ulisp-led-4-bit-display")))
5.2. packages.lisp
(in-package :cl-user) (defpackage #:ulisp-led-4-bit-display (:use #:cl #:cl-connect-arduino))
5.3. ulisp-led-4-bit-display.lisp
(in-package :ulisp-led-4-bit-display) (defmacro run-command-arduino (&body body) (let ((commands (gensym)) (serial-name (gensym))) `(let ((,commands '(,@body)) (,serial-name ,*arduino-serial*)) (dolist (x ,commands) (arduino-command ,serial-name (apply #'list x)))))) (defun tm1637-set () (run-command-arduino (defvar *scl* 2) (defvar *sda* 3) (defvar *delaytime* 5) (defun tm1637 () (pinmode *scl* :output) (pinmode *sda* :output) (digitalwrite *scl* :high) (digitalwrite *sda* :high)) ;;定義腳位狀況 (tm1637) (defun start () (digitalwrite *scl* :high) (digitalwrite *sda* :high) (digitalwrite *sda* :low) (bitdelay) (digitalwrite *scl* :low) (format t "~&start~%")) (defun stop () (digitalwrite *scl* :low) (digitalwrite *sda* :low) (digitalwrite *scl* :high) (bitdelay) (digitalwrite *sda* :high) (format t "~&stop~%")) (defun re-start () (stop) (start)) (defun writebyte (data) (let ((ack t)) ;;(format t "~&data: ~A~%" data) (dotimes (x 8) (let ((high-p (logbitp x data))) (digitalwrite *scl* :low) (if high-p (digitalwrite *sda* :high) (digitalwrite *sda* :low)) ;; (format t "~A " high-p) (digitalwrite *scl* :high))) (digitalwrite *scl* :low) ;; wait for the ack (digitalwrite *sda* :high) (digitalwrite *scl* :high) (pinmode *sda* :input) ;; (format t "~&~A ~A" (digitalread *sda*) (digitalread *scl*)) (bitdelay) ;;(format t "~&ack :~A~%" ack) (setf ack (digitalread *sda*)) ;;(format t "~&ack :~A~%" ack) (unless ack (pinmode *sda* :output) (digitalwrite *sda* :low)) (bitdelay) (digitalwrite *sda* :high) (bitdelay) ack)) (defun bitdelay (&optional (times *delaytime*)) (delay times)) ;; (defun display (bit-addr disp-data) ;; (let ((addr-fixed #x44) ;; (addr-auto #x40)) ;; (start) ;; (writebyte addr-fixed) ;; command1 ;; (stop) ;; (start) ;; (writebyte (or bit-addr #xc0)) ;;command2 ;; (writebyte disp-data) ;; (stop) ;; (start) ;; (writebyte #x8f) ;; cmd_disp_ctrl, command3 ;; (stop) ;; )) )) (defun all-bright () (run-command-arduino (tm1637) (start) (writebyte #x40) (re-start) (writebyte #xc0) ;; (dotimes (x 6) ;; ;; 手動設定 ;; ;;(writebyte #xff) ;; (writebyte #xff) (dolist (x '(#x38 #x06 #x6d #x73 #xff #xff)) (writebyte x)) (re-start) (writebyte #x8f) (stop)))
5.4. 程式重點
- 要注意 I2C format 位元讀取時間是在 scl 高位元才會讀取,sda 在 scl 低位元時變換才有效。
- 在 scl 高位元變換 sda 訊號時,為 start 位元,及 stop 位元
- 一定要等 ack 位元回傳