Color LCD(5)

SPI接続カラーLCDのコントーラST7735Rにはインテリジェントな描画機能が無いので、画面上に直線を引いたり塗りつぶしたりといった処理はすべて自前で行わなくてはならない。

任意の位置にドットを表示する事ができれば、あとはプログラムによって色々な図形を描画することは可能で、実際にブレゼンハムのアルゴリズムで直線描画のメソッドを作ったりはしてみたのだが、必要とされる描画機能をすべて自前で実装するのはかなり大変。

画像ファイルを読み込むために使用したPillowには各種描画を行うためのモジュールも用意されているので、それを使ってメモリ上の仮想画面に描画を行ってからLCDに転送してはどうか?と思って試してみた。

具体的には

from PIL import ImageDraw

でImageDrawモジュールをロードしておいて

im = Image.new(‘RGBA’, (128, 160), (0, 0, 0))

で新規の画像イメージを作成する。
あとはline、rectangle等のメソッドを使用してその画像に描画を行ってから、LCDにまとめて転送すれば良い。

試してみると一画面まるごとの転送でも0.5秒以下だったので、決して速いとは言えないが用途によっては十分かも知れない。
一画面まるごとではなく、必要な範囲だけ転送するようにすれば当然もっと速くなる。そのための範囲指定転送も試してみた。

from PIL import ImageFont

でフォントモジュールをロードすれば文字表示も可能で、試してはいないがフォントを適切に選択すれば漢字表示もできるはず。

全画面転送、部分転送、テキスト表示を行うテストプログラムは、長くなるので最後の「続きを読む」に以降に置いた。

プログラムを実行すると最初に以下のように図形描画と文字列描画を行い

2013-12-12 12.13.34

四角形をランダムな位置と色で表示する。最初の図形はメモリ上の仮想画面に描画してからまるごと転送、四角形の描画は更新範囲だけの転送を行うようにした。

2013-12-12 12.13.42

あたりまえだが転送する範囲が狭ければ素早く転送されるので、最初に画面全体を転送しておき、あとは更新部分だけを転送するような形で利用すれば、かなり実用性が高まるのではないかと思う。
それ以上のレスポンスが必要な場合はSPI転送を諦めて、パラレル接続にすべきだろう。

テストプロプログラムのソースコードは、「続きを読む」をクリック。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO
import spidev           # sudo pip install spidev
import time
import sys
from PIL import Image   # sudo pip install pillow
from PIL import ImageDraw
from PIL import ImageFont
import random

RSPort = 24
RstPort = 25

class ST7735:
    def __init__(self, rst, rs):
        self.spi = spidev.SpiDev()
        self.spi.open(0, 0)
        self.spi.max_speed_hz = 16000000
        self.rst = rst
        self.rs = rs
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)
        GPIO.setup(self.rs, GPIO.OUT)
        GPIO.setup(self.rst, GPIO.OUT)
        self.reset()
        self.write_cmd(0x11)
        time.sleep(0.12)
        self.write((0xB1, 0x01, 0x2C, 0x2D))
        self.write((0xB2, 0x01, 0x2C, 0x2D))
        self.write((0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D))
        self.write((0xB4, 0x07))
        self.write((0xC0, 0xA2, 0x02, 0x84))
        self.write((0xC1, 0xC5))
        self.write((0xC2, 0x0A, 0x00))
        self.write((0xC3, 0x8A, 0x2A))
        self.write((0xC4, 0x8A, 0xEE))
        self.write((0xC5, 0x0E))
        self.write((0x36, 0xC8))
        self.write((0xE0, 0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10))
        self.write((0xE1, 0x03, 0x1D, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10))
        self.write((0x2A, 0x00, 0x02, 0x00, 0x81))
        self.write((0x2B, 0x00, 0x01, 0x00, 0xA0))
        self.write((0x3A, 0x05))
        self.write_cmd(0x29)
    def reset(self):
        GPIO.output(self.rst, False)
        time.sleep(0.1)
        GPIO.output(self.rst, True)
        time.sleep(0.1)
    def write_cmd(self, cmd):
        GPIO.output(self.rs, False)  # RS=0
        self.spi.xfer2([cmd])
    def write_data(self, data):
        GPIO.output(self.rs, True)   # RS=1
        self.spi.xfer2([data])
    def write(self, cmd):
        if len(cmd) == 0:
            return
        GPIO.output(self.rs, False)  # RS=0
        self.spi.xfer2([cmd[0]])
        GPIO.output(self.rs, True)   # RS=1
        self.spi.xfer2(list(cmd[1:]))
    def write_rgb(self, r, g, b):
        self.write_data(r & 0xF8 | g >> 5)
        self.write_data(g & 0xFC << 3 | b >> 3)
    def fill(self, r, g, b):
        self.write((0x2A, 0x00, 0x02, 0x00, 0x81))
        self.write((0x2B, 0x00, 0x01, 0x00, 0xA0))
        self.write_cmd(0x2C)
        GPIO.output(self.rs, True)   # RS=1
        hi = r & 0xF8 | g >> 5
        lo = g & 0xFC << 3 | b >> 3
        pixline = []
        for n in range(2048):
            pixline.append(hi)        
            pixline.append(lo)
        for n in range(10):
            self.spi.xfer2(pixline[0:])
    def image(self, imgfile):
        try:
            im = Image.open(imgfile).convert("RGB")
            im.thumbnail((128, 160))
            self.trans(im)
        except:
            pass
    def trans(self, im):
        pix = im.load()
        w = im.size[0]
        h = im.size[1]
        if w > 128:
            w = 128
        if h > 160:
            h = 160
        self.write((0x2A, 0x00, 0x02, 0x00, w + 1))
        self.write((0x2B, 0x00, 0x01, 0x00, h))
        self.write_cmd(0x2C)
        GPIO.output(self.rs, True)   # RS=1
        pixline = []
        px = 0
        py = 0
        for i in range(10):
            for n in range(2048):
                pixel = pix[px, py]
                hi = pixel[0] & 0xF8 | pixel[1] >> 5
                lo = pixel[1] & 0xFC << 3 | pixel[2] >> 3
                pixline.extend([hi, lo])
                px = px + 1
                if px >= w:
                    px = 0
                    py = py + 1
                    if py >= h:
                        break
            self.spi.xfer2(pixline)
            del pixline[:]
            if py >= h:
                break
    def blit(self, im, x1, y1, x2, y2):
        if x2 < x1:
            x1, x2 = x2, x1
        if y2 < y1:
            y1, y2 = y2, y1
        if x1 > 127 or x2 < 0:
            return
        if x1 < 0:
            x1 = 0
        if x2 > 127:
            x2 = 127
        if y1 > 159 or y2 < 0:
            return
        if y1 < 0:
            y1 = 0
        if y2 > 159:
            y2 = 159
        pix = im.load()
        self.write((0x2A, 0x00, x1 + 2, 0x00, x2 + 2))
        self.write((0x2B, 0x00, y1 + 1, 0x00, y2 + 1))
        self.write_cmd(0x2C)
        GPIO.output(self.rs, True)   # RS=1
        pixline = []
        px = x1
        py = y1
        for i in range(10):
            for n in range(2048):
                pixel = pix[px, py]
                hi = pixel[0] & 0xF8 | pixel[1] >> 5
                lo = pixel[1] & 0xFC << 3 | pixel[2] >> 3
                pixline.extend([hi, lo])
                px = px + 1
                if px > x2:
                    px = x1
                    py = py + 1
                    if py > y2:
                        break
            self.spi.xfer2(pixline)
            del pixline[:]
            if py > y2:
                break

if __name__ == "__main__":
    lcd = ST7735(RstPort, RSPort)
    im = Image.new('RGBA', (128, 160), (0, 0, 0))
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf", 16)
    try:
        draw.rectangle([0, 0, 127, 159], fill=(0x00, 0x00, 0x00))
        draw.line([0, 0, 127, 0], fill=(0xFF, 0x00, 0x00))
        draw.line([127, 0, 127, 159], fill=(0xFF, 0x00, 0x00))
        draw.line([0, 0, 0, 159], fill=(0xFF, 0x00, 0x00))
        draw.line([0, 159, 127, 159], fill=(0xFF, 0x00, 0x00))
        draw.line([0, 0, 127, 159], fill=(0xFF, 0xFF, 0x00))
        draw.line([127, 0, 0, 159], fill=(0xFF, 0xFF, 0x00))
        draw.pieslice([0, 16, 127, 144], 270, 30, fill=(0xFF, 0x00, 0x00))
        draw.pieslice([0, 16, 127, 144], 30, 120, fill=(0xFF, 0xFF, 0x00))
        draw.pieslice([0, 16, 127, 144], 120, 180, fill=(0x00, 0xFF, 0xFF))
        draw.pieslice([0, 16, 127, 144], 180, 225, fill=(0x00, 0xFF, 0x00))
        draw.pieslice([0, 16, 127, 144], 225, 270, fill=(0xFF, 0x00, 0xFF))
        draw.text([0, 0], "Hello World!", font=font, fill=(0xFF, 0xFF, 0xFF))
        draw.text([2, 16], "Hello World!", font=font, fill=(0xFF, 0xFF, 0x00))
        draw.text([4, 32], "Hello World!", font=font, fill=(0x00, 0xFF, 0xFF))
        draw.text([6, 48], "Hello World!", font=font, fill=(0x00, 0xFF, 0x00))
        draw.text([8, 64], "Hello World!", font=font, fill=(0xFF, 0x00, 0xFF))
        draw.text([10, 80], "Hello World!", font=font, fill=(0xFF, 0x00, 0x00))
        draw.text([12, 96], "Hello World!", font=font, fill=(0x00, 0x00, 0xFF))
        lcd.trans(im)
        time.sleep(2)
        for i in range(10):
            py = i * 12 + 20; 
            for n in range(10):
                px = n * 12 + 4
                draw.rectangle([px, py, px + 10, py + 10], fill=(0xFF, 0xFF, 0xFF))    
                draw.rectangle([px, py, px + 10, py + 10], outline=(0, 0, 0))    
                lcd.blit(im, px, py, px + 10, py + 10)
        random.seed()
        while True:
            px = random.randint(0, 9) * 12 + 4
            py = random.randint(0, 9) * 12 + 20
            r = random.randint(0, 255)
            g = random.randint(0, 255)
            b = random.randint(0, 255)
            draw.rectangle([px, py, px + 10, py + 10], fill=(r, g, b))    
            draw.rectangle([px, py, px + 10, py + 10], outline=(0, 0, 0))    
            lcd.blit(im, px, py, px + 10, py + 10)
            pass
    except KeyboardInterrupt:
        print '\nbreak'
    GPIO.cleanup()
広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中