===== Эксперимент 54. Управление кладовщиком =====
Научим кладовщика двигаться при нажатии на кнопки "вверх", "вниз", "влево" и "вправо".
Подключим кнопки к микроконтроллеру. Три кнопки подтянуты к земле, а одна к питанию. Это сделано специально, чтобы обеспечить условия для правильной загрузки микроконтроллера. Микроконтроллер при включении проверяет состояние некоторых выводов и на основании этого принимает решение о режиме работы — выполнение программы или переход в режим перепрошивки. Для нормального режима работы необходимо, чтобы уровень сигнала на выводе 15 был низким, а на 2 и 0 был высоким. Чтобы соблюсти эти условия и пришлось подключить кнопки по-разному.
==== Схема эксперимента ====
{{ :products:esp-iot:exp27_mont.png?direct&600 |}}
//Рисунок 1. Монтажная схема эксперимента с 8 выводами//
{{ :products:esp-iot:exp27_mont_11pin.png?direct&600 |}}
//Рисунок 2. Монтажная схема эксперимента с 11 выводами//
==== Программный код эксперимента ====
from machine import Pin, SPI
from tft import TFT_GREEN
_init()
machine.freq(160000000)
dc = Pin(4, Pin.OUT) #a0
cs = Pin(2, Pin.OUT)
rst = Pin(5, Pin.OUT)
spi = SPI(1, baudrate=40000000, polarity=0, phase=0)
# TFT object, this is ST7735R green tab version
tft = TFT_GREEN(128, 160, spi, dc, cs, rst, rotate=0)
Map = [
[1,1,0,1,1,1,0,1],
[0,1,1,1,1,1,1,0],
[1,1,0,0,0,1,1,1],
[0,1,0,1,0,1,0,1],
[0,1,0,0,0,1,0,1],
[1,1,1,1,0,0,0,1],
[1,0,0,0,0,0,0,1],
[1,0,0,0,1,0,0,1],
[1,0,0,0,1,1,1,1],
[1,1,1,1,1,0,0,0]
]
Gates = []
Boxes = []
class Box:
def __init__(self, tft, x, y):
self.tft = tft
self.x = x
self.y = y
self.picture = 'box.bmp'
self.picture_onGate = 'boxngate.bmp'
self.onGate = False
self.draw()
def draw(self):
if (self.onGate):
self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture_onGate)
else:
self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
def setOnGate(self, state):
self.onGate = state
def getOnGate(self):
return self.onGate
def getPos(self):
return (self.x, self.y)
def setPos(self, x, y):
self.x = x
self.y = y
self.draw()
class Gate:
def __init__(self, tft, x, y):
self.tft = tft
self.x = x
self.y = y
self.picture = 'gate.bmp'
self.draw()
def draw(self):
self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
def getPos(self):
return (self.x, self.y)
class Man:
def __init__(self, tft, x, y):
self.tft = tft
self.x = x
self.y = y
self.picture = 'man.bmp'
self.draw()
def draw(self):
self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
def getPos(self):
return (self.x, self.y)
def setPos(self, x, y):
self.tft.rect(self.x * 16, self.y * 16, 16, 16, tft.COLOR_BLACK)
self.x = x
self.y = y
self.draw()
class Button:
def __init__(self, p, pressSate):
self.pin = Pin(p, Pin.IN)
self.pressSate = pressSate
self.oldState = not pressSate
def onPress(self):
state = self.pin.value()
if state != self.oldState:
self.oldState = state
if state == self.pressSate:
return True
return False
# init TFT
tft.initr(tft.BGR) # tft.initr(tft.RGB) #Если вместо синего цвета отображается красный, а вместо красного синий
tft.clear(tft.COLOR_BLACK) #b, g, r
x = 0
y = 0
for row in Map:
for col in row:
if col:
tft.draw_bmp(x * 16, y * 16,'brick.bmp')
x+=1
x=0
y+=1
Boxes.append(Box(tft, 3,4))
Boxes.append(Box(tft, 4,6))
Boxes.append(Box(tft, 2,7))
Gates.append(Gate(tft, 6,3))
Gates.append(Gate(tft, 6,4))
Gates.append(Gate(tft, 6,5))
man = Man(tft, 5, 6)
btnUp = Button(16, 1)
btnDown = Button(15, 1)
btnLeft = Button(12, 1)
btnRight = Button(0, 0)
while True:
mPos = man.getPos()
if btnUp.onPress():
newPos = (mPos[0], mPos[1]-1)
man.setPos(newPos[0], newPos[1])
if btnDown.onPress():
newPos = (mPos[0], mPos[1]+1)
man.setPos(newPos[0], newPos[1])
if btnLeft.onPress():
newPos = (mPos[0]-1, mPos[1])
man.setPos(newPos[0], newPos[1])
if btnRight.onPress():
newPos = (mPos[0]+1, mPos[1])
man.setPos(newPos[0], newPos[1])
В код прошлого эксперимента мы добавили класс кнопки, который уже использовали ранее, например в проекте секундомера. Объявили 4 кнопки, на выводах 16, 15, 12 и 0:
btnUp = Button(16, 1)
btnDown = Button(15, 1)
btnLeft = Button(12, 1)
btnRight = Button(0, 0)
Добавили бесконечный цикл, в котором постоянно мониторим события нажатия на кнопки:
while True:
mPos = man.getPos()
if btnUp.onPress():
newPos = (mPos[0], mPos[1]-1)
man.setPos(newPos[0], newPos[1])
if btnDown.onPress():
newPos = (mPos[0], mPos[1]+1)
man.setPos(newPos[0], newPos[1])
if btnLeft.onPress():
newPos = (mPos[0]-1, mPos[1])
man.setPos(newPos[0], newPos[1])
if btnRight.onPress():
newPos = (mPos[0]+1, mPos[1])
man.setPos(newPos[0], newPos[1])
При нажатии на кнопку "вверх" уменьшаем координату Y и задаем новую координату кладовщику. Аналогичные действия производим при нажатии на другие кнопки. Теперь наш кладовщик может двигаться по экрану. Но сейчас нет никаких ограничений — он свободно проходит сквозь стены и ящики, никак на них не влияя. Теперь самое время реализовать логику игры, описать условия и взаимодействия. Этим займемся в следующем эксперименте.