13 Nov 2013

Led matrix graphical user interface on the RaspberryPi

Yesterday, I plugged into my Raspberry Pi a little i2c LED Matrix. I wrote Python class to interact with it but I tought it would be really interesting to toggle the matrix's LED with a graphical user interface on the Pi itself. This is exactly what I done and you can take a look at the result in the following Youtube video:



To connections between the matrix and the Pi are really simple, you just need to connect 4 signals directly together : GND, 3V3, DATA and CLK. There is no need for pull-up resistor on the i2c clock and data lines, I presume the Pi already have them. The display is designed for 5V but it works really well at 3.3V.

For using i2c on the Raspberry Pi, you need to make some little configurations and install the Python libraries. These steps are outlined on this Instructable tutorial.

You will also need the PyQt4 package, install it with:
sudo apt-get install python-qt4

The final Python script is listed below. The LedMatrix class is the i2c communication part of my program and MatrixWidget is the graphical user interface. The Qt windows part does essentially two things, it reacts to mouse press and draw an array of ellipse (the virtual LEDs).

If you have any questions with the code, just ask in the comments and I will be glad to help. Happy coding!

#!/usr/bin/env python
import sys
from smbus import SMBus
from PyQt4 import QtGui, QtCore

class LedMatrix():
    ADDRESS = 0x70
    OSCILLATOR_ON = 0x21
    BLINK_CMD = 0x80
    DISPLAY_ON = 0x01
    BLINK_2HZ = 0x01
    BLINK_1HZ = 0x02
    BLINK_HALFHZ = 0x03
    BRIGHTNESS_CMD = 0xE0
    POS_X = (128, 1, 2, 4, 8, 16, 32, 64)
    POSn_X = (127, 254, 253, 251, 247, 239, 223, 191)
    POS_Y = (7, 0, 1, 2, 3, 4, 5, 6)

    def __init__(self, blink=0, brightness=15):
        self.bus = SMBus(1) #device on i2c channel 1
        self.bus.write_byte(self.ADDRESS, self.OSCILLATOR_ON)
        self.bus.write_byte(self.ADDRESS, self.BLINK_CMD|self.DISPLAY_ON|(blink<<1))
        self.bus.write_byte(self.ADDRESS, self.BRIGHTNESS_CMD|brightness)
        self.clearBuffer()

    def setBrightness(self, brightness):
        self.bus.write_byte(self.ADDRESS, self.BRIGHTNESS_CMD|brightness)
        
    def setBlinkRate(self, blink):      
        self.bus.write_byte(self.ADDRESS, self.BLINK_CMD|self.DISPLAY_ON|(blink<<1))
    
    def setPixel(self, x, y, state):
        if state:
            self.buffer[self.POS_Y[y]]|=self.POS_X[x]
        else:
            self.buffer[self.POS_Y[y]]&=self.POSn_X[x]

    def clearBuffer(self):
        self.buffer = [0]*8
    
    def writeBuffer(self):
        data = []
        for row in self.buffer:
            data.append(0)
            data.append(row)
        self.bus.write_block_data(self.ADDRESS, 0x00, data)

class MatrixWidget(QtGui.QWidget):
    def __init__(self):
        super(MatrixWidget, self).__init__()     
        self.w=20
        self.setGeometry(300, 300, self.w*10, self.w*10)
        self.setWindowTitle('Led Matrix')
        self.clearPixelBuffer()
        self.setFixedSize(self.width(),self.height())
        self.leds = LedMatrix()
        self.show()

    def clearPixelBuffer(self):
        self.buffer = [[0 for _ in range(8)] for _ in range(8)]

    def mousePressEvent(self, QMouseEvent):
        x = QMouseEvent.pos().x()
        y = QMouseEvent.pos().y()
        x = x/self.w-1
        y = y/self.w-1
        if x==-1 or y==-1 or x==8 or y==8:
            self.clearPixelBuffer()
            self.update()
            self.leds.clearBuffer()
            self.leds.writeBuffer()
            return
        pixel = self.buffer[x][y]
        if pixel:
            self.leds.setPixel(x, y, False)
            self.buffer[x][y]=0
        else:
            self.leds.setPixel(x, y, True)
            self.buffer[x][y]=1        
        self.update()
        self.leds.writeBuffer()
    
    def paintEvent(self, e):
        qp = QtGui.QPainter()
        qp.begin(self)
        self.refresh(qp, e)
        qp.end()
    
    def drawLed(self, qp, x, y):
        state = self.buffer[x][y]
        if state:
            col = QtGui.QColor("#FFF71C") #bright yellow
        else:
            col = QtGui.QColor("#373511") #dark yellow
        qp.setPen(col)
        qp.setBrush(col)
        qp.drawEllipse(self.w+self.w*x,self.w+self.w*y,self.w-3,self.w-3)
           
    def refresh(self, qp, event):
        qp.setBrush(QtCore.Qt.black)
        qp.drawRect(event.rect())
        for y in range(8):
            for x in range(8):
                self.drawLed(qp, x, y)

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    ex = MatrixWidget()
    sys.exit(app.exec_())

No comments:

Post a Comment