CommonLisp에서 RaspberryPi 전자 공작 ~I2C LCD 그 2~

소개



지난번 I2C에서 액정 모듈【MI2CLCD-01】을 제어해 보았습니다만, 이번은 그것을 GUI 어플리케이션으로부터 제어해 보고 싶습니다.

회로도 및 장치 주소



회로도와 디바이스 주소는 이전과 동일하므로 생략합니다.

패키징



cffi와 ltk를 Quicklisp로로드하고 패키지 정의.

packages.lisp
;; cffiとltkをQuicklispでロード
(ql:quickload "cffi")
(ql:quickload "ltk")

;; パッケージ定義
(defpackage :cl-cffi
  (:use :common-lisp
    :ltk
    :cffi))

API 래퍼 작성



이전에 만든 것과 같은 것을 준비합니다.

libwiringPi.lisp
(define-foreign-library libwiringPi
  (:unix "libwiringPi.so"))

(use-foreign-library libwiringPi)

;; Initialization of the wiringPi
(defcfun "wiringPiSetupGpio" :int)

;; Set the mode of the GPIO pin
(defcfun "pinMode" :void (pin :int) (mode :int))

;; GPIO pin output control
(defcfun "digitalWrite" :void (pin :int) (value :int))

;; Waiting process
(defcfun "delay" :void (howlong :uint))

;; Set the state when nothing is connected to the terminal
(defcfun "pullUpDnControl" :void (pin :int) (pud :int))

;; Read the status of the GPIO pin
(defcfun "digitalRead" :int (pin :int))

;; Initialization of the I2C systems.
(defcfun "wiringPiI2CSetup" :int (fd :int))

;; Writes 8-bit data to the instructed device register.
(defcfun "wiringPiI2CWriteReg8" :int (fd :int) (reg :int) (data :int))

프로그램 본체



LCD에 표시할 문자열을 입력하는 엔트리와 엔트리에 입력한 문자를 LCD에 표시하는 버튼을 준비합니다.
LCD의 1단째와 2단째를 나누어 표시할 수 있도록 프로그램을 작성해 보았습니다.

mi2clcd-01.lisp
;; Load packages
(load "packages.lisp" :external-format :utf-8)

(in-package :cl-cffi)

;; Load wrapper API
(load "libwiringPi.lisp" :external-format :utf-8)

;; i2cdetectコマンドで確認したI2Cデバイスアドレス (0x3e)
(defconstant +i2c-addr+ #X3E)

;; LCDのコントラスト (範囲:0x00~0x0F)
(defconstant +contrast+ #X0A)

;; 1段に表示できるLCDの桁数 (16桁)
(defconstant +column+ 16)

(defun i2c-lcd ()
  ;; I2Cシステムの初期化
  (setq fd (wiringPiI2CSetup +i2c-addr+))

  ;; コントラストの計算
  (setq fcnt (logior (logand +contrast+ #X0F) #X70))

  ;; 各種初期化処理
  (wiringPiI2CWriteReg8 fd #X00 #X38) ; Function set : 8bit, 2 line
  (wiringPiI2CWriteReg8 fd #X00 #X39) ; Function set : 8bit, 2 line, IS=1
  (wiringPiI2CWriteReg8 fd #X00 #X14) ; Internal OSC freq
  (wiringPiI2CWriteReg8 fd #X00 fcnt) ; Contrast set
  (wiringPiI2CWriteReg8 fd #X00 #X5F) ; Power/ICON/Constract
  (wiringPiI2CWriteReg8 fd #X00 #X6A) ; Follower control
  (delay 300)                         ; Wait time (300 ms)
  (wiringPiI2CWriteReg8 fd #X00 #X38) ; Function set : 8 bit, 2 line, IS=0
  (wiringPiI2CWriteReg8 fd #X00 #X06) ; Entry mode set
  (wiringPiI2CWriteReg8 fd #X00 #X0C) ; Display on/off
  (wiringPiI2CWriteReg8 fd #X00 #X01) ; Clear display
  (delay 30)                          ; Wait time (0.3 ms)
  (wiringPiI2CWriteReg8 fd #X00 #X02) ; Return home
  (delay 30)                          ; Wait time (0.3 ms)

  ;; 以下GUI作成処理
  (with-ltk ()
    (wm-title *tk* "Entry")
    (bind *tk* "<Alt-q>" (lambda (event)
                           (setq *exit-mainloop* t)))
    (let ((lbl1 (make-instance 'label :text "First line" :width 60))   ; 1段目表示用ラベル
          (entry1 (make-instance 'entry))                              ; 1段目表示用エントリ
          (btn1 (make-instance 'button :text "Button1"))               ; 1段目表示用ボタン
          (lbl2 (make-instance 'label :text "Second line" :width 60))  ; 2段目表示用ラベル
          (entry2 (make-instance 'entry))                              ; 2段目表示用エントリ
          (btn2 (make-instance 'button :text "Button2")))              ; 2段目表示用ボタン
      ;; LCD1段目にエントリに入力された文字列を表示させる処理
      (setf (command btn1) (lambda ()
                 ;; 1段目の左端にカーソルをセット
                 (wiringPiI2CWriteReg8 fd #X00 #X80)
                 ;; 1段目を全て半角スペースで埋めることでクリアする
                 (dotimes (count +column+)
                   (wiringPiI2CWriteReg8 fd #X40 #X20))
                 ;; 1段目の左端にカーソルを再セット
                 (wiringPiI2CWriteReg8 fd #X00 #X80)
                 ;; エントリに入力された文字列をLCDへ表示する
                 (loop :for char :across (text entry1)
                   :do (wiringPiI2CWriteReg8 fd #X40 (char-code char)))))
      ;; LCD2段目にエントリに入力された文字列を表示させる処理
      (setf (command btn2) (lambda ()
                 ;; 2段目の左端にカーソルをセット
                 (wiringPiI2CWriteReg8 fd #X00 #XC0)
                 ;; 2段目を全て半角スペースで埋めることでクリアする
                 (dotimes (count +column+)
                   (wiringPiI2CWriteReg8 fd #X40 #X20))
                 ;; 2段目の左端にカーソルを再セット
                 (wiringPiI2CWriteReg8 fd #X00 #XC0)
                 ;; エントリに入力された文字列をLCDへ表示する
                 (loop :for char :across (text entry2)
                   :do (wiringPiI2CWriteReg8 fd #X40 (char-code char)))))
      (focus entry1)
      ;; 各ウィジェットを上から配置していく
      (pack (list lbl1 entry1 btn1 lbl2 entry2 btn2) :fill :x))))

;; 実行!
(i2c-lcd)

실행



SBCL을 시작하고 다음 명령으로 실행.
(load "mi2clcd-01.lisp" :external-format :utf-8)

이하 실행중인 모습



실제 LCD의 모습



마지막으로



GUI 애플리케이션에서 I2C LCD를 제어할 수 있습니다.
또, 1단째와 2단째를 나누어 따로따로 LCD에 표시시킬 수도 있었습니다.
이것은 좀처럼 편리하지 않을까~, 뭐라고 생각하거나.

프로그램 본체의 실제의 처리를 실시하는 개소가 고차고차 해 보기 어려워져 버리고 있으므로, 함수 만들고 나누거나 할 수 있으면 보다 예쁘게 될까라고 생각했습니다. 앞으로의 과제로 하려고 합니다.

좋은 웹페이지 즐겨찾기