Найти - Пользователи
Полная версия: Дисплей ssd1306
Начало » Python для новичков » Дисплей ssd1306
1
ingfa_1981
Привествую
Вопрос такой возник.
Пытался поизучать протокол работы oled дисплея ssd1306 128x64, по шине i2c. В MX линукс подключил переходник который,
появился как i2c-10, ну и через библиотеку smbus2 передаю команды. Из кода видно что хочу вывести текст в первой и последней строке дисплея. Выводится последняя строка на месте первой. Первая строка вообще не выводится.
К тому же строка обтекается белым фоном, которым залит дисплей.
Что я делаю не так, может кто разбирался ранее с такими вещами? Практического применения не вижу (просто мне так удобно изучить тему), на контроллерах этот дисплей с их библиотеками прекрасно работает.


 from smbus2 import SMBus
# Из C библиотеки
SSD1306_I2C_ADDRESS = 0x3C    # 011110+SA0+RW - 0x3C or 0x3D
SSD1306_EXTERNALVCC = 0x1
SSD1306_SETLOWCOLUMN     = 0x00
SSD1306_SETHIGHCOLUMN    = 0x10
SSD1306_MEMORYMODE       = 0x20
SSD1306_COLUMNADDR       = 0x21
SSD1306_PAGEADDR         = 0x22
SSD1306_SETSTARTLINE     = 0x40
SSD1306_DEFAULT_ADDRESS  = 0x78
SSD1306_SETCONTRAST      = 0x81
SSD1306_CHARGEPUMP       = 0x8D
SSD1306_SEGREMAP         = 0xA0
SSD1306_DISPLAYALLON_RESUME = 0xA4
SSD1306_DISPLAYALLON     = 0xA5
SSD1306_NORMALDISPLAY    = 0xA6
SSD1306_INVERTDISPLAY    = 0xA7
SSD1306_SETMULTIPLEX     = 0xA8
SSD1306_DISPLAYOFF       = 0xAE
SSD1306_DISPLAYON        = 0xAF
SSD1306_SETPAGE          = 0xB0
SSD1306_COMSCANINC       = 0xC0
SSD1306_COMSCANDEC       = 0xC8
SSD1306_SETDISPLAYOFFSET = 0xD3
SSD1306_SETDISPLAYCLOCKDIV = 0xD5
SSD1306_SETPRECHARGE     = 0xD9
SSD1306_SETCOMPINS       = 0xDA
SSD1306_SETVCOMDETECT    = 0xDB
SSD1306_SWITCHCAPVCC     = 0x02
SSD1306_NOP              = 0xE3
HORIZONTAL_ADDRESSING_MODE  = 0x00
VERTICAL_ADDRESSING_MODE    = 0x01
PAGE_ADDRESSING_MODE        = 0x02
class SSD1306Base(object):
    def __init__(self, width, height):
        self.i2c = SMBus(10)
        self.width = width
        self.height = height
        self._pages = height//8
        self._buffer = [0]*(width*self._pages)
    def _initialize(self):
        raise NotImplementedError
    def command(self, c):
        control = 0x00   # Co = 0, DC = 0
        self.i2c.write_i2c_block_data(SSD1306_I2C_ADDRESS, control,[c])
    def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
        """Initialize display."""
        # Save vcc state.
        self._vccstate = vccstate
        # initialize display.
        self._initialize()
        # Turn on the display.
        self.command(SSD1306_DISPLAYON)
    def display(self):
        self.command(0x00)
        self.command(SSD1306_COLUMNADDR)
        self.command(0)              # Column start address. (0 = reset)
        self.command(self.width-1)   # Column end address.
        self.command(SSD1306_PAGEADDR)
        self.command(0)              # Page start address. (0 = reset)
        self.command(self._pages-1)  # Page end address.
        # Write buffer data.
        for i in range(0, len(self._buffer), 16):
            control = 0x40   # Co = 0, DC = 0
            self.i2c.write_i2c_block_data(SSD1306_I2C_ADDRESS, control,self._buffer[i:i+16])
    def image(self, image):
        """Set buffer to value of Python Imaging Library image.  The image should
        be in 1 bit mode and a size equal to the display size.
        """
        imwidth, imheight = image.size
        if imwidth != self.width or imheight != self.height:
            raise ValueError('Image must be same dimensions as display ({0}x{1}).'.format(self.width, self.height))
        pix = image.load()
        # Iterate through the memory pages
        index = 0
        for page in range(self._pages):
            for x in range(self.width):#128
                # Set the bits for the column of pixels at the current position.
                bits = 0
                # Don't use range here as it's a bit slow
                for bit in [0, 1, 2, 3, 4, 5, 6, 7]:
                    bits = bits << 1
                    bits |= 0 if pix[(x, page*8+7-bit)] == 0 else 1
                # Update buffer byte and increment to next byte.
                self._buffer[index] = bits
                index += 1
        self.save(image)
    def save(self, image):
        """save contents of buffer for further analysis"""
        with open("out.bin", "wb") as f:
            f.write(bytes(self._buffer))
        image.save("out_raw.bmp")
    def clear(self):
        """Clear contents of image buffer."""
        self._buffer = [0]*(self.width*self._pages)
    def set_contrast(self, contrast):
        """Sets the contrast of the display.  Contrast should be a value between
        0 and 255."""
        if contrast < 0 or contrast > 255:
            raise ValueError('Contrast must be a value from 0 to 255 (inclusive).')
        self.command(SSD1306_SETCONTRAST)
        self.command(contrast)
    def dim(self, dim):
        """Adjusts contrast to dim the display if dim is True, otherwise sets the
        contrast to normal brightness if dim is False.
        """
        # Assume dim display.
        contrast = 0
        # Adjust contrast based on VCC if not dimming.
        if not dim:
            if self._vccstate == SSD1306_EXTERNALVCC:
                contrast = 0x9F
            else:
                contrast = 0xCF
class SSD1306_128_64(SSD1306Base):
    def __init__(self):
        # Call base class constructor.
        super(SSD1306_128_64, self).__init__(128,64)
    def _initialize(self):
        initial = [SSD1306_DISPLAYOFF,
SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE,
SSD1306_COMSCANDEC,
SSD1306_SETSTARTLINE | 0x00,
SSD1306_SETCONTRAST, 0x7F,
SSD1306_SEGREMAP | 0x01,
SSD1306_NORMALDISPLAY,
SSD1306_SETMULTIPLEX, 63,
SSD1306_SETDISPLAYOFFSET, 0x00,
SSD1306_SETDISPLAYCLOCKDIV, 0x80,
SSD1306_SETPRECHARGE, 0x22,
SSD1306_SETCOMPINS, 0x12,
SSD1306_SETVCOMDETECT, 0x20,
SSD1306_CHARGEPUMP, 0x14,
SSD1306_DISPLAYALLON_RESUME,
SSD1306_DISPLAYON]
        for i in initial:
            self.command(i)
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
disp = SSD1306_128_64()
disp.begin()
disp.clear()
disp.display()
image = Image.new('1', (128, 64))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('arial.ttf', 18)
draw.text((0, 50),'Hello',  font=font, fill=255)
draw.text((0, 10),'Hello10',  font=font, fill=255)
disp.image(image)
disp.display()
xam1816
 
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw

image = Image.new('1', (128, 64))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('arial.ttf', 18)
draw.text((0, 0),'Hello', font=font, fill=255)
draw.text((0, 10),'Hello10', font=font, fill=255)

image.show()
ingfa_1981
xam1816
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw

image = Image.new('1', (128, 64))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('arial.ttf', 18)
draw.text((0, 0),'Hello', font=font, fill=255)
draw.text((0, 10),'Hello10', font=font, fill=255)

image.show()
на картинке все вравильно на дисплее
draw.text((0, 0),'Hello', font=font, fill=255)
draw.text((0, 10),'Hello10', font=font, fill=255)

ничего не видно
Если выполнить
draw.text((0,50),'Hello10', font=font, fill=255
то отобразится как первая строка
xam1816
ingfa_1981
Если выполнить
draw.text((0,50),'Hello10', font=font, fill=255
то отобразится как первая строка
а если 2ю строку считать как 0, 60, отобразится? приложи фото через https://imgur.com/ например, там есть ссылка для вставки на форуме, чтобы сразу картинка в сообщении отображалась
ingfa_1981
 import time
import smbus2 as smbus
from PIL import Image,ImageFont,ImageDraw
_COMMAND_MODE = 0x80
_DATA_MODE = 0x40
_NORMAL_DISPLAY = 0xA6
_DISPLAY_OFF = 0xAE
_DISPLAY_ON = 0xAF
_INVERSE_DISPLAY = 0xA7
_SET_BRIGHTNESS = 0x81
BasicFont = [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00],
             [0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00],
             [0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x00],
             [0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00],
             [0x00, 0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x00],
             [0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00],
             [0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00],
             [0x00, 0xA0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00],
             [0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00],
             [0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00],
             [0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, 0x00],
             [0x00, 0x62, 0x51, 0x49, 0x49, 0x46, 0x00, 0x00],
             [0x00, 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, 0x00],
             [0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x00],
             [0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00],
             [0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00, 0x00],
             [0x00, 0x01, 0x71, 0x09, 0x05, 0x03, 0x00, 0x00],
             [0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00],
             [0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00],
             [0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x00, 0xAC, 0x6C, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00],
             [0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00],
             [0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00],
             [0x00, 0x02, 0x01, 0x51, 0x09, 0x06, 0x00, 0x00],
             [0x00, 0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, 0x00],
             [0x00, 0x7E, 0x09, 0x09, 0x09, 0x7E, 0x00, 0x00],
             [0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00],
             [0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00],
             [0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00, 0x00],
             [0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00],
             [0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x00],
             [0x00, 0x3E, 0x41, 0x41, 0x51, 0x72, 0x00, 0x00],
             [0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00],
             [0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, 0x00],
             [0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00],
             [0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00],
             [0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00, 0x00],
             [0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x00],
             [0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00],
             [0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00],
             [0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x00],
             [0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x00],
             [0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00],
             [0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, 0x00],
             [0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x00],
             [0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x00],
             [0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x00],
             [0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00],
             [0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x00],
             [0x00, 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00],
             [0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00],
             [0x00, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00],
             [0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
             [0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x00],
             [0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, 0x00, 0x00],
             [0x00, 0x38, 0x44, 0x44, 0x28, 0x00, 0x00, 0x00],
             [0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00],
             [0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00],
             [0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x00, 0x00],
             [0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, 0x00, 0x00],
             [0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00],
             [0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x80, 0x84, 0x7D, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00],
             [0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, 0x00],
             [0x00, 0x7C, 0x08, 0x04, 0x7C, 0x00, 0x00, 0x00],
             [0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00],
             [0x00, 0xFC, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00],
             [0x00, 0x18, 0x24, 0x24, 0xFC, 0x00, 0x00, 0x00],
             [0x00, 0x00, 0x7C, 0x08, 0x04, 0x00, 0x00, 0x00],
             [0x00, 0x48, 0x54, 0x54, 0x24, 0x00, 0x00, 0x00],
             [0x00, 0x04, 0x7F, 0x44, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x3C, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00],
             [0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x00],
             [0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x00],
             [0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00],
             [0x00, 0x1C, 0xA0, 0xA0, 0x7C, 0x00, 0x00, 0x00],
             [0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00],
             [0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, 0x00],
             [0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x00],
             [0x00, 0x02, 0x05, 0x05, 0x02, 0x00, 0x00, 0x00]]
class GroveOledDisplay128x64(object):
    HORIZONTAL = 0x00
    VERTICAL = 0x01
    PAGE = 0x02
    def __init__(self, bus=10, address=0x3C):
        self.bus = smbus.SMBus(bus)
        self.address = address
        self.off()
        self.inverse = False
        self.mode = self.HORIZONTAL
        self.clear()
        self.on()
    def on(self):
        self.send_command(_DISPLAY_ON)
    def off(self):
        self.send_command(_DISPLAY_OFF)
    def send_command(self, command):
        self.bus.write_byte_data(self.address, _COMMAND_MODE, command)
    def send_data(self, data):
        self.bus.write_byte_data(self.address, _DATA_MODE, data)
    def send_commands(self, commands):
        for c in commands:
            self.send_command(c)
    def clear(self):
        self.off()
        for i in range(8):
            self.set_cursor(i, 0)
            self.puts(' ' * 16)
        self.on()
        self.set_cursor(0, 0)
    @property
    def inverse(self):
        return self._inverse
    @inverse.setter
    def inverse(self, enable):
        self.send_command(_INVERSE_DISPLAY if enable else _NORMAL_DISPLAY)
        self._inverse = enable
    @property
    def mode(self):
        return self._mode
    @mode.setter
    def mode(self, mode):
        self.send_command(0x20)
        self.send_command(mode)
        self._mode = mode
    def set_cursor(self, row, column):
        self.send_command(0xB0 + row)
        self.send_command(0x00 + (8 * column & 0x0F))
        self.send_command(0x10 + ((8 * column >> 4) & 0x0F))
    def putc(self, c):
        C_add = ord(c)
        if C_add < 32 or C_add > 127:  # Ignore non-printable ASCII characters
            c = ' '
            C_add = ord(c)
        for i in range(0, 8):
            self.send_data(BasicFont[C_add - 32][i])
    def puts(self, text):
        for c in text:
            self.putc(c)
    def show_image(self, image):
        from PIL import Image
        import numpy as np
        image.save("ssd1306.bmp")
        #im = Image.open(image)
        #bw = im.convert('1')
        #pixels = np.array(bw.getdata())
        pixels = np.array(image.getdata())
        page_size = 128 * 8
        self.set_cursor(0, 0)
        for page in range(8):
            start = page_size * page
            end = start + page_size
            for i in range(start, start + 128):
                data = np.packbits(pixels[i:end:128][::-1])[0]
                self.send_data(data)
display = GroveOledDisplay128x64(bus=10)
image = Image.new('1', (128, 64))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('/home/konsyst/arial.ttf', 15)
draw.text((0,50),'Hello',  font=font, fill=255)
display.show_image(image)
display.set_cursor(0, 2)
display.puts('hello')
display.set_cursor(1, 4)
display.puts('world')
display.set_cursor(2, 2)
display.puts('privet')
image.show()

Не могу сфотографировать, по некоторым причинам.
Нашел другой пример
 display = GroveOledDisplay128x64(bus=10)
image = Image.new('1', (128, 64))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('/home/konsyst/arial.ttf', 15)
draw.text((0,50),'Hello',  font=font, fill=255)
display.show_image(image)
Через Pill выводится на экран не в том месте.Вначале экрана вместо последней строки экрана.
А вот текст выводится правильно. Этот вывод работает.
 display.set_cursor(0, 2)
display.puts('hello')
display.set_cursor(1, 4)
display.puts('world')
display.set_cursor(2, 2)
display.puts('privet')

This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB