`Although it is an article on Mac environment, the procedure is the same for Windows environment. Please read and try the environment-dependent part. ``
Create a math game using LCD1602A 16x2 I2C.
After reading this article to the end, you will be able to:
No. | Overview | keyword |
---|---|---|
1 | Electronic circuit | |
2 | LCD control | SMBus |
3 | Button control | gpiozero |
screen | Button 1 | Button 2 |
---|---|---|
menu | Selection of addition and subtraction | Decision |
addition | Return to the menu by displaying the next question and displaying the 11th question | Displaying the answer |
subtraction | Return to the menu by displaying the next question and displaying the 11th question | Displaying the answer |
menu | addition | subtraction |
---|---|---|
environment | Ver. |
---|---|
macOS Catalina | 10.15.6 |
Raspberry Pi 4 Model B 4GB RAM | - |
Raspberry Pi OS (Raspbian) | 10 |
Python | 3.7.3 |
gpiozero | 1.5.1 |
RPi.GPIO | 0.7.0 |
smbus2 | 0.3.0 |
I think that understanding will deepen if you read while actually following the implementation contents and source code. Please use it by all means.
-From Raspberry Pi setup to Python environment installation -Create a remote control car with Raspberry Pi and Python
command.sh
~$ sudo raspi-config
5 Interfacing Options
P5 I2C
command.sh
~$ sudo reboot
command.sh
~$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
The I2C communication address will be 0x27
command.sh
~$ git clone https://github.com/nsuhara/raspi-lcdgame.git -b master
~$ cd raspi-lcdgame
~$ python -m venv .venv
~$ source .venv/bin/activate
~$ pip install -r requirements.txt
~$ source config
~$ python app/main.py
~$ Control Key + C
target.sh
/app
├─ addition.py
├─ i2clcd1602a
│ ├─ __init__.py
│ ├─ katakana.py
│ └─ pcf8574t.py
├─ main.py
├─ menu.py
├─ story_board.py
└─ subtraction.py
LCD
target.sh
/app
└─ i2clcd1602a
├─ __init__.py
├─ katakana.py
└─ pcf8574t.py
pcf8574t.py
"""i2clcd1602a/pcf8574t.py
"""
import time
from smbus2 import SMBus
from i2clcd1602a.katakana import convert
class LCD():
"""LCD
"""
SMBUS_REV1 = 0
SMBUS_REV2 = 1
I2C_ADDR = 0x27
ENABLE_BIT = 0b00000100
LINE_1 = 0x80
LINE_2 = 0xC0
LINE_SIZE = 16
MODE_COMMAND = 0
MODE_CHAR = 1
MODE_OPTION_BACKLIGHT = 0x08
CMD_INITIALISE = 0x33
CMD_SET_4_BIT_MODE = 0x32
CMD_CURSOR_MOVE_DIRECTION = 0x06
CMD_TURN_CURSOR_OFF = 0x0C
CMD_2_LINE_DISPLAY = 0x28
CMD_CLEAR_DISPLAY = 0x01
CMD_WAIT = 0.0005
def __init__(self):
self.smbus = SMBus(self.SMBUS_REV2)
self._send(mode=self.MODE_COMMAND, bits=self.CMD_INITIALISE)
self._send(mode=self.MODE_COMMAND, bits=self.CMD_SET_4_BIT_MODE)
self._send(mode=self.MODE_COMMAND, bits=self.CMD_CURSOR_MOVE_DIRECTION)
self._send(mode=self.MODE_COMMAND, bits=self.CMD_TURN_CURSOR_OFF)
self._send(mode=self.MODE_COMMAND, bits=self.CMD_2_LINE_DISPLAY)
self._send(mode=self.MODE_COMMAND, bits=self.CMD_CLEAR_DISPLAY)
def destroy(self):
"""destroy
"""
self._send(mode=self.MODE_COMMAND, bits=self.CMD_CLEAR_DISPLAY)
self.smbus.close()
def message(self, message, line):
"""message
"""
message = convert(message=message)
message = message[0:self.LINE_SIZE]
message = message.ljust(self.LINE_SIZE, ' ')
self._send(mode=self.MODE_COMMAND | self.MODE_OPTION_BACKLIGHT,
bits=line)
for char in message:
self._send(mode=self.MODE_CHAR | self.MODE_OPTION_BACKLIGHT,
bits=ord(char))
def clear(self):
"""close
"""
self._send(mode=self.MODE_COMMAND | self.MODE_OPTION_BACKLIGHT,
bits=self.CMD_CLEAR_DISPLAY)
def off(self):
"""off
"""
self.destroy()
def _send(self, mode, bits):
"""_send
"""
higher_bits = mode | (bits & 0xF0)
self._write(bits=higher_bits)
lower_bit = mode | ((bits << 4) & 0xF0)
self._write(bits=lower_bit)
def _write(self, bits):
"""_write
"""
self.smbus.write_byte(self.I2C_ADDR, bits)
time.sleep(self.CMD_WAIT)
self.smbus.write_byte(self.I2C_ADDR, (bits | self.ENABLE_BIT))
time.sleep(self.CMD_WAIT)
self.smbus.write_byte(self.I2C_ADDR, (bits & ~self.ENABLE_BIT))
time.sleep(self.CMD_WAIT)
def loop(self):
"""loop
"""
while True:
self.message(message='1234567890123456', line=self.LINE_1)
self.message(message='abcdefghijklmnop', line=self.LINE_2)
time.sleep(2)
self.message(message='ABCDEFGHIJKLMNOP', line=self.LINE_1)
self.message(message='Sashisuseso', line=self.LINE_2)
time.sleep(2)
if __name__ == '__main__':
lcd = LCD()
try:
print('start')
lcd.loop()
except KeyboardInterrupt:
lcd.destroy()
print('stop')
katakana.sh
"""i2clcd1602a/katakana.py
"""
SP_CODE = 0xfec0
def convert(message):
"""convert
"""
converted = []
for char in message:
if ord(char) > SP_CODE:
converted.append(chr(ord(char)-SP_CODE))
else:
converted.append(char)
return ''.join(converted)
target.sh
/app
└─ main.py
main.py
"""app/main.py
"""
from signal import pause
from time import sleep
from gpiozero import Button
from addition import Addition
from i2clcd1602a.pcf8574t import LCD
from menu import Menu
from subtraction import Subtraction
class Raspi():
"""Raspi
"""
GPIO_BCM_BUTTON1 = 15
GPIO_BCM_BUTTON2 = 25
def __init__(self):
self.lcd = LCD()
self.button1 = Button(self.GPIO_BCM_BUTTON1)
self.button1.when_pressed = self.button1_pressed
self.button1.when_released = self.button1_released
self.button2 = Button(self.GPIO_BCM_BUTTON2)
self.button2.when_pressed = self.button2_pressed
self.button2.when_released = self.button2_released
self.status = 'menu'
self.display = {
'menu': Menu(self),
'addition': Addition(self),
'subtraction': Subtraction(self)
}
self.display.get(self.status).top()
def destroy(self):
"""destroy
"""
self.lcd.off()
def button1_pressed(self):
"""button1_pressed
"""
self.display.get(self.status).button1_pressed()
def button1_released(self):
"""button1_released
"""
self.display.get(self.status).button1_released()
def button2_pressed(self):
"""button2_pressed
"""
self.display.get(self.status).button2_pressed()
def button2_released(self):
"""button2_released
"""
self.display.get(self.status).button2_released()
def pause(self):
"""pause
"""
pause()
if __name__ == '__main__':
app = Raspi()
try:
print('start')
app.pause()
except KeyboardInterrupt:
app.lcd.clear()
app.lcd.message(message='Good by...', line=app.lcd.LINE_1)
sleep(1)
app.destroy()
print('stop')
target.sh
/app
└─ story_board.py
story_board.py
"""app/story_board.py
"""
import abc
class StoryBoard(metaclass=abc.ABCMeta):
"""StoryBoard
"""
def __init__(self):
pass
@abc.abstractmethod
def top(self):
pass
@abc.abstractmethod
def button1_pressed(self):
pass
@abc.abstractmethod
def button1_released(self):
pass
@abc.abstractmethod
def button2_pressed(self):
pass
@abc.abstractmethod
def button2_released(self):
pass
target.sh
/app
├─ menu.py
└─ story_board.py
menu.py
"""app/menu.py
"""
from story_board import StoryBoard
class Menu(StoryBoard):
"""Menu
"""
def __init__(self, app):
super().__init__()
self.app = app
self.lcd = app.lcd
self.status = None
def top(self):
"""top
"""
self.lcd.message(message='Menu', line=self.lcd.LINE_1)
self.lcd.message(message='>Tashizan Hikizan', line=self.lcd.LINE_2)
self.status = 'addition'
def button1_pressed(self):
"""button1_pressed
"""
if self.status == 'addition':
self.lcd.message(message='Tashizan>Hiki Zan', line=self.lcd.LINE_2)
self.status = 'subtraction'
else:
self.lcd.message(message='>Tashizan Hikizan', line=self.lcd.LINE_2)
self.status = 'addition'
def button1_released(self):
"""button1_released
"""
print('>>> button1_released')
def button2_pressed(self):
"""button2_pressed
"""
if self.status == 'addition':
self.app.status = 'addition'
else:
self.app.status = 'subtraction'
self.app.display.get(self.app.status).top()
def button2_released(self):
"""button2_released
"""
print('>>> button2_released')
target.sh
/app
├─ addition.py
└─ story_board.py
addition.py
"""app/addition.py
"""
from random import randint
from story_board import StoryBoard
class Addition(StoryBoard):
"""Addition
"""
MAXIMUM = 5
def __init__(self, app):
super().__init__()
self.app = app
self.lcd = app.lcd
self.question = 0
self.num1 = 0
self.num2 = 0
def top(self):
"""top
"""
self.question = 0
self.num1 = 0
self.num2 = 0
self.lcd.message(message='Addition game^o^', line=self.lcd.LINE_1)
self.lcd.message(message='Kimiha Wakaru Kana?', line=self.lcd.LINE_2)
def button1_pressed(self):
"""button1_pressed
"""
self.question = self.question + 1
if self.question > 10:
self.app.status = 'menu'
self.app.display.get(self.app.status).top()
return
self.num1 = randint(1, self.MAXIMUM)
self.num2 = randint(1, self.MAXIMUM)
self.lcd.message(message='Q{}) {} + {} = ?'.format(str(self.question).zfill(2), self.num1,
self.num2), line=self.lcd.LINE_1)
self.lcd.message(message='Kotae)', line=self.lcd.LINE_2)
def button1_released(self):
"""button1_released
"""
print('>>> button1_released')
def button2_pressed(self):
"""button2_pressed
"""
if self.num1 == 0 or self.num2 == 0:
return
self.lcd.message(message='Kotae) {}'.format(
self.num1+self.num2), line=self.lcd.LINE_2)
def button2_released(self):
"""button2_released
"""
print('>>> button2_released')
target.sh
/app
├─ story_board.py
└─ subtraction.py
subtraction.py
"""app/subtraction.py
"""
from random import randint
from story_board import StoryBoard
class Subtraction(StoryBoard):
"""Subtraction
"""
MAXIMUM = 5
def __init__(self, app):
super().__init__()
self.app = app
self.lcd = app.lcd
self.question = 0
self.num1 = 0
self.num2 = 0
def top(self):
"""top
"""
self.question = 0
self.num1 = 0
self.num2 = 0
self.lcd.message(message='Hiki Zan Game^o^', line=self.lcd.LINE_1)
self.lcd.message(message='Kimiha Wakaru Kana?', line=self.lcd.LINE_2)
def button1_pressed(self):
"""button1_pressed
"""
self.question = self.question + 1
if self.question > 10:
self.app.status = 'menu'
self.app.display.get(self.app.status).top()
return
self.num1 = randint(1, self.MAXIMUM)
self.num2 = randint(1, self.MAXIMUM)
if self.num1 < self.num2:
temp = self.num1
self.num1 = self.num2
self.num2 = temp
self.lcd.message(message='Q{}) {} - {} = ?'.format(str(self.question).zfill(2), self.num1,
self.num2), line=self.lcd.LINE_1)
self.lcd.message(message='Kotae)', line=self.lcd.LINE_2)
def button1_released(self):
"""button1_released
"""
print('>>> button1_released')
def button2_pressed(self):
"""button2_pressed
"""
if self.num1 == 0 or self.num2 == 0:
return
self.lcd.message(message='Kotae) {}'.format(
self.num1-self.num2), line=self.lcd.LINE_2)
def button2_released(self):
"""button2_released
"""
print('>>> button2_released')
Recommended Posts