postsTweet今回は、マイコンのコンソール、いわゆるUARTを使ったターミナル出力を使って「テトリス」を作ってみました。使用した言語は、組み込みなのでもちろんC言語を使用しました。「作ってみた!」と大層なことを言っていますが、ゲームのプログラミングを勉強してみようと思って、今回は「ゲヱム道館」さんのYouTube「1時間で作ってみた」シリーズの「テトリス小一時間で作ってみた」を参考にしてみました。参考と言っても、ほとんどそのものだったりします。C++を使用して、Windowsのコンソールアプリとして開発していますが、私はマイコン好きなので、もちろんマイコンで実装しました。ゲームの作成について解説する程ゲーム開発の知識もありませんので、テトリス実装についての解説はゲヱム道館さんにお任せします。MCU上に実装する際に問題になった点や工夫を私なりに説明したいと思います。Family使用したボードは、NXP社のLPCXpresso54102というボードで、実装されているLPC54102はデュアルコアMCU(Cortex-M4F・Cortex-M0+)です。プログラムを実行するのは、メインコアのCortex-M4Fコア上に実装しました。サブコアには、Cortex-M0+が採用されています。この製品は、センサーデータの取得のような定期的なアクセスには、省電力コアのCortex-M0+を使用することでシステムの消費電力を下げつつ、センサーデータのアルゴリズム処理にはパワフルなCortex-M4Fを使うことで負荷が高い処理にも対応できるアーキテクチャになっています。今回は、ただ単純にコンソールだけしか使っていませんので、こんなMCUを使う必要は全くなかったんですけどね〜〜LPC541xxシリーズじゃなきゃ出来ないわけではなく、他のマイコンでも同様に実装可能なので、皆さんも是非参考にしてご自身のマイコンでゲーム開発を楽しんでみてください。おすすめボード以下におすすめボードを紹介します。Direct(オンラインショッピング)で様々なボードが買えます。電子部品を取り扱う通販でも購入が可能です。IDEを使わせてもらいました。IDEはMac環境でも対応しているのが◎。MacOSでも使える開発環境は重宝します。IDEは、こちらからダウンロード可能です。Worldプロジェクトのインポートさて、いよいよ「テトリス」の実装をしていきます。プロジェクトの作成から始めます。World」プロジェクトを使います。マイコン開発を始める必要最低限の設定を行った状態で開発を始めることが可能です。World」プロジェクトのインポート次に、ボードを選択します。今回わたしは、LPC54102を選択していきます。インポートしたSDKのデバイスが表示されます。World」プロジェクトをインポートしたところです。このプロジェクトにコードを足していきます。今回は、ホストPC上のターミナルにアスキーアートを出力してゲームを作成します。ターミナルにコンソソール出力することが、マイコンのコンソールゲームを開発する上での第一関門です。Macでコンソールを表示するには?私の環境はMacOSなので、ターミナルアプリを使用し「Screen」コマンドでコンソール表示を行っています。「Screen」を使用するには、ボードをUSBコネクタに接続し、MacOSのターミナルを起動後に以下コマンドを実行します。メモしたパスを書き込むscreenに続けてメモしたのを記入します。UART接続のボーレート(115200bps)を指定します。これで、Macのターミナルで、コンソールとして使用することが出来ます。IDEにもコンソール表示機能がありますが、このMCUXpressoのコンソールではテトリスが上手く動きませんでしたので、UART出力をしてTeraTermなどのターミナルを使用することをおすすめします。TeraTermは、まだ試してないので正しく動作するかわかりませんが、恐らく問題ないかと思います。MacOSのScreenでは問題ありませんでした。)上手く動かないのは、エスケープシーケンスが認識されないためです。IDEではコンソールへの出力設定を、「セミホスティング」と「UART出力」をどちらか選択することが出来ます。外部ホストのコンソールに出力するためには、「UART出力」を選択する必要があります。セミホスティングについて知りたい方は、以前の記事を参考にしてください。userマイコンデバッグの要!printfデバッグhttps://mcu-things.com/jp/lpc-printf-debug-semihosting/プログラムのデバッグとして、動的な状態を標準出力に出力して可視化する手法です。セミホスティングって何?からLPCマイコンでprintfデバッグを見ていきます。10.2.1では、このセミホスティングとUART出力の設定を、クリック一発で簡単に切り替えることができるようになっています。UART出力への切り替え今回は、外部ホストのコンソールを利用するために、UART出力へ切り替えます。Settingから設定します。consoleを選択します。Console」が選択出来ません。選択後、「トンカチマーク」をクリックして、再ビルドします。World”」が出力されるか確認します。World」を確認これで、無事コンソールへの出力ができるようになりました。コードの実装コードを実装して行く中で、マイコン上に実装する時に問題になる点があります。その問題を順を追って説明していきます。画面のクリアまず、マイコンでコンソールゲームを作成する際の問題点は、画面描画のため定期的に画面をクリア(消去)する必要あるという点です。クリアせずに画面を描画しようとすると、当然どんどん行は下に出力され下にスクロールして行くし、刻一刻と時間が過ぎる中でキャラクタの動きを与えると、画面が前の描画との不整合からチラつきが発生したりします。そこで、定期的に画面を一旦消去して、画面の描画をし直すんです。C++のC標準ライブラリ(stdlib.h)のシステムコマンド”CLS”を使用して、画面をクリアしています。マイコンではこのコンソール画面のクリアコマンドがありません。このSystem(“cls”)で、一応、Buildは通りますが、画面はクリアされないんです。マイコンでは、どうするか?エスケープシーケンスでクリアマイコンでコンソール画面をクリアするには、「エスケープシーケンス」コマンドをコンソールに出力し、コンソール画面を消去することが出来ます。今回画面クリアで試した「エスケープシーケンス」は、以下2つになります。カーソルを(1,1)に移動する。実は、エスケープシーケンスで画面クリアを入れると、当然一旦画面がクリアされるのですが、UART出力する時間が掛かるのと、画面クリアのタイミングで若干のチラつきが発生するんです。Worldを出力し終わる前に、画面クリアされてしまうことがあるようです。カーソル位置を描画開始位置に移動させるそこで、画面の安定描画をさせるために、私のプログラムではカーソルを元の描画スタート位置に移動させています。それが、「\033[1;1f」このエスケープシーケンスです。画面クリアせずに、カーソルだけを描画開始位置に移動させて描画をさせることで、変更があったブロックだけが変化するように見えるので、描画が安定して見えます。チラつきが劇的に少なくなります。インターネットで「エスケープシーケンス」と検索すると色々出てきますので、興味ある方は調べてみてください。画面描画タイミングテトリスでは、テトリミノ(テトリスのブロック)が落ちるタイミングが約1秒ごとに下に向かって落ちて行きます。この1秒のタイミングで画面描画を行います。ゲヱム道館さんでは、C標準ライブラリを使ってシステムの時刻を取得して1秒ごとに画面描画をすることで対応しています。マイコンではタイマーを使うことで同様のことを実行することが可能です。Timer))や汎用のタイマーを使っても実装可能です。Counter)を使用することにしました。理由は、初期化や設定が非常に簡単で、使用するまで時間が掛からないからです。UTICKドライバの追加まず、UTICKドライバを追加します。Components」をクリックします。UTICKドライバをチェックして、OKをクリックすると、ドライバが追加されます。“fsl_utick.h”を追加して、下記のように初期化をします。UTICKの初期化では、引数にUTICKモード、カウント数、コールバック関数をしています。カウント数を600000にすると、約1秒で割り込みが発生します。cb_utick);割り込み発生後に、指定したコールバック関数をコールしてくれます。コールバック関数では、割り込みフラグのクリアとユーザ変数としてのフラグをTrueにするだけですが、このフラグ(utickIntFlag)を見て1秒経ったかどうかを判断します。cb_utick(){UTICK_ClearStatusFlags(UTICK0);utickIntFlag=true;}試しに、このutickを使って見ます。World”」を出力します。printfで出力が終わった後に、utickIntFlagをfalseに戻しておきます。World出力しています。(書き換わっているのは分かりませんが、多分書き換えが出来ています。)先ほどの、出力画面と変わりありませんが、カーソル位置が左上に移動しているのが分かると思います。アスキーアートが上手く表示出来ない私の環境(MacOSX)が問題だったのか、テトリスのブロックやフィールドを描画するのに、アスキーアートを使用していますが、これが上手く描画されませんでしたね。四角のブロックを表示するのですが、小さすぎたり、ブロックとブロックの間の間隔が広くなってしまったりと、上手く描画できませんでした。結果的には、◾️の隣に余計な文字が付加されているようです。これを削除することで、上手く描画させることが可能になりました。IDEのテキストエディタ上で、「◾️」と表示すると、カーソルを動かしてみると分かるのですが、2文字と認識されているようです。四角の隣に見えない文字が設定されているようで、それが原因で、コンソール上では四角と四角の間に空白が挿入されて表示され、間隔が広くなってしまっていたようです。SDKではkbhit()のような、キーボードが押されたことを認識する関数は用意されていないので、UARTのRXステータスレジスタを直接見てデータがあれば(RXREADY)、処理するというコードで代用しています。(USART0->STAT&USART_STAT_RXRDY_MASK){「テトリス」のコードを実装するあとは、ゲヱム道館さんのYouTubeに沿ってコーディングを進めていきます。私のソースコードは、Gitに公開していますので、上手く動かない場合には、参考にして見てください。テトリスのゲームクリアは、実装していませんので、延々とブロックが落ちてきて、ブロックをひたすら消すだけのゲームとなっています。完成!!私のソースコードはこちらから→https://github.com/mcuthings/LPC54102-Tetrisまとめ今回は、マイコンでコンソールゲーム「テトリス」を作って見ました。コンソールではなくLCD画面にテトリスをカラーで作って見たいなーと思っています。ゲーム開発で使うC言語は、ゲーム特有のコーディングがあり、少々難しいところもありますが、面白いですね。皆さんもチャレンジして見てください。勉強になりますよーーー。SDRAMを使ってみた。siteプロフィールマイコン大好き、マイコンで何でも出来るをモットーにどんどん記事をアップしていきたいと思っています。マイコンは特に、NXPマイコンが好きです。KinetisやLPCマイコンを中心に幅広く投稿していきます。横浜のNXPファンお問い合わせは、こちらから。(7)ブログをメールで購読メールアドレスを記入して購読すれば、更新をメールで受信できます。