Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Клон Arduboy с Arduino Nano и I2C OLED-дисплеем

Компоненты и расходные материалы

Arduino Nano R3
× 1
Графический OLED-экран, 128 x 64
× 1
Зуммер
× 1
Тактильный переключатель, срабатывающий сверху
× 6
Общий катод, рассеянный RGB
× 1
Резистор 221 Ом
× 3
Резистор 10 кОм
× 1

Необходимые инструменты и машины

3D-принтер (общий)
Паяльник (общий)

Об этом проекте

Arduboy - это миниатюрная игровая система размером с кредитную карту. Он поставляется с классической 8-битной игрой и может быть перепрограммирован из библиотеки игр с открытым исходным кодом, доступных в Интернете. Arduboy имеет открытый исходный код, поэтому вы можете научиться программировать и создавать свои собственные игры. Исходная версия основана на микроконтроллере ATmega32U4 и последовательном OLED-дисплее 128x64 пикселей.

Консоль, конструкция которой представлена ​​ниже, состоит из Arduino Nano и версии I2C OLED-дисплея, которую гораздо проще найти по более низкой цене. Вы можете скачать необходимые библиотеки и код по адресу:

https://github.com/harbaum/Arduboy2

Если у вас есть 3D-принтер, вы также можете загрузить файлы .STL возможного варианта коробки, в которой установлена ​​консоль. Подробное руководство по установке доступно на том же сайте. Он питается от Arduino Nano с одной литий-ионной батареей на 3,7 В и работает довольно хорошо.

Я тестировал на этой консоли много игр, и все они отлично работают:

- ArduBreakout

- Пинбол

- Бегущий по теням

- Змея

- ВИРУС-LQP-79

- Девятнадцать43

и многое другое ...

Схема показана ниже.

В качестве примера я представляю код игры ArduBreakout, но вы можете скачать любую другую игру на сайте Arduboy, совместимую с этой версией консоли.

Код

  • Игра ArduBreakout
Игра ArduBreakout Arduino
 / * Breakout Copyright (C) 2011 Себастьян Госкик Все права защищены. Модификации Скотта Аллена 2016 г. (после предыдущих изменений ???) Эта библиотека является бесплатным программным обеспечением; вы можете распространять и / или изменять его в соответствии с условиями Стандартной общественной лицензии ограниченного применения GNU, опубликованной Free Software Foundation; либо версии 2.1 Лицензии, либо (по вашему выбору) любой более поздней версии. * / # include  // блок в EEPROM для сохранения рекордов # define EE_FILE 2Arduboy2 arduboy; BeepPin1 beep; const unsigned int FRAME_RATE =40; // Частота кадров в кадрах в секундуconst unsigned int COLUMNS =13; // Столбцы кирпичейconst unsigned int ROWS =4; // Ряды кирпича dx =-1; // Начальное движение баллинта dy =-1; // Начальное движение ballint xb; // Начальное положение шаров int yb; // Позиция старта шаровboolean выпущена; // Если мяч был выпущен игрокомboolean paused =false; // Если игра была приостановлена ​​byte xPaddle; // Позиция по оси X paddleboolean isHit [ROWS] [COLUMNS]; // Массив, если кирпичи попали или нет, boolean bounced =false; // Используется для исправления двойного отскока glitchbyte life =3; // Количество жизней в байтах level =1; // Текущий уровень без знака int score =0; // Оценка игры без подписи int brickCount; // Количество кирпичей hitboolean pad, pad2, pad3; // Буфер нажатия кнопки, используемый для остановки повторения паузыboolean oldpad, oldpad2, oldpad3; char text_buffer [16]; // Общая строка bufferboolean start =false; // Если в меню или в gameboolean initialDraw =false; // Если начальная розыгрыш произошлаchar initials [3]; // Инициалы, используемые в рекорде // Границы шара, используемые при обнаружении столкновений byte leftBall; byte rightBall; byte topBall; byte bottomBall; // Границы блоков, используемые при обнаружении столкновений byte leftBrick; byte rightBrick; byte topBrick; byte bottomBrick; byte tick; void setup () {arduboy.begin (); beep.begin (); arduboy.setFrameRate (FRAME_RATE); arduboy.initRandomSeed ();} void loop () {// приостанавливаем рендеринг до следующего кадра if (! (arduboy.nextFrame ())) return; // Обработка времени и остановки сигналов beep.timer (); // Цикл титульного экрана переключается с титульного экрана // и рекордов до тех пор, пока не будет нажата кнопка FIRE while (! Start) {start =titleScreen (); если (! старт) {старт =displayHighScores (EE_FILE); }} // Отрисовка начального уровня if (! InitialDraw) {// Очищает экран arduboy.clear (); // Выбирает шрифт // Рисует новый уровень level =1; newLevel (); оценка =0; initialDraw =true; } если (живет> 0) {drawPaddle (); // Приостановить игру, если ОГОНЬ нажал pad =arduboy.pressed (A_BUTTON) || arduboy.pressed (B_BUTTON); если (pad ==true &&oldpad ==false &&выпущено) {oldpad2 =false; // Принудительно запускает цикл 2 контактной площадки один раз pause (); } oldpad =pad; drawBall (); если (brickCount ==ROWS * COLUMNS) {уровень ++; newLevel (); }} еще {drawGameOver (); если (оценка> 0) {enterHighScore (EE_FILE); } arduboy.clear (); initialDraw =false; start =false; жизней =3; newLevel (); } arduboy.display ();} void movePaddle () {// Двигаться вправо if (xPaddle  0) {if (arduboy.pressed (LEFT_BUTTON)) {xPaddle- =2; }}} void moveBall () {tick ++; if (Release) {// Двигать мяч if (abs (dx) ==2) {xb + =dx / 2; // 2х скорость действительно 1,5 скорости if (tick% 2 ==0) xb + =dx / 2; } иначе {xb + =dx; } yb =yb + dy; // Устанавливаем границы leftBall =xb; rightBall =xb + 2; topBall =yb; bottomBall =yb + 2; // Отскок от верхнего края if (yb <=0) {yb =2; dy =-dy; playTone (523, 250); } // Теряем жизнь, если заден нижний край if (yb> =64) {arduboy.drawRect (xPaddle, 63, 11, 1, 0); xPaddle =54; yb =60; выпущен =ложь; жизни--; playToneTimed (175, 500); если (случайный (0, 2) ==0) {dx =1; } еще {dx =-1; }} // Отскок от левой стороны if (xb <=0) {xb =2; dx =-dx; playTone (523, 250); } // Отскок от правой стороны if (xb> =WIDTH - 2) {xb =WIDTH - 4; dx =-dx; playTone (523, 250); } // Оттолкнуться от ракетки if (xb + 1> =xPaddle &&xb <=xPaddle + 12 &&yb + 2> =63 &&yb <=64) {dy =-dy; dx =((xb- (xPaddle + 6)) / 3); // Применяет вращение к мячу // предотвращает прямой отскок if (dx ==0) {dx =(random (0,2) ==1)? 1:-1; } playTone (200, 250); } // Отскок от Bricks for (byte row =0; row  =topBrick &&leftBall <=rightBrick &&rightBall> =leftBrick) {Score (); brickCount ++; isHit [строка] [столбец] =истина; arduboy.drawRect (10 * столбец, 2 + 6 * строка, 8, 4, 0); // Вертикальное столкновение if (bottomBall> bottomBrick || topBall  rightBrick) {// Отскакивает только один раз кирпичом, каждый шар перемещается if (! Bounced) {dx =- dx; xb + =dx; bounced =true; playTone (261, 250); }}}}}} // Сбросить Bounce bounced =false; } else {// Мяч следует за ракеткой xb =xPaddle + 5; // Отпускаем мяч, если нажал FIRE pad3 =arduboy.pressed (A_BUTTON) || arduboy.pressed (B_BUTTON); если (pad3 ==true &&oldpad3 ==false) {выпущено =true; // Применяем случайное направление к мячу при отпускании if (random (0, 2) ==0) {dx =1; } еще {dx =-1; } // Убедитесь, что мяч направлен вверх dy =-1; } oldpad3 =pad3; }} void drawBall () {// arduboy.setCursor (0,0); // arduboy.print (arduboy.cpuLoad ()); // arduboy.print (""); arduboy.drawPixel (xb, yb, 0); arduboy.drawPixel (xb + 1, yb, 0); arduboy.drawPixel (xb, yb + 1, 0); arduboy.drawPixel (xb + 1, yb + 1, 0); moveBall (); arduboy.drawPixel (xb, yb, 1); arduboy.drawPixel (xb + 1, yb, 1); arduboy.drawPixel (xb, yb + 1, 1); arduboy.drawPixel (xb + 1, yb + 1, 1);} void drawPaddle () {arduboy.drawRect (xPaddle, 63, 11, 1, 0); movePaddle (); arduboy.drawRect (xPaddle, 63, 11, 1, 1);} void drawGameOver () {arduboy.drawPixel (xb, yb, 0); arduboy.drawPixel (xb + 1, yb, 0); arduboy.drawPixel (xb, yb + 1, 0); arduboy.drawPixel (xb + 1, yb + 1, 0); arduboy.setCursor (37, 42); arduboy.print («Игра окончена»); arduboy.setCursor (31, 56); arduboy.print ("Оценка:"); arduboy.print (оценка); arduboy.display (); arduboy.delayShort (4000);} недействительная пауза () {пауза =истина; // Отрисовываем паузу на экране arduboy.setCursor (52, 45); arduboy.print («ПАУЗА»); arduboy.display (); пока (пауза) {arduboy.delayShort (150); // Отмена паузы при нажатии FIRE pad2 =arduboy.pressed (A_BUTTON) || arduboy.pressed (B_BUTTON); если (pad2 ==true &&oldpad2 ==false &&выпущено) {arduboy.fillRect (52, 45, 30, 11, 0); приостановлено =ложь; } oldpad2 =pad2; }} void Score () {score + =(level * 10);} void newLevel () {// Отрисовываем ракетку arduboy.drawRect (xPaddle, 63, 11, 1, 0); // Отрисовываем мяч arduboy.drawPixel (xb, yb, 0); arduboy.drawPixel (xb + 1, yb, 0); arduboy.drawPixel (xb, yb + 1, 0); arduboy.drawPixel (xb + 1, yb + 1, 0); // Изменяем различные переменные для сброса игры xPaddle =54; yb =60; brickCount =0; выпущен =ложь; // Рисует новые блоки и сбрасывает их значения для (byte row =0; row <4; row ++) {for (byte column =0; column <13; column ++) {isHit [row] [column] =false; arduboy.drawRect (10 * столбец, 2 + 6 * строка, 8, 4, 1); }} arduboy.display ();} // Используется для задержки изображений при чтении кнопки inputboolean pollFireButton (int n) {for (int i =0; i  0) {sprintf (text_buffer, «% c% c% c% u», инициалы [0], инициалы [1], инициалы [2], оценка); arduboy.setCursor (x + 24, y + (i * 8)); arduboy.print (text_buffer); arduboy.display (); }} если (pollFireButton (300)) {вернуть истину; } return false; arduboy.display ();} boolean titleScreen () {// Очищает экран arduboy.clear (); arduboy.setCursor (16,22); arduboy.setTextSize (2); arduboy.print («ПРОРЫВ»); arduboy.setTextSize (1); arduboy.display (); если (pollFireButton (25)) {вернуть истину; } // Мигает «Press FIRE» 5 раз для (byte i =0; i <5; i ++) {// Рисует «Press FIRE» arduboy.setCursor (31, 53); arduboy.print («НАЖМИТЕ ПОЖАР!»); arduboy.display (); если (pollFireButton (50)) {вернуть истину; } // Удаляет "Press FIRE" arduboy.setCursor (31, 53); arduboy.print (""); arduboy.display (); если (pollFireButton (25)) {вернуть истину; }} return false;} // Функция по ноотропному дизайну для добавления рекордовvoid enterInitials () {byte index =0; arduboy.clear (); инициалы [0] =''; инициалы [1] =''; инициалы [2] =''; в то время как (правда) {arduboy.display (); arduboy.clear (); arduboy.setCursor (16,0); arduboy.print («ВЫСОКАЯ ОЦЕНКА»); sprintf (text_buffer, "% u", оценка); arduboy.setCursor (88, 0); arduboy.print (text_buffer); arduboy.setCursor (56, 20); arduboy.print (инициалы [0]); arduboy.setCursor (64, 20); arduboy.print (инициалы [1]); arduboy.setCursor (72, 20); arduboy.print (инициалы [2]); для (байт я =0; я <3; я ++) {arduboy.drawLine (56 + (я * 8), 27, 56 + (я * 8) + 6, 27, 1); } arduboy.drawLine (56, 28, 88, 28, 0); arduboy.drawLine (56 + (индекс * 8), 28, 56 + (индекс * 8) + 6, 28, 1); arduboy.delayShort (70); if (arduboy.pressed (LEFT_BUTTON) || arduboy.pressed (B_BUTTON)) {if (index> 0) {index--; playToneTimed (1046, 80); }} if (arduboy.pressed (RIGHT_BUTTON)) {if (index <2) {index ++; playToneTimed (1046, 80); }} if (arduboy.pressed (UP_BUTTON)) {инициалы [индекс] ++; playToneTimed (523, 80); // А-Я 0-9:-? ! - / '' if (инициалы [индекс] =='0') {инициалы [индекс] =''; } if (инициалы [индекс] =='!') {инициалы [индекс] ='A'; } if (инициалы [индекс] =='[') {инициалы [индекс] ='0'; } if (инициалы [индекс] =='@') {инициалы [индекс] ='!'; }} если (arduboy.pressed (DOWN_BUTTON)) {инициалы [индекс] -; playToneTimed (523, 80); если (инициалы [индекс] =='') {инициалы [индекс] ='?'; } если (инициалы [индекс] =='/') {инициалы [индекс] ='Z'; } если (инициалы [индекс] ==31) {инициалы [индекс] ='/'; } если (инициалы [индекс] =='@') {инициалы [индекс] =''; }} если (arduboy.pressed (A_BUTTON)) {playToneTimed (1046, 80); если (индекс <2) {индекс ++; } else {return; }}}} void enterHighScore (файл байтов) {// Каждый блок EEPROM имеет 7 рекордов, и каждая запись рекордов // имеет длину 5 байтов:3 байта для инициалов и два байта для очков. int адрес =файл * 7 * 5 + EEPROM_STORAGE_SPACE_START; байт привет, lo; char tmpInitials [3]; беззнаковый int tmpScore =0; // Обработка рекордов для (byte i =0; i <7; i ++) {hi =EEPROM.read (address + (5 * i)); lo =EEPROM.read (адрес + (5 * i) + 1); if ((hi ==0xFF) &&(lo ==0xFF)) {// Значения не инициализированы, поэтому рассматривайте эту запись // как оценку 0. tmpScore =0; } else {tmpScore =(привет <<8) | вот; } если (оценка> tmpScore) {enterInitials (); для (байт j =i; j <7; j ++) {hi =EEPROM.read (адрес + (5 * j)); lo =EEPROM.read (адрес + (5 * j) + 1); если ((привет ==0xFF) &&(lo ==0xFF)) {tmpScore =0; } else {tmpScore =(привет <<8) | вот; } tmpInitials [0] =(char) EEPROM.read (адрес + (5 * j) + 2); tmpInitials [1] =(char) EEPROM.read (адрес + (5 * j) + 3); tmpInitials [2] =(char) EEPROM.read (адрес + (5 * j) + 4); // записываем счет и инициалы в текущий слот EEPROM.update (address + (5 * j), ((score>> 8) &0xFF)); EEPROM.update (адрес + (5 * j) + 1, (оценка &0xFF)); EEPROM.update (адрес + (5 * j) + 2, инициалы [0]); EEPROM.update (адрес + (5 * j) + 3, инициалы [1]); EEPROM.update (адрес + (5 * j) + 4, инициалы [2]); // tmpScore и tmpInitials теперь содержат то, что мы хотим // записать в следующий слот. оценка =tmpScore; инициалы [0] =tmpInitials [0]; инициалы [1] =tmpInitials [1]; инициалы [2] =tmpInitials [2]; } оценка =0; инициалы [0] =''; инициалы [1] =''; инициалы [2] =''; возвращение; }}} // Воспроизвести тон с указанной частотой в течение указанной продолжительности .void playTone (unsigned int frequency, unsigned int duration) {beep.tone (beep.freq (frequency), duration / (1000 / FRAME_RATE));} // Воспроизведение тона с указанной частотой в течение указанной продолжительности с использованием // задержки для отсчета времени тона. // Используется, когда beep.timer () не вызывается. Void playToneTimed (unsigned int frequency, unsigned int duration) { beep.tone (beep.freq (частота)); arduboy.delayShort (продолжительность); beep.noTone ();} 

Изготовленные на заказ детали и корпуса

3d_parts_ThLGvJvWga.rar

Схема


Производственный процесс

  1. Связь Arduino I2C с Raspi 2 WIOT
  2. Портативная игровая консоль | Клон Arduboy
  3. Игра Arduino Pong - OLED-дисплей
  4. Arduino Temp. Монитор и часы реального времени с дисплеем 3.2
  5. Простой датчик препятствий с Arduino
  6. Игра с дисплеем Nextion
  7. Arduino Nano:управление двумя шаговыми двигателями с помощью джойстика
  8. DIY вольтметр с Arduino и дисплеем Nokia 5110
  9. Клеточные автоматы на основе Arduino и OLED
  10. Изолированный аналоговый вход для Arduino