Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Arduboy Clone met Arduino Nano en I2C OLED-display

Componenten en benodigdheden

Arduino Nano R3
× 1
Grafische OLED, 128 x 64
× 1
Zoemer
× 1
Tactiele schakelaar, bovenkant bediend
× 6
RGB diffuse gemeenschappelijke kathode
× 1
Weerstand 221 ohm
× 3
Weerstand 10k ohm
× 1

Benodigde gereedschappen en machines

3D-printer (algemeen)
Soldeerbout (algemeen)

Over dit project

Arduboy is een miniatuurspelsysteem ter grootte van een creditcard. Het wordt geleverd met een klassiek 8-bits spel en kan opnieuw worden geprogrammeerd vanuit een bibliotheek met open source-spellen die online beschikbaar is. Arduboy is open source, dus je kunt leren coderen en je eigen games maken. De originele versie is gebaseerd op ATmega32U4 microcontroller en 128x64 Pixels seriële OLED-display.

De console waarvan de constructie hieronder wordt weergegeven, bestaat uit Arduino Nano en de I2C-versie van het OLED-scherm, die veel gemakkelijker te vinden is tegen een lagere prijs. U kunt de benodigde bibliotheken en code downloaden op:

https://github.com/harbaum/Arduboy2

Als u een 3D-printer bezit, kunt u ook .STL-bestanden downloaden van een mogelijke boxoptie waarin de console is geïnstalleerd. Een gedetailleerde installatiehandleiding is beschikbaar op dezelfde site. Het wordt aangedreven door een Arduino Nano met één lithium-ionbatterij van 3.7v en het werkt best goed.

Ik heb veel games getest op deze console, die allemaal geweldig werken:

- ArduBreakout

- Flipperkast

- Schaduwloper

- Slang

- VIRUS-LQP-79

- Negentien43

en nog veel meer...

Het schema is hieronder weergegeven.

Als voorbeeld presenteer ik de code voor het ArduBreakout-spel, maar je kunt elk ander spel downloaden op de Arduboy-site die compatibel is met deze versie van de console.

Code

  • ArduBreakout-spel
ArduBreakout-spelArduino
/* Breakout Copyright (C) 2011 Sebastian Goscik Alle rechten voorbehouden. Wijzigingen door Scott Allen 2016 (na eerdere wijzigingen door ???) Deze bibliotheek is gratis software; u kunt het herdistribueren en/of wijzigen onder de voorwaarden van de GNU Lesser General Public License zoals gepubliceerd door de Free Software Foundation; ofwel versie 2.1 van de Licentie, of (naar uw keuze) een latere versie. */#include // blok in EEPROM om hoge scores op te slaan#define EE_FILE 2Arduboy2 arduboy;BeepPin1 beep;const unsigned int FRAME_RATE =40; // Framesnelheid in frames per secondeconst unsigned int KOLOMMEN =13; //Columns of bricksconst unsigned int RIJEN =4; //Rijen van bricksint dx =-1; //Initiële beweging van ballint dy =-1; //Initiële verplaatsing van ballint xb; // Ballen startpositie yb; // Ballen startpositieboolean vrijgegeven; //Als de bal is losgelaten door de playerboolean gepauzeerd =false; //Als het spel is gepauzeerd door xPaddle; //X positie van paddleboolean isHit[ROWS][COLUMNS]; //Array van of stenen worden geraakt of nietboolean bounced=false; // Gebruikt om dubbele bounce glitchbyte-levens =3 te repareren; //Aantal levensbyte-niveau =1; // Huidig ​​niveau unsigned int score=0; //Score voor de gameunsigned int brickCount; //Aantal stenen hitboolean pad, pad2, pad3; //Knopdrukbuffer die wordt gebruikt om te stoppen met het herhalen van boolean oldpad, oldpad2, oldpad3;char text_buffer [16]; //Algemene string bufferboolean start=false; //If in menu of in gameboolean initialDraw=false;//If de eerste trekking is gebeurdchar initials[3]; //Initialen gebruikt in hoge score//Ball Bounds gebruikt bij botsingsdetectiebyte leftBall;byte rightBall;byte topBall;byte bottomBall;//Brick Bounds gebruikt bij botsingsdetectiebyte leftBrick;byte rightBrick;byte topBrick;byte bottomBrick;byte tick;void setup (){ arduboy.begin(); piep.begin(); arduboy.setFrameRate(FRAME_RATE); arduboy.initRandomSeed();}void loop(){ // pauzeer renderen tot het tijd is voor het volgende frame als (!(arduboy.nextFrame())) terugkeer; // Behandel de timing en het stoppen van tonen beep.timer(); // Titelschermlus schakelt van titelscherm // en hoge scores totdat FIRE wordt ingedrukt terwijl (!start) { start =titleScreen(); if (!start) { start =displayHighScores(EE_FILE); } } // Initiële level draw if (!initialDraw) { // Wist het scherm arduboy.clear(); //Selecteert Lettertype // Tekent het nieuwe niveau niveau =1; nieuw level(); score =0; initiëleDraw=waar; } if (leeft>0) { drawPaddle(); // Pauzeer het spel als FIRE op pad drukt =arduboy.pressed (A_BUTTON) || arduboy.pressed (B_BUTTON); if(pad ==true &&oldpad ==false &&vrijgegeven) { oldpad2 =false; // Forceert pad lus 2 om eenmaal pauze (); } oude pad =pad; drawBall(); if (brickCount ==RIJEN * KOLOMMEN) { level ++; nieuw level(); } } else { drawGameOver(); if (score> 0) { enterHighScore(EE_FILE); } arduboy.clear(); initialDraw=false; begin=onwaar; levens=3; nieuw level(); } arduboy.display();}void movePaddle(){ //Ga naar rechts if(xPaddle  0) { if (arduboy.pressed(LEFT_BUTTON)) { xPaddle-=2; } }} ongeldig moveBall(){ tick++; if (vrijgegeven) { // Verplaats bal if (abs (dx) ==2) { xb +=dx/2; // 2x snelheid is echt 1,5 snelheid als (tick%2==0) xb +=dx/2; } anders { xb +=dx; } yb=yb + dy; // Grenzen instellen leftBall =xb; rechterBal =xb + 2; topBall =yb; bottomBall =yb + 2; //Bounce van de bovenrand als (yb <=0) {yb =2; dy =-dy; playTone (523, 250); } // Verlies een leven als de onderkant raakt if (yb>=64) { arduboy.drawRect (xPaddle, 63, 11, 1, 0); xPaddle =54; yb=60; vrijgegeven =onwaar; leeft--; playToneTimed(175, 500); if (willekeurig (0, 2) ==0) { dx =1; } anders { dx =-1; } } //Bounce van linkerkant if (xb <=0) { xb =2; dx =-dx; playTone (523, 250); } //Bounce van rechterkant if (xb>=BREEDTE - 2) { xb =BREEDTE - 4; dx =-dx; playTone (523, 250); } //Bounce off paddle if (xb+1>=xPaddle &&xb<=xPaddle+12 &&yb+2>=63 &&yb<=64) { dy =-dy; dx =((xb-(xPaddle+6))/3); // Past spin toe op de bal // voorkom straight bounce if (dx ==0) { dx =(random(0,2) ==1) ? 1 :-1; } speeltoon(200, 250); } //Bounce off Bricks for (byte row =0; row =topBrick &&leftBall <=rightBrick &&rightBall>=leftBrick) { Score(); BrickCount++; isHit[rij][kolom] =waar; arduboy.drawRect (10*kolom, 2+6*rij, 8, 4, 0); // Verticale botsing if (bottomBall> bottomBrick || topBall  rightBrick) { //Bounce slechts één keer dat elke bal beweegt if (!bounced) { dx =- dx; xb +=dx; bounced =waar; playTone (261, 250); } } } } } } //Reset Bounce bounced =false; } else { //Bal volgt peddel xb=xPaddle + 5; // Laat bal los als FIRE op pad3 =arduboy.pressed (A_BUTTON) || arduboy.pressed (B_BUTTON); if (pad3 ==true &&oldpad3 ==false) { vrijgegeven =true; // Pas een willekeurige richting toe op de bal bij het loslaten als (willekeurig (0, 2) ==0) { dx =1; } anders { dx =-1; } // Zorgt ervoor dat de bal naar boven gaat dy =-1; } oudpad3 =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); beweegPaddle(); arduboy.drawRect(xPaddle, 63, 11, 1, 1);}nietig 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("Game Over"); arduboy.setCursor(31, 56); arduboy.print("Score:"); arduboy.print(score); arduboy.display(); arduboy.delayShort(4000);}void pause(){ paused =true; // Teken pauze naar het scherm arduboy.setCursor (52, 45); arduboy.print("PAUZE"); arduboy.display(); while (onderbroken) { arduboy.delayShort(150); // Pauzeer als FIRE wordt ingedrukt pad2 =arduboy.pressed (A_BUTTON) || arduboy.pressed (B_BUTTON); if (pad2 ==true &&oldpad2 ==false &&vrijgegeven) { arduboy.fillRect(52, 45, 30, 11, 0); gepauzeerd=false; } oudpad2 =pad2; }}void Score(){ score +=(level*10);}void newLevel(){ //Undraw paddle arduboy.drawRect(xPaddle, 63, 11, 1, 0); //Bal ongedaan maken arduboy.drawPixel (xb, yb, 0); arduboy.drawPixel(xb+1, yb, 0); arduboy.drawPixel(xb, yb+1, 0); arduboy.drawPixel(xb+1, yb+1, 0); // Verander verschillende variabelen om het spel te resetten xPaddle =54; jb =60; aantal stenen =0; vrijgegeven =onwaar; // Tekent nieuwe stenen en stelt hun waarden opnieuw in voor (byte rij =0; rij <4; rij ++) { voor (byte kolom =0; kolom <13; kolom ++) { isHit [rij] [kolom] =false; arduboy.drawRect (10*kolom, 2+6*rij, 8, 4, 1); } } arduboy.display();}//Wordt gebruikt om afbeeldingen te vertragen tijdens het lezen van de knop inputboolean pollFireButton(int n){ for(int i =0; i  0) { sprintf(text_buffer, "%c%c%c %u", initialen[0], initialen[1], initialen[2], score); arduboy.setCursor(x + 24, y + (i*8)); arduboy.print(text_buffer); arduboy.display(); } } if (pollFireButton(300)) { return true; } onwaar retourneren; arduboy.display();}boolean titleScreen(){ // Wist het scherm arduboy.clear(); arduboy.setCursor(16,22); arduboy.setTextSize(2); arduboy.print("BREAKOUT"); arduboy.setTextSize(1); arduboy.display(); if (pollFireButton(25)) { return true; } //Flash "Druk op FIRE" 5 keer voor (byte i =0; i <5; i++) { // Tekent "Druk op FIRE" arduboy.setCursor (31, 53); arduboy.print ("DRUK OP BRAND!"); arduboy.display(); if (pollFireButton(50)) { return true; } //Verwijdert "Press FIRE" arduboy.setCursor (31, 53); arduboy.print(" "); arduboy.display(); if (pollFireButton(25)) { return true; } } retourneer false;}//Functie door nootropic ontwerp om hoge scores toe te voegen.void enterInitials(){ byte index =0; arduboy.clear(); initialen[0] =' '; initialen[1] =' '; initialen[2] =' '; while (waar) { arduboy.display(); arduboy.clear(); arduboy.setCursor (16,0); arduboy.print ("HOGE SCORE"); sprintf(text_buffer, "%u", score); arduboy.setCursor(88, 0); arduboy.print(text_buffer); arduboy.setCursor(56, 20); arduboy.print(initialen[0]); arduboy.setCursor(64, 20); arduboy.print(initialen[1]); arduboy.setCursor(72, 20); arduboy.print(initialen[2]); for(byte i =0; i <3; i++) { arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1); } arduboy.drawLine(56, 28, 88, 28, 0); arduboy.drawLine(56 + (index*8), 28, 56 + (index*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)) { initialen[index]++; playToneTimed (523, 80); // A-Z 0-9 :-? !-/ ' ' if (initialen[index] =='0') { initialen[index] =' '; } if (initialen[index] =='!') { initialen[index] ='A'; } if (initialen[index] =='[') { initialen[index] ='0'; } if (initialen[index] =='@') { initialen[index] ='!'; } } if (arduboy.pressed(DOWN_BUTTON)) { initials[index]--; playToneTimed (523, 80); if (initialen[index] ==' ') { initialen[index] ='?'; } if (initialen[index] =='/') { initialen[index] ='Z'; } if (initialen[index] ==31) { initialen[index] ='/'; } if (initialen[index] =='@') { initialen[index] =' '; } } if (arduboy.pressed(A_BUTTON)) { playToneTimed (1046, 80); if (index <2) { index++; } anders { terugkeer; } } }}void enterHighScore (bytebestand){ // Elk blok van EEPROM heeft 7 hoge scores en elke invoer met hoge score // is 5 bytes lang:3 bytes voor initialen en twee bytes voor score. int adres =bestand * 7 * 5 + EEPROM_STORAGE_SPACE_START; byte hallo, kijk; char tmpInitialen[3]; niet-ondertekende int tmpScore =0; // Hoge scoreverwerking voor (byte i =0; i <7; i++) { hi =EEPROM.read (adres + (5*i)); lo =EEPROM.lezen (adres + (5*i) + 1); if ((hi ==0xFF) &&(lo ==0xFF)) { // De waarden zijn niet geïnitialiseerd, dus behandel dit item // als een score van 0. tmpScore =0; } else { tmpScore =(hallo <<8) | zie; } if (score> tmpScore) { enterInitials(); for(byte j =i; j <7; j++) { hi =EEPROM.read(adres + (5*j)); lo =EEPROM.lezen (adres + (5*j) + 1); if ((hi ==0xFF) &&(lo ==0xFF)) { tmpScore =0; } else { tmpScore =(hallo <<8) | zie; } tmpInitials[0] =(char)EEPROM.read(adres + (5*j) + 2); tmpInitials[1] =(char)EEPROM.read(adres + (5*j) + 3); tmpInitials[2] =(char)EEPROM.read(adres + (5*j) + 4); // schrijf score en initialen naar huidige slot EEPROM.update (adres + (5*j), ((score>> 8) &0xFF)); EEPROM.update (adres + (5*j) + 1, (score &0xFF)); EEPROM.update(adres + (5*j) + 2, initialen[0]); EEPROM.update(adres + (5*j) + 3, initialen[1]); EEPROM.update(adres + (5*j) + 4, initialen[2]); // tmpScore en tmpInitials bevatten nu wat we willen //schrijven in het volgende slot. score =tmpScore; initialen[0] =tmpInitials[0]; initialen[1] =tmpInitials[1]; initialen[2] =tmpInitials[2]; } score =0; initialen[0] =' '; initialen[1] =' '; initialen[2] =' '; opbrengst; } }}// Speel een toon af op de opgegeven frequentie voor de opgegeven duur.void playTone(unsigned int frequency, unsigned int duration){ beep.tone(beep.freq(frequency), duration / (1000 / FRAME_RATE));} // Speel een toon af op de gespecificeerde frequentie voor de gespecificeerde duur met// een vertraging om de toon te timen.// Gebruikt wanneer beep.timer() niet wordt aangeroepen.void playToneTimed(unsigned int frequency, unsigned int duration){ piep.toon(piep.freq(frequentie)); arduboy.delayShort(duur); piep.noTone();}

Aangepaste onderdelen en behuizingen

3d_parts_ThLGvJvWga.rar

Schema's


Productieproces

  1. Arduino I2C-communicatie met Raspi 2 WIOT
  2. Handheld-gameconsole | Arduboy Clone
  3. Arduino Pong Game - OLED-scherm
  4. Arduino Temp. Monitor en realtimeklok met 3.2-weergave
  5. Eenvoudige obstakelsensor met Arduino
  6. Spelen met Nextion Display
  7. Arduino Nano:bedien 2 stappenmotoren met joystick
  8. DIY voltmeter met Arduino en een Nokia 5110-display
  9. Arduino en OLED-gebaseerde mobiele automaten
  10. Handheld geigerteller met Arduino Nano
  11. Een geïsoleerde analoge ingang voor Arduino