Эксперимент 54. Управление кладовщиком

Научим кладовщика двигаться при нажатии на кнопки «вверх», «вниз», «влево» и «вправо».

Подключим кнопки к микроконтроллеру. Три кнопки подтянуты к земле, а одна к питанию. Это сделано специально, чтобы обеспечить условия для правильной загрузки микроконтроллера. Микроконтроллер при включении проверяет состояние некоторых выводов и на основании этого принимает решение о режиме работы — выполнение программы или переход в режим перепрошивки. Для нормального режима работы необходимо, чтобы уровень сигнала на выводе 15 был низким, а на 2 и 0 был высоким. Чтобы соблюсти эти условия и пришлось подключить кнопки по-разному.

Схема эксперимента

Рисунок 1. Монтажная схема эксперимента с 8 выводами

Рисунок 2. Монтажная схема эксперимента с 11 выводами

Программный код эксперимента

Exp54.py
  1. from machine import Pin, SPI
  2. from tft import TFT_GREEN
  3. _init()
  4. machine.freq(160000000)
  5.  
  6.  
  7. dc = Pin(4, Pin.OUT) #a0
  8. cs = Pin(2, Pin.OUT)
  9. rst = Pin(5, Pin.OUT)
  10. spi = SPI(1, baudrate=40000000, polarity=0, phase=0)
  11.  
  12.  
  13. # TFT object, this is ST7735R green tab version
  14. tft = TFT_GREEN(128, 160, spi, dc, cs, rst, rotate=0)
  15.  
  16. Map = [
  17. [1,1,0,1,1,1,0,1],
  18. [0,1,1,1,1,1,1,0],
  19. [1,1,0,0,0,1,1,1],
  20. [0,1,0,1,0,1,0,1],
  21. [0,1,0,0,0,1,0,1],
  22. [1,1,1,1,0,0,0,1],
  23. [1,0,0,0,0,0,0,1],
  24. [1,0,0,0,1,0,0,1],
  25. [1,0,0,0,1,1,1,1],
  26. [1,1,1,1,1,0,0,0]
  27. ]
  28.  
  29. Gates = []
  30. Boxes = []
  31.  
  32. class Box:
  33. def __init__(self, tft, x, y):
  34. self.tft = tft
  35. self.x = x
  36. self.y = y
  37. self.picture = 'box.bmp'
  38. self.picture_onGate = 'boxngate.bmp'
  39. self.onGate = False
  40. self.draw()
  41.  
  42. def draw(self):
  43. if (self.onGate):
  44. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture_onGate)
  45. else:
  46. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
  47.  
  48. def setOnGate(self, state):
  49. self.onGate = state
  50.  
  51. def getOnGate(self):
  52. return self.onGate
  53.  
  54. def getPos(self):
  55. return (self.x, self.y)
  56.  
  57. def setPos(self, x, y):
  58. self.x = x
  59. self.y = y
  60. self.draw()
  61.  
  62. class Gate:
  63. def __init__(self, tft, x, y):
  64. self.tft = tft
  65. self.x = x
  66. self.y = y
  67. self.picture = 'gate.bmp'
  68. self.draw()
  69.  
  70. def draw(self):
  71. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
  72.  
  73. def getPos(self):
  74. return (self.x, self.y)
  75.  
  76. class Man:
  77. def __init__(self, tft, x, y):
  78. self.tft = tft
  79. self.x = x
  80. self.y = y
  81. self.picture = 'man.bmp'
  82. self.draw()
  83.  
  84. def draw(self):
  85. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
  86.  
  87. def getPos(self):
  88. return (self.x, self.y)
  89.  
  90. def setPos(self, x, y):
  91. self.tft.rect(self.x * 16, self.y * 16, 16, 16, tft.COLOR_BLACK)
  92. self.x = x
  93. self.y = y
  94. self.draw()
  95.  
  96.  
  97. class Button:
  98. def __init__(self, p, pressSate):
  99. self.pin = Pin(p, Pin.IN)
  100. self.pressSate = pressSate
  101. self.oldState = not pressSate
  102.  
  103. def onPress(self):
  104. state = self.pin.value()
  105. if state != self.oldState:
  106. self.oldState = state
  107. if state == self.pressSate:
  108. return True
  109. return False
  110.  
  111.  
  112. # init TFT
  113. tft.initr(tft.BGR) # tft.initr(tft.RGB) #Если вместо синего цвета отображается красный, а вместо красного синий
  114. tft.clear(tft.COLOR_BLACK) #b, g, r
  115.  
  116. x = 0
  117. y = 0
  118.  
  119. for row in Map:
  120. for col in row:
  121. if col:
  122. tft.draw_bmp(x * 16, y * 16,'brick.bmp')
  123. x+=1
  124. x=0
  125. y+=1
  126.  
  127. Boxes.append(Box(tft, 3,4))
  128. Boxes.append(Box(tft, 4,6))
  129. Boxes.append(Box(tft, 2,7))
  130.  
  131. Gates.append(Gate(tft, 6,3))
  132. Gates.append(Gate(tft, 6,4))
  133. Gates.append(Gate(tft, 6,5))
  134.  
  135. man = Man(tft, 5, 6)
  136.  
  137. btnUp = Button(16, 1)
  138. btnDown = Button(15, 1)
  139. btnLeft = Button(12, 1)
  140. btnRight = Button(0, 0)
  141.  
  142. while True:
  143. mPos = man.getPos()
  144.  
  145. if btnUp.onPress():
  146. newPos = (mPos[0], mPos[1]-1)
  147. man.setPos(newPos[0], newPos[1])
  148.  
  149. if btnDown.onPress():
  150. newPos = (mPos[0], mPos[1]+1)
  151. man.setPos(newPos[0], newPos[1])
  152.  
  153. if btnLeft.onPress():
  154. newPos = (mPos[0]-1, mPos[1])
  155. man.setPos(newPos[0], newPos[1])
  156.  
  157. if btnRight.onPress():
  158. newPos = (mPos[0]+1, mPos[1])
  159. man.setPos(newPos[0], newPos[1])

В код прошлого эксперимента мы добавили класс кнопки, который уже использовали ранее, например в проекте секундомера. Объявили 4 кнопки, на выводах 16, 15, 12 и 0:

  1. btnUp = Button(16, 1)
  2. btnDown = Button(15, 1)
  3. btnLeft = Button(12, 1)
  4. btnRight = Button(0, 0)

Добавили бесконечный цикл, в котором постоянно мониторим события нажатия на кнопки:

  1. while True:
  2. mPos = man.getPos()
  3.  
  4. if btnUp.onPress():
  5. newPos = (mPos[0], mPos[1]-1)
  6. man.setPos(newPos[0], newPos[1])
  7.  
  8. if btnDown.onPress():
  9. newPos = (mPos[0], mPos[1]+1)
  10. man.setPos(newPos[0], newPos[1])
  11.  
  12. if btnLeft.onPress():
  13. newPos = (mPos[0]-1, mPos[1])
  14. man.setPos(newPos[0], newPos[1])
  15.  
  16. if btnRight.onPress():
  17. newPos = (mPos[0]+1, mPos[1])
  18. man.setPos(newPos[0], newPos[1])

При нажатии на кнопку «вверх» уменьшаем координату Y и задаем новую координату кладовщику. Аналогичные действия производим при нажатии на другие кнопки. Теперь наш кладовщик может двигаться по экрану. Но сейчас нет никаких ограничений — он свободно проходит сквозь стены и ящики, никак на них не влияя. Теперь самое время реализовать логику игры, описать условия и взаимодействия. Этим займемся в следующем эксперименте.