Gamepad من Sega Mega Drive و Raspberry Pi Part 2 (آخر ستة أزرار)



استمر ، الأسهل قد انتهى! والآن إلى الأصعب والمثيرة للاهتمام. إذا كنت كسولًا جدًا في القراءة ، فستجد أدناه (أقرب إلى نهاية المقالة) رابطًا للفيديو ، مع نتيجة وشرح لكل شيء ، بما في ذلك ما هو موضح في الجزء الأول. إذا كنت مهتما ، يرجى اتباع التالي.

في وضع 6 أزرار ، تحدث القراءة في 4 دورات أو مراحل (إذا تم التعبير عنها بلغة المحاكي). أي ، كل 16 مللي ثانية هناك تغيير دوري (4 دورة) في حالة تحديد الإخراج ، وتظهر كل دورة رابعة عند إخراج وحدة التحكم حالة الأزرار الإضافية. فيما يلي مخطط للقراءة ، من أجل الوضوح ، والذي يجب تكراره:



من الجيد أن يكون لدي محلل منطقي ، وبمساعدة مني اشتعلت منه خلل ، والذي تجلى في حقيقة أن الدورة لم تخرج من المرحلة الرابعة.

لن أتغلب على الأدغال ، وسأذكر هذه الوظيفة على الفور:

static u32 read_pad_6btn(int i, u32 out_bits) { u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU int phase = Pico.m.padTHPhase[i]; u32 value = 0; if (i == 0 && phase == 0 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 0 && !(out_bits & 0x40)) // TH { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 1 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 1 && !(out_bits & 0x40)) // TH { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 2 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 2 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 3 && (out_bits & 0x40)) { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read Z button value ^= digitalRead(Data1) << 1; //read Y button value ^= digitalRead(Data2) << 2; //read X button value ^= digitalRead(Data3) << 3; //read MODE button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 3 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); value |= 0x0f; } if (i == 1 && phase == 0 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 0 && !(out_bits & 0x40)) // TH { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } if (i == 1 && phase == 1 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 1 && !(out_bits & 0x40)) // TH { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } if (i == 1 && phase == 2 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 2 && !(out_bits & 0x40)) { value = (pad & 0xc0) >> 2; // ?0SA 0000 } if(i == 1 && phase == 3 && (out_bits & 0x40)) { return (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ } if(i == 1 && phase == 3 && !(out_bits & 0x40)) { return ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111 } return value; } 

دعنا نحلل أي من الشروط ، على سبيل المثال:

 if (i == 0 && phase == 1 && !(out_bits & 0x40)) // TH 

يتم التحقق هنا من أننا نقرأ من لوحة اللعبة الأولى (i == 0) ، ومرحلة القراءة الثانية (المرحلة == 1) ، ويجب تعيين إخراج التحديد على 0 ! (Out_bits & 0x40) . لفهم كيفية عمل هذا في المضاهاة ، قمت بتجميع التعليمات البرمجية على Xubuntu ، وقم بتشغيل Visual Studio Code ، حيث قمت بتعيين مجموعة من نقاط التوقف ، في وضع التصحيح. والنتيجة هي هذه الصورة الجميلة:



في الواقع ، نتيجة العمل هي:


هنا يجب أن أقول بضع كلمات عن المحاكي نفسه. إما أنني لم أحسبها ، أو أن هذا خطأ ، لكن المحاكي يبدأ في البداية في وضع من ثلاثة أزرار ، حتى إذا تمت الإشارة إلى عكس ذلك في الإعدادات العامة. 99 ٪ من الألعاب وهذا يكفي. من أجل الدخول في وضع التشغيل باستخدام لوحة ألعاب ذات 6 أزرار ، يجب عليك الدخول في الإعدادات والعودة إلى اللعبة دون تغيير أي شيء.
ولكن هناك لعبة واحدة خارج هذا السياق ، وهي أزرار Lost Vikings ، والأزرار X و Z و MODE تعمل بشكل جيد دون أي رقص.

PS

لكن يمكنك القيام بذلك بشكل أسهل ، فقد قام شخص واحد بكتابة سائق بالفعل للعمل باستخدام لوحة الألعاب ، وعلى مستوى منخفض للغاية. ما زلت بعيدًا عن هذا.

شكرا لاهتمامكم!

Source: https://habr.com/ru/post/ar435094/


All Articles