工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

ATmegaエイリアンをテーマにしたスロットマシン

コンポーネントと消耗品

>
Microchip Technology ATmega328
ATmega328P-PU、正確には。$ 3.00 SlotMachine用に1つ、I2CクレジットLEDディスプレイ用に1つ奴隷。
× 2
8桁の7セグメントディスプレイ
$ 1.20プレーヤーのクレジット残高を表示します。
× 1
8x8マトリックス、4セグメント、MAX7219
$ 3.78スピニングリールをシミュレートし、シンボルを表示します。 4つのセグメントのうち3つだけが使用されます。
× 1
I2C2004シリアルブルーバックライトLCDモジュール20X 4 2004
$ 3.00オプションのメニューを表示します。 aliexpressで買い物をしましょう。送料を払わないでください!
× 1
ブレッドボード(汎用)
830ポイント$ 4.00
× 2
一時的な連絡ボタン
50ドルで1.00ドル。1つはリールの回転を制御し、3つはメニューをナビゲートし、2つは接地ピン1を制御します。 ATmegasの。
× 6
RGB拡散コモンカソード
さまざまなことを知らせるために使用されます。
× 1
LED(汎用)
ボードに電力が供給されているかどうかを示します。
× 1
抵抗10kオーム
4つで各ボタンを引き上げ、2つでATmegaのピン1に対応します。
× 6
抵抗1kオーム
各ボタンとATmega入力ピンの間。
× 4
抵抗330オーム
RGB LEDの赤、緑、青のリード線用。
× 3
16MHzクリスタル
1つはSlotMachineのATmega328P-PU用、もう1つはLEDディスプレイスレーブのATmega328P-PU用です。どちらも16MHzで動作します。
× 2
スライドスイッチ
電源用。
× 1
ブザー
2つ必要です。1つはSlotMachineチップ用、もう1つはディスプレイスレーブチップ用です。これらのうちの1つだけが必要であり、両方のマイクロコントローラーで共有できるように回路を変更すると便利です。
× 2
コンデンサ22pF
× 4
0.10uFコンデンサ
× 6
コンデンサ100nF
これはオプションであり、SlotMachineのプログラミングにArduino MiniUSBシリアルアダプターを使用している場合にのみ必要です。私が持っているように、チップ。
× 1
コンデンサ10µF
供給電圧をスムーズにするため。
× 2
リニアレギュレータ(7805)
電圧供給を調整するには、5V。
× 1
ジャンパー線(汎用)
これはかなりの量が必要です。ほとんどの場合、私は自分で作成しますが、ジャンパー線も使用します。
× 1
5V電源
× 1
Arduino MiniUSBシリアルアダプター
$ 13.20これはオプションで、ArduinoUnoを使用してATmega328p-puチップをプログラムできます。
× 1
FTDIUSB-TTLシリアルアダプター
$ 1.66 x 2 =$ 3.32ATmega328P-PUを適切にプログラミングするため。回路図には示されていません。
× 1
はんだ付け可能なブレッドボード
フルサイズのはんだ付け可能なブレッドボード。
× 1
SparkFunはんだ付け可能なブレッドボード-ミニ
× 1
ポケットはんだ-60/40ロジンコア直径0.031 "
× 1
透明なプラスチック製の防水電子プロジェクトボックスエンクロージャー
$ 13.00これはエンクロージャーです。
× 1

必要なツールとマシン

>
はんだごて(汎用)
救いの手

アプリとオンラインサービス

>
Arduino IDE
タイマーフリートーンライブラリ
LEDコントロールライブラリ
LiquidCrystal / LCDライブラリ
LiquidCrystalI2Cライブラリ

このプロジェクトについて

ATmegaエイリアンをテーマにしたスロットマシン

<図>

このプロジェクトは、2台のATmega328P-PUマイクロコントローラーを使用したエイリアンをテーマにしたスロットマシンの実装です。私はCoryPotterのAlienInvasion Slot Machineに触発され、そのアイデアを拡張したいと思いました。スロットマシンは、娯楽および教育目的でのみ使用されます。私は、ゲームが実際のスロットマシンを可能な限りシミュレートするように最善を尽くしました。このプロジェクトは現在、パンボードになっています。部品が中国から到着するとすぐにエンクロージャーが追加され、すべてをはんだ付けする機会がありました。このプロジェクトは、私が暇なときに構築するのに約2か月かかりました。私にとってビルドの最も困難な部分は、5億回ほどのシミュレーションの後で、カジノ業界が単純なスロットマシンの動作を期待するようにゲームを動作させるために必要なすべての数学を理解することでした。

<図>

ゲームの仕組み

ゲームには3つのリールがあり、各リールに同じ固有の25個のシンボルが表示されます(4つの8x8マトリックスを持つコンポーネントの8x8マトリックスの1つは使用されません)。勝つには5つの異なる方法があります。 3つの宇宙船を手に入れると、ジャックポットを獲得できます。あなたが1つか2つの宇宙船を手に入れるならば、あなたはまたいくつかのクレジットを獲得します。一致する2つまたは3つのシンボルを取得した場合、あなたも勝ちます。以下に示すように、宇宙船と2つのシンボルが一致する場合、ゲームは、最も低い確率/最も高い支払いで、勝利したイベントに基づいて支払います。言い換えれば、勝利イベントは相互に排他的であり、リールの1回のスピンで2つの異なる方法で勝利することはできません。これにより、プログラミングが少し簡単になりました。私には他にもたくさんの課題がありました。

<図>

機能

スロットマシンには、2つのナビゲーションボタンと1つの選択ボタンを使用して20 x 4I2C対応LCDディスプレイからアクセスできるいくつかの興味深い機能があります。ボタンは、マイクロコントローラーの外部割り込み機能を利用するかなり洗練されたデバウンスアルゴリズムを使用しています。これがメインメニューです。

<図>

<図>

メニューには6行あるため、メニュー全体を表示するには、[下に移動]ボタンを使用して下にスクロールする必要があります。リールを「回転させる」ための専用のボタンがあります。それに加えて、メインメニューから「再生」を選択することもできます。賭けはいつでも変更できます。

<図>

最もエキサイティングな機能は、ゲームを「自動」モードでプレイできることです。つまり、LCD画面の設定メニューから自動モードオプションを選択すると、オプションをもう一度選択するか、100万回再生されるまで、ゲームが何度も再生されます。これは、ゲームをテストするための重要な機能です。ここでサウンドを無効にすることもできます。

<図>

LCDのメニューから、シミュレーションから生成されたすべてのメトリックを表示することもできます。これらのメトリックも出力され、USBケーブルを使用してRXピンとTXピンを介してマイクロコントローラーをモニターに接続すると、シリアルモニターに表示される場合があります。表示される指標のリストには、クレジット残高、ジャックポットに当たった回数、その他の方法でクレジットを獲得した回数が含まれます。これにより、さまざまな支払いに基づいてシミュレーションを実行することができ、支払いテーブルを確立して証明するのに役立ちました。ペイアウトテーブル自体は構成できません。一度設定すると、同じままになります。ボラティリティ指数を使用してペイアウトテーブルを駆動することで構成可能にすることは可能だと思いますが、それにはさらに多くの作業が必要になります。

<図>

<図>

[リセット]オプションを使用すると、すべてのメトリック(EEprom書き込みを除く)をゼロにリセットできます。このチップは、EEpromへの約100,000回の書き込みで機能します。チップ上で利用可能なEEpromは512kであり、その一部しか使用していないため、100,000回の書き込みに近づくと、EEprom内のメトリックの場所を実際に移動することが可能になります。私はこの機能を実装していませんが、それはチップの寿命を延ばすための手段になるでしょう。

最後に、ホールド、または家が(時間の経過とともに)保持する各賭けのパーセンテージを構成できます。リセット操作を実行した後、保留を再度設定する必要があることに注意してください。

<図>

プレーヤーのクレジット残高は、常に8桁の7セグメントディスプレイに表示されます。

<図>

数学

ゲームが現実的であることを確認するために多くの作業が行われました。確率が計算され、ゲームが許容可能な揮発性指数(VI)を持つようにペイアウトテーブルが設計されました。このインデックスは、マシンの動作がどの程度予測可能かを測定します。 VIが高いマシンは、プレーヤー(または家)により多くのお金を稼ぐ可能性が高くなります。 VIが低いマシンよりも予測可能性が低くなります。同じ正確なゲームが、異なるVIを持つ異なるカジノ(または同じカジノ)に存在することは事実です。 VIは、支払いスケジュールを操作することによって変更されます。私たちのゲームでは、ここに各種類の勝利の確率と支払いがあります。

<図>

オッズ(右端)とペイアウト(左端)が劇的に異なることに注意してください。このゲームが、ペイアウトテーブルがオッズと一致するか、それに厳密に従うようにプログラムされている場合、VIは許容できないほど高くなります。ホールドはペイアウトのパーセンテージとして計算され、ハウス/カジノによって保持される賭けの部分です。前述のように、LCDメニューから保留を設定できます。管轄区域ごとに、その管轄区域内のスロットマシンの最大ホールドを管理する規制が異なることに注意してください。通常の最大ホールドは15%です。ホールドを法律で許可されている最大値に設定しても、必ずしもそのマシンによって生成される利益が最大化されるとは限らないことを理解してください。ホールドが高くなると、プレーヤーがマシンを使用できなくなる可能性があるためです。ただし、多くのプレーヤーはホールドを無視していると思います。ホールドは通常、細字で埋められており、マシンの需要曲線は比較的垂直です(つまり、マシンの使用コストであるホールドはほとんど無視されます)。マシンによって生み出される利益は、ゲーム自体のデザインだけでなく、マシンの場所や配置にもはるかに依存します。しかし、それは単なる憶測です。ホールドに敏感な知識豊富なギャンブラーがいると思います。

ゲームが正しく機能していることを証明するために、コードで利用可能な3つのテーブルを含むスプレッドシートが作成されました(最初のテーブルは上に表示されています)。スプレッドシートを作成する最初のステップは、各タイプの勝利のオッズを正確に計算することでした([計算された確率]列)。

3つの宇宙船

3つの宇宙船が出現する確率は、可能な組み合わせの総数の逆数です。勝ちの組み合わせの数、1、可能な組み合わせの総数、15625。各リールには25の一意のシンボルがあるため、確率は1 /(25 x 25 x 25)、つまり0.000064です。これにより、オッズ1 /確率-1は1から15624に等しくなります。ここで確率からオッズを計算する方法を学びました。

3つのシンボルが一致します(宇宙船を除く)

宇宙船以外の3つのシンボルが一致する確率は、24(各リールの一意のシンボルの数から宇宙船を引いた数)を可能な組み合わせの数で割ったものです。一致する3つのシンボルの組み合わせが24あるため、24は分子です。 24/15625 =0.001536。それはオッズを約1から650.04にします。

2つの宇宙船

一致する2つの宇宙船の合計24x3の組み合わせがあります。それは、宇宙船の2つのマッチを作る3つの方法があるからです。 X =宇宙船、Y =その他の記号、XXY、XYX、およびYXXを指定します。 Yには24の可能な値があります。したがって、24 X 3/15625 =0.004608です。オッズは1から216.01です。

1つの宇宙船が登場

リールごとに、1つの宇宙船が登場するために24 x24の組み合わせが可能です。

宇宙船はどのリールにも出現する可能性があるため、1つのリールで利用可能な組み合わせの数に3つのリールを掛ける必要があります。したがって、確率は24 x 24 x 3/15625 =0.110592です。オッズは1から8.04です。

2つのシンボルが一致します

宇宙船を除く任意の2つのシンボルには、23(25から1つの宇宙船から3つのシンボルに一致する1つのシンボルを引いたもの)x3リールx宇宙船ではない24のシンボルがあります。確率は(23 X 3 X 24)/ 15625 =0.105984です。オッズは1から8.44です。

勝利の種類ごとの確率がわかったので、スプレッドシートを使用して、ボラティリティインデックスを許容できる(<〜20)方法でペイアウトテーブルを設計できます。これを行う方法を理解するために、私はこの投稿に大きく依存しました。最初の表のHouseIncome列に、試行錯誤のプロセスを使用して、VIが20未満になり、セルJ10の合計がゼロに近づくまで値を入力しました。これらの値を使用して、SlotMachine.inoでTHREE_SPACESHIP_PAYOUT、THREE_SYMBOL_PAYOUT、TWO_SPACESHIP_PAYOUT、ONE_SPACESHIP_PAYOUT、およびTWO_SYMBOL_PAYOUTを適宜設定しました。次に、最初にゼロパーセントのホールドを使用して、1,000、001回の再生のシミュレーションを5回実行し、メトリックメニューの値を[実際の結果]テーブル(3番目のテーブル)の適切な行と列に入力しました。

<図>

確率実績が計算された確率と密接に追跡されており、Pct DiffProb列が妥当であることがわかりました。また、House Pays行の値を、Understanding Potential Incomeテーブル(2番目のテーブル)の1,000、000行のIncomeHigh列とIncomeLow列の値の範囲と一致させ、実際の結果テーブルは、IncomeHigh列とIncomeLow列で指定された範囲内にありました。潜在的な収入の理解の表は、90%の信頼区間で特定の保留値の予想収入範囲を定義します。以下の例では、ホールドが0に設定されているため、勝つ可能性は負ける可能性と一致します。ゲームを100万回プレイすると、収入が16、432から-16、432の間になる可能性が90%あります。

<図>

スプレッドシートとプログラムを操作し、何百万ものシミュレーションを実行した後、プログラムの欠陥を解決し、スプレッドシートの欠陥に対処し、VI <20を維持するペイアウトテーブルの値を定義することができました。最後に変更しました15%にホールドし、別の5つのシミュレーションを実行して、ゲームの収益が実際の状況でデプライされた場合の期待と一致していることを確認しました。15%ホールドの収益表は次のとおりです。

<図>

そして、これが実際の結果です。

<図>

ペイアウト値の設定の背後にあるすべての計算を本当に理解したい場合は、スプレッドシートの数式を調べることをお勧めします。エラーを見つけた場合は、親切に指摘してください。私は数学者(またはCプログラマー)ではないので、標準の免責事項が適用されます。

コード

コードを1行ずつ説明することはしません。それは広範囲にコメントされており、どこでもトリッキーなことは何も起こっていません。したがって、フォースを使用して、ソースを読んでください。 ATmega386のレジスターの操作に精通しておらず、Arduinoライブラリーに依存せずにAVRマイクロコントローラーのコードを書く方法についてもっと知りたい場合は、ElliottWilliamのコピーを入手することをお勧めします。優れた本「Make:AVRProgramming」。 safaribooksonline.comのサブスクリプションをお持ちの場合は、そこにあります。それ以外の場合は、Amazonで入手できます。これらのプログラムでは、Arduino関数を使用する場所もあれば、レジスターを直接操作する場所もあります。申し訳ありません。

最初に気付くかもしれないのは、プログラムがグローバル変数を広範囲に使用していることです。 Stack Overflowで、このトピックに関する良い議論があります。ここではグローバル変数の多用を促進または擁護するつもりはありませんが、このトピックに関するすべての視点を理解し、単一のプログラマーと限られたリソースで組み込みアプリケーションプロジェクトでそれらを使用することには強い議論があることを認識することをお勧めします。

私はいくつかのライブラリを利用していますが、それがなければ、このプロジェクトは私には不可能でした。タイマーフリートーンライブラリは、パッシブピエゾスピーカーを介してさまざまな周波数を駆動するために使用されます。 SlotMachine.hには、音符の定義が多数あることに気付くでしょう。それを使って、好きなメロディーをまとめることができます。 SlotMachineのマイクロコントローラーが起動し、セットアップ機能が実行されたときに、「第3種の接近遭遇」のテーマの一部を再生するためにそれらのほんの一握りを使用します。何かのためにタイマーが必要になると思ったので、タイマーフリーライブラリを選択しましたが、結局タイマーをまったく使用しなくなりました。必要に応じてご利用いただけます。 LEDコントロールライブラリは、SlotMachine.inoとslotCreditDisplaySlave.inoの両方で使用されます。前者では、スロットマシンのリールとして機能する3つの8 x 8LEDマトリックスを制御するために使用されます。 slotCreditDisplaySlave.inoでは、ライブラリにより、プレーヤーのクレジット残高を表示する8桁の7セグメントディスプレイに簡単にアクセスできます。これは、クレジット残高を提供するためだけに別のAVRチップ(ATmega328)を使用しないようにしたことを言及するのに良い時期ですが、8 x8マトリックスと8桁の7セグメントディスプレイを制御する方法を見つけることができませんでした単一のマイクロコントローラー。そのため、最終的には、その目的を果たすためにI2Cスレーブを作成する必要がありました。確かに、より安価なAVRを使用してクレジット残高を表示することもできますが、この記事を簡単にするために、別のATmega328P-PUチップを使用することにしました。明るい面としては、大きなジャックポットを獲得すると、クレジットはクレジット表示スレーブにカウントされ続けますが、先に進んで再びスピンすることができます。 LiquidCrystal / LCDおよびLiquidCrystalI2Cライブラリは、20行x4行のLCDディスプレイへのアクセスを容易にするために必要です。前述のように、LCD_SCREEN_HEIGHTの定義を4から2に変更するだけで、手元にある20 x 2 LCDに置き換えることができます。このプロジェクト用に取得するLCDディスプレイがI2C対応であることを確認してください。そうでない場合は、LCD1602アダプタプレート用のI2C SPIシリアルインターフェイスボードポートモジュール、部品番号PCF8574を入手し、LCD1602ディスプレイにはんだ付けする必要があります。

<図>

ゲームは同時に多くの異なる状態になる可能性があり、machineState変数は状態を追跡します。たとえば、「回転」と「自動モード」を同時に行うことができます。私はプログラムの中でこの概念をあまり利用していません。とにかく、他のプログラムほどではありません。ただし、状態に基づいていくつかの条件付き分岐があります。イベントの概念もあり、イベントはProcessEvents関数でディスパッチおよび処理されます。イベントキューがあればもっといいかもしれませんが、私はそこまで行きませんでした。

SlotMachine.inoのコメントセクションに既知の欠陥と「やるべきこと」のリストがあります。リールを「スピン」すると(スピンボタンを押すか、LCDメニューから「再生」オプションを選択して)、1つまたは2つのリールが動かないことがあります。これは、舞台裏で乱数ジェネレーターが、そのリールにすでに表示されているシンボルを選択したためです。これは、ゲームをよりリアルに見せるために修正できますが、実際には欠陥ではありません。ほとんどのスロットマシンのように、リールは左から右への回転を終了しません。これは、物事を単純にするために、設計によって行われます。リールが実際に回転する前に、回転ごとに生成される3つの乱数を昇順で並べ替えることで、リールを左から右に回転させることができます。私は気にしませんでした。

「todos」に関しては、ある時点で、電圧低下保護を追加し、犬の保護を監視して、演習を行い、その方法を学びたいと思います。グローバル変数に割り当てられたスペースの80%はすでに消費されていることに注意してください。これは、ATmega386およびArduinoプログラムで物事が不安定になり始める可能性があるポイントです。その時点で、このプログラムを使用しています。物事を機能させ続けるためにいくらかの予算を立てなければならなかったので、プログラムにこれ以上グローバルを追加することはお勧めしません。これにより、たとえば、メニューがグローバル変数スペースを大量に消費するため、メニューの設定部分に機能を追加することが困難になります。メニューをプログラムメモリに移動してグローバル変数の問題を解決しようとしましたが、グローバルで使用されるスペースを減らすことができませんでした。コンパイラはメニュー用にすべてのスペースを事前に割り当てる必要があるためだと思います。 。ゲームを少し盛り上げるために、さらに多くの作業を行うことができます。 RGB LEDとピエゾブザーをもっと活用し、勝利をもう少し祝い、お金がなくなったときに良い音を出すこともできますが、それを試してみたい人には任せます。

ゲームのすべてのシンボルをデザインする必要がありました。それらのいくつかは、古典的なアーケードゲーム「スペースインベーダー」を思い出させるでしょう、そして私はどこかからそれらを借りたかもしれません。残りは私が手作業でデザインしたもので、中にはプロ並みではないものもあります。このサイトを使用して、シンボルのデザインを支援しました。シンボルを調整したい場合は、SlotMachine.hで調整して、心ゆくまで遊んでください。プログラムロジックには影響しません。記号については、テキストエディタで設計できるように、基数2 /バイナリで数値を表します。

コードはGitHubで入手できます。

スロットマシンの構築

FTDI USB to Serialボードを使用して、両方のATmega328P-PUマイクロコントローラーをインプレースでプログラムしました。これらの接続は、フリッツの回路図には示されていません。はんだ不要のブレッドボードにFTDIブレークアウトボードを設定する手順については、このリンクをたどってください。あなたはセットアップを釘付けにするために少しグーグルする必要があるかもしれません。この投稿は、FTDIブレークアウトボードを介したプログラミングの開始時にマイクロコントローラーを自動的にリセットしようとしていた問題のトラブルシューティングにも役立ったと思います。 ATmega328リセットピン(位置1 / PC6 /リセットピン)とFTDIブレークアウトボードのRTSの間の接続と直列に、100 nFのコンデンサを配置することを忘れないでください。これにより、必要なときにリセットボタンを押し続ける必要がなくなります。チップをプログラムします。 Arduino Unoを使用してチップをプログラムすることを選択した場合、手順はここにあります。提供されたコードを使用してチップを一度だけプログラムする場合は、ArduinoUnoからチップをプログラムするのがおそらく最も速くて簡単です。

両方のマイクロコントローラーは、ブレッドボード上の「Arduino」チップ(ATmega328P-PU)でセットアップされています。コンポーネントをはんだ付けしてこのプロジェクトを最終的に構築することを計画している場合、またはプロジェクトをブレッドボードするときにここで行ったことをコピーしたい場合は、ブレッドボードにArduinoをセットアップする方法を理解する必要があります。それを行うには、ここの優れた指示に従ってください。これらの手順には、Arduinoブートローダーを2つのチップにロードする必要がある場合に従う必要のある手順が含まれています。これは、ここで提案されているように、中国のサプライヤーから、および/またはe-bay経由でチップを購入する場合に実行する必要があります。パーツのリストにあります。これを行うには、AVRISP mkIIやUSBTinyISPなどのAVRプログラマーが必要です。 Arduinoがある場合は、それを使用してブートローダーを書き込むこともできます。上記のリンクをたどると、すべてのオプションが説明されます。

パーツ

If you have some of the smaller components in your inventory already (resistors, capacitors, the crystal and the regulator) then you can get away with spending <$40 on parts for this build. If you add in the cost of the enclosure and the perfboard, it's probably approaching $60. I've tried to include the supplier I used for all of the pieces. I use AliExpress.com, Amazon.com, and ebay.com for most of my parts and tools, and all of these parts are easily sourced at any of those locations. Also, if you don't want to purchase a 20 x 4 LCD display, and you already have a 20 x 2 LCD display on hand, you can simply change LCD_SCREEN_HEIGHT in SlotMachine.ino from 4 to 2.

Here is the enclosure I've ordered, into which I'll insert the components:

<図>

This item is available here for $13.80. That's a little on the pricey side in my view. I'm hoping that everything will fit and that the top is very transparent so that I don't have to cut holes in it to see the reels and the credit balance display. We'll see how it goes when it gets here! Suggestions welcome.

ソフトウェア

All of these libraries listed in the parts section will need to be installed into your Arduino development environment if you wish to compile the code so that you can upload it onto your ATmega chip. This page explains how to install an Arduino library.

Hand Tools

  • Soldering iron
  • Helping Hands

Schematic

The Fritzing schematic is available here, and the.fzz file is included with the code on GitHub.

<図>

Below I've included some directions on wiring the micro-controllers, because the Fritzing diagram is crowded. This doesn't represent all of the connections necessary, but it should clear up any confusion. I haven't grounded all of the unused pins, but I am probably going to do that in the final product. If you're having trouble following the Fritzing diagram with respect to setting up the circuitry for the power supply, remember to look here, under Adding circuitry for a power supply 。 Remember to add the switch between the breadboard ground rail and the power supply circuit so that you can power the circuit off and on without having to unplug or disconnect the power supply. That will be important when we put everything into an enclosure.

Slot Machine

  • Pin 1 - RTS on the FTDI USB to Serial break out board, reset button
  • Pin 2 - TXD on the FTDI USB to Serial break out board
  • Pin 3 - RXD on the FTDI USB to Serial break out board
  • Pin 4 - 1K ohm resistor - momentary 'spin' button
  • Pin 5 - 330 ohm resistor - RGB LED blue pin
  • Pin 6 - unused, consider grounding it
  • Pin 7 VCC - breadboard power rail, 0.1uF capacitor
  • Pin 8 GND - breadboard ground rail, 0.1uF capacitor
  • Pin 9 XTAL1 - 16MHz crystal, 22pF capacitor to breadboard ground rail
  • Pin 10 XTAL2 - 16MHz crystal, 22pF capacitor to breadboard ground rail
  • Pin 11 - unused, consider grounding it
  • Pin 12 - unused, consider grounding it
  • Pin 13 - unused, consider grounding it
  • Pin 14 - DIN on the 8x8 matrices
  • Pin 15 - 330 ohm resistor - RGB LED red pin
  • Pin 16 - 330 ohm resistor - RGB LED green pin
  • Pin 17 - piezo buzzer positive - negative piezo buzzer - breadboard ground rail
  • Pin 18 - CS on the 8x8 matrices
  • Pin 19 - CLK on the 8x8 matrices
  • Pin 20 AVCC - breadboard power rail, 0.1uF capacitor
  • Pin 21 AREF - breadboard power rail
  • Pin 22 GND - breadboard ground rail
  • Pin 23 - leave this pin floating, it's used to seed the random number generator
  • Pin 24 - 1K ohm resistor - momentary 'navigate up' button
  • Pin 25 - 1K ohm resistor - momentary 'navigate down' button
  • Pin 26 - 1K ohm resistor - momentary 'select' button
  • Pin 27 SDA - Pin 27 SDA on the display I2C ATmega328P-PU slave
  • Pin 28 SCL - Pin 28 SCL on the display I2C ATmega328P-PU slave

Display Slave

  • Pin 1 - RTS on the FTDI USB to Serial break out board, reset button
  • Pin 2 - TXD on the FTDI USB to Serial break out board
  • Pin 3 - RXD on the FTDI USB to Serial break out board
  • Pin 4 - unused, consider grounding it
  • Pin 5 - unused, consider grounding it
  • Pin 6 - unused, consider grounding it
  • Pin 7 VCC - breadboard power rail, 0.1uF capacitor
  • Pin 8 GND - breadboard ground rail, 0.1uF capacitor
  • Pin 9 XTAL1 - 16MHz crystal, 22pF capacitor to breadboard ground rail
  • Pin 10 XTAL2 - 16MHz crystal, 22pF capacitor to breadboard ground rail
  • Pin 11 - unused, consider grounding it
  • Pin 12 - unused, consider grounding it
  • Pin 13 - unused, consider grounding it
  • Pin 14 - unused, consider grounding it
  • Pin 15 - piezo buzzer positive - negative piezo buzzer - breadboard ground rail
  • Pin 16 - CS on the seven segment display
  • Pin 17 - CLK on the seven segment display
  • Pin 18 - DIN on the seven segment display
  • Pin 19 - unused, consider grounding it
  • Pin 20 AVCC - breadboard power rail, 0.1uF capacitor
  • Pin 21 AREF - breadboard power rail
  • Pin 22 GND - breadboard ground rail
  • Pin 23 - unused, consider grounding it
  • Pin 24 - unused, consider grounding it
  • Pin 25 - unused, consider grounding it
  • Pin 26 - unused, consider grounding it
  • Pin 27 SDA - Pin 27 SDA on the slot machine I2C ATmega328P-PU
  • Pin 28 SCL - Pin 28 SCL on the slot machineI2C ATmega328P-PU

まとめ

This project was a lot of fun to build. The most challenging part was understanding all of the math necessary to create a payout table that works. I hope you can have fun with this project too, if you decide to build it. If you have any problems, questions, or, most importantly, discover any defects in the code or with the math, please contact me so I can fix any problems! My email address is [email protected]. I'll be creating part II of this article when I enclose all of the components.

コード

  • SlotMachine.ino
  • SlotMachine.h
  • slotCreditsDisplaySlave.ino
SlotMachine.inoArduino
/*SlotMachine.ino Version:1.0 Date:2018/07/01 - 2018/08/29 Device:ATMega328P-PU @ 16mHz Language:C Purpose =======A slot machine for entertainment and educational purposes only, with the following features:- AtMega328P microcontroller running at 16mHz - Custom I2C seven segment display for displaying credit balance, also built with an ATMega328P running at 16mHz. That program is supplied in a seperate file. - Three 8x8 LED matricies for displaying symbols driven by MAX7219. - I2C LCD display 20x4, to show menus - various buzzers, buttons and an RGB LED. - the ability to update various settings via the LCD menu to influence the machine's behavior. - the ability to change the amount of the wager. Known Defects =============- Sometimes one or two of the reels won't spin, not really a defect. - crash as soon as payed out exceeds 1,000,000. TODO ====- add brown out detection - add watch dog protection (wdt_enable(value), wdt_reset(), WDTO_1S, WDTO_250MS) Warnings ========- Beware of turning on too much debugging, it's easy to use all of the data memory, and in general this makes the microcontroller unstable. - Gambling is a tax on people who are bad at math. This is for entertainment only. It was the intent of the author to program this game to return ~%hold of every wager to the house, similar to many slot machines. - Why not control the LED that displays the credits with the LedControl library? I tried that and couldn't get more than one LedControl object to work at a time. So I had to create an I2C slave instead and use another AVR. Suggestions ===========- Best viewed in an editor w/ 160 columns, most comments are at column 80 - Please submit defects you find so I can improve the quality of the program and learn more about embedded programming. Author ======- Copyright 2018, Daniel Murphy  - Contributors:Source code has been pulled from all over the internet, it would be impossible for me to cite all contributors. Special thanks to Elliott Williams for his essential book "Make:AVR Programming", which is highly recommended. Thanks also to Cory Potter, who gave me the idea to do this. License =======Daniel J. Murphy hereby disclaims all copyright interest in this program written by Daniel J. Murphy. This program is free software:you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Libraries =========- https://github.com/wayoda/LedControl - https://bitbucket.org/teckel12/arduino-timer-free-tone/wiki/Home - https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library - https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home The Program ===========- Includes */#include #include #include  // for the abs function#include "LedControl.h" // https://github.com/wayoda/LedControl#include "SlotMachine.h"#include  // https://bitbucket.org/teckel12/arduino-timer-free-tone/wiki/Home#include #include  // https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home#include  // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library//- Payout Table/* Probabilities based on a 1 credit wager Three spaceships:1 / (25 * 25 * 25) =0.000064 Any three symbols:24 / 15625 =0.001536 Two spaceships:(24 * 3) / 15625 =0.004608 One spaceship:(24 * 24 * 3)/ 15625 =0.110592 Two symbols match:(23 * 3 * 24) / 15625 =0.105984 House win, 1 minus sum of all probabilities =0.777216 _ Use the spreadsheet to work out the payout table remembering to keep the volatility resonable i.e. <20. P R O O F Actual Actual Winning Combination Payout Probablility Count Probability ========================================================*/#define THREE_SPACESHIP_PAYOUT 600 // 0.000064 0.00006860 se e the excel spreadsheet #define THREE_SYMBOL_PAYOUT 122 // 0.001536 0.00151760 that accompanies this program.#define TWO_SPACESHIP_PAYOUT 50 // 0.004608 0.00468740#define ONE_SPACESHIP_PAYOUT 3 // 0.110592 0.11064389#define TWO_SYMBOL_PAYOUT 2 // 0.105984 0.10575249//// With these payouts the Volatility Index is 16.43////- Macros#define ClearBit(x,y) x &=~y#define SetBit(x,y) x |=y#define ClearBitNo(x,y) x &=~_BV(y) #define SetState(x) SetBit(machineState, x)//- Defines#define DEBUG 1 // turns on (1) and off (0) output from debug* functions#define BAUD_RATE 38400 // Baud rate for the Serial monitor #define NUMFRAMES 25 // Number of symbols in each "reel" or "s lot". e.g three reels:|7|7|7|#define LINESPERFRAME 8 // each line corresponds to one row on the 8x8 dot matrix LED#define FRAME_DELAY 100 // milliseconds, controls the speed of the spinning reels#define NUMREELS 3 // the hardware (8x8 matricies) accomodates 4 reels, we're only using three now #define DEBOUNCE_TIME 1000 // microseconds (changed from 500 to 1000 to cut down on double press problem) #define BUTTON_DDR DDRD // this accomodates the button that starts the reels spinning#define BUTTON_PORT PORTD#define BUTTON_PIN PIND#define PCMSK_BUTTON PCMSK2#define PCIE_BUTTON PCIE2 #define BUTTON_SPIN_PIN DDD2 // the actual spin button#define BUTTON_SPIN_INT PCINT18#define BUTTON_SPIN_PORT PORTD2 #define NAV_DDR DDRC // this is for the buttons that control menu navigation on the 20x4 LCD#define NAV_PORT PORTC#define NAV_PIN PINC#define PCMSK_NAV PCMSK1#define PCIE_NAV PCIE1 #define NAV_UP_PIN DDC1 // Navigate up button#define NAV_UP_INT PCINT9#define NAV_UP_PORT PORTC1 #define NAV_DOWN_PIN DDC2 // Navigate down button#define NAV_DOWN_INT PCINT10#define NAV_DOWN_PORT PORTC2 #define SELECT_PIN DDC3 // Select current menu item button#define SELECT_INT PCINT11#define SELECT_PORT PORTC3 #define BUZZER_DDR DDRB // This is for the slot machines piezo buzzer#define BUZZER_PORT PORTB#define BUZZER_PIN DDB3#define TONE_PIN 11 // Pin you have speaker/piezo connected to (TODO:be sure to include a 100ohm resistor).#define EVENT_NONE 0 // These are all of the various events that can occur in the machine#define EVENT_SPIN 1#define EVENT_SHOW_MENU 2 #define EVENT_SELECT 3#define EVENT_NAV_UP 4#define EVENT_NAV_DOWN 5#define EVENT_BACK 6#define EVENT_PLAY 10#define EVENT_BET 11#define EVENT_SETTINGS 12#define EVENT_VIEW_METRICS 13#define EVENT_RESET 14#define EVENT_HOLD 15#define STATE_IDLE B00000001 // These are the various states the machine can be in, not all are#define STATE_SPINNING B00000010 // mutually exclusive.#define STATE_AUTO B00000100 // This state is for automatically running the program to gather metrics.#define STATE_SHOW_MENU B00001000 // State we're in when showing the menu. Note you can spin and show menu // concurrently.#define MINIMUM_WAGER 5 // TODO:consider this something that can be changed via settings#define WAGER_INCREMENT 5 // TODO:consider this something that can be changed via settings#define ONE_SECOND 1000 // # milliseconds in one second. Used to control how long the siren sounds. #define SHIP_LOC 144 // Location of various symbols in the array of symbols maintained in SlotMachine.h#define ALIEN_1_LOC 152 // needed for animation#define ALIEN_2_LOC 160#define EEPROM_FREQ 10000 // Write to EEPROM every Nth play#define AUTO_MODE_MAX 1000000 // stop after this many plays in auto mode#define RED 1 // TODO:should we use an enum here? Must be a better way...#define GREEN 2#define BLUE 3#define PURPLE 4#define WHITE 5#define OFF 6#define MAX_NOTE 4978 // Maximum high tone in hertz. Used for siren.#define MIN_NOTE 31 // Minimum low tone in hertz. Used for siren.#define STARTING_CREDIT_BALANCE 500 // Number of credits you have at "factory reset".#define DEFAULT_HOLD 0 // default hold is zero, over time the machine pays out whatever is wagered#define NUM_LED_DATAIN 7#define NUM_LED_CLK 6#define NUM_LED_LOAD 5#define NUM_CHIP_COUNT 1#define MATRIX_LED_DATAIN 8#define MATRIX_LED_CLK 13#define MATRIX_LED_LOAD 12#define MATRIX_CHIP_COUNT 4#define LOW_INTENSITY 1 // dim#define HIGH_INTENSITY 10 // bright#define SIREN_FLASHES 1#define LCD_SCREEN_WIDTH 20#define LCD_SCREEN_HEIGHT 4#define CREDITS_I2C_SLAVE_ADDR 0x10 // I2C addresses#define LCD_I2C_ADDR 0x3F // LCD display w/ 4 lines#define BACKLIGHT_PIN 3#define En_pin 2#define Rw_pin 1#define Rs_pin 0#define D4_pin 4#define D5_pin 5#define D6_pin 6#define D7_pin 7#define MENU_SIZE 17#define MAIN_MENU_NUMBER 0#define MAIN_MENU_ELEMENTS 6char *mainMenu[] ={ "Play", "Bet", "Settings", "Metrics", "Reset", "Hold", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " };#define BET_MENU_NUMBER 1#define BET_MENU_ELEMENTS 3char *betMenu[] ={ "+5 credits:", // TODO:make this dynamic based on WAGER_INCREMENT "-5 credits:", "Back", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " };#define SETTINGS_MENU_NUMBER 2#define SETTINGS_MENU_ELEMENTS 3#define SETTINGS_BACK_ITEM 2char *settingsMenu[] ={ "Auto/Manual", // TODO:fill out this menu with more cool options "Toggle Sound ", "Back ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " };#define METRICS_MENU_NUMBER 3#define METRICS_MENU_ELEMENTS 15char *metricsMenu[METRICS_MENU_ELEMENTS];#define HOLD_MENU_NUMBER 4#define HOLD_MENU_ELEMENTS 3char *holdMenu[] ={ "+1 percent:", "-1 percent:", "Back", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " };int selectPos =0;int menuNumber =MAIN_MENU_NUMBER;int elements =MAIN_MENU_ELEMENTS;char *currentMenu[MENU_SIZE];LiquidCrystal_I2C lcd( LCD_I2C_ADDR, // Create the LCD display object for the 20x4 display En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin );LedControl lc=LedControl( MATRIX_LED_DATAIN, // Create the LED display object for the 8x8 matrix MATRIX_LED_CLK, MATRIX_LED_LOAD, MATRIX_CHIP_COUNT ); // Pins:DIN,CLK,CS, # of chips connectedvolatile int reelArrayPos[NUMREELS];volatile byte machineState;volatile byte event =EVENT_NONE;volatile byte color =RED;#define ADC_READ_PIN 0 // we read the voltage from this floating pin to seed the random number generator#define RED_PIN 9 // Pin locations for the RGB LED#define GREEN_PIN 10#define BLUE_PIN 3#define NUM_NOTES 5 // The number of notes in the melody // EEProm address locations#define PAYEDOUT_ADDR 0x00 // 4 bytes#define WAGERED_ADDR 0x04 // 4 bytes#define PLAYED_ADDR 0x08 // 4 bytes#def ine TWO_MATCH_ADDR 0x12 // 4 bytes#define THREE_MATCH_ADDR 0x16 // 2 bytes#define SHIP_ONE_MATCH_ADDR 0x18 // 4 bytes#define SHIP_TWO_MATCH_ADDR 0x22 // 2 bytes#define SHIP_THREE_MATCH_ADDR 0x24 // 2 bytes#define EEPROM_WRITES_ADDR 0x34 // 4 bytes#define RESET_FLAG_ADDR 0x38 // 4 bytes#define CREDIT_BALANCE_ADDR 0x42 // 4 bytes#define HOLD_ADDR 0x46 // 2 bytesboolean sound =true;byte reelMatches =0; // per play variablesbyte shipMatches =0;unsigned long wagered =0; // amount wagered on a single spindouble owedExcess =0; // change, need to track this so hold is accurateunsigned long twoMatchCount =0; // 1 if two symbols matchunsigned int threeMatchCount =0; // 1 if three symbols matchunsigned long shipOneMatchCount =0; // 1 if there's one ship presentunsigned int shipTwoMatchCount =0; // 1 if there are two ships presentunsigned int shipThreeMatchCount =0; // 1 if there are three ships present (Jackpot!)unsigned long totalCalcs =0; // total plays only relavent in auto modesigned long startingCreditBalance; // the credit balance before spinningint increment =WAGER_INCREMENT;#define DISP_CREDIT_INCREMENT 1 // on the seven segment display, increment/decrement the balance by this value until the final value is reached. // lifetime variables (stored in EEprom) Reset sets most back to zerounsigned long storedPayedOut; // sum of all payoutsunsigned long storedWagered; // sum of all wagers (profit =payouts - wagers)unsigned long storedPlays; // the number of spinsunsigned long storedTwoMatchCount; // number of times two symbols have matchedunsigned int storedThreeMatchCount; // number of times three symbols have matchedunsigned long storedShipOneMatchCount; // number of times one ship has appearedunsigned int storedShipTwoMatchCount; // number of time two ships have appearedunsigned int storedShipThreeMatchCount; // number of times three ships have appeared (Jackpot!)unsigned long storedEEpromWrites; // number of times we've written to EEprom. 100,000 is the approximate maximumsigned long storedCreditBalance; // the credit balance.int storedHold =DEFAULT_HOLD; // the house advantage, in percent, usually between 1 and 15, 2 bytes volatile byte portdhistory =0b00000100; // default is high because of the pull-up, correct settingvolatile byte portchistory =0b00001110; // default is high because of the pull-up, correct setting //- Debugging Routines // These routines are helpful for debugging, I will leave them in for your use. // For sending output to the serial monitor. Set the baud rate in setup.void debug(String text) { if (DEBUG) { Serial.println(text); }}void debugNoLF(String text) { if (DEBUG) { Serial.print(text); }}void debugInt(signed int anInt) { if (DEBUG) { char myInt[10]; itoa(anInt,myInt,10); debug(myInt); }}void debugLong(signed long aLong) { if (DEBUG) { char myLong[10]; ltoa(aLong,myLong,10); debug(myLong); }}void debugDouble(double aDouble) { if (DEBUG) { char *myDouble =ftoa(aDouble); debug(myDouble); }}void debugMetric(const char myString[], signed int anInt) { if (DEBUG) { debugNoLF(myString);debugNoLF(F(":")); debugInt(anInt); Serial.print(F("\r\n")); }}void debugMetricLong(const char myString[], signed long aLong) { if (DEBUG) { debugNoLF(myString);debugNoLF(F(":")); debugLong(aLong); Serial.print(F("\r\n")); }}void debugStoredMetrics() { for (int i =0; i <11; i++) { debug(metricsMenu[i]); }}void debugMetricDouble(const char myString[], double aDouble) { if (DEBUG) { debugNoLF(myString);debugNoLF(F(":")); debugDouble(aDouble); Serial.print(F("\r\n")); }} // quick and dirty ftoa for legacy codechar *ftoa(double f) // from https://www.microchip.com/forums/m1020134.aspx{ static char buf[17]; char * cp =buf; unsigned long l, rem; if(f <0) { *cp++ ='-'; f =-f; } l =(unsigned long)f; f -=(double)l; rem =(unsigned long)(f * 1e6); sprintf(cp, "%lu.%10.10lu", l, rem); return buf;}//- All Other Functionsvoid beep() { // Beep and flash LED green unless STATE_AUTO setGreen(); if (sound) { BUZZER_PORT |=(1 < 0) { celebrateWin(reelMatches); } setupMetricsMenu(); } else if ((totalCalcs++%EEPROM_FREQ) ==0) { // EEPROM can be written ~100,000 times, storeMetrics(); displayCredits(); // displayCredits takes care of the sign on increment setupMetricsMenu(); debugStoredMetrics(); debugMetricDouble("owedExcess",owedExcess); // don't want to put owedExcess in metricsMenu because of global var space shortage if (totalCalcs>=AUTO_MODE_MAX) { // drop out of auto mode when threshold exceeded ClearBit(machineState, STATE_AUTO); SetState(STATE_IDLE); event =EVENT_NONE; } } ClearBit(machineState, STATE_SPINNING);}void spin() {//debug("spin()"); SetState(STATE_SPINNING); if (!(STATE_AUTO ==(machineState &STATE_AUTO))) { beep(); } zeroAllBalances(); byte reelsStopped[NUMREELS] ={0,0,0}; byte stopArrayPos[NUMREELS]; for (int reelNum =0; reelNum  0) { winnings =wagered * (THREE_SPACESHIP_PAYOUT - (THREE_SPACESHIP_PAYOUT * (storedHold/100.0))); // winnings are the amount wagered times the payout minus the hold. } else if (threeMatchCount> 0) { winnings =wagered * (THREE_SYMBOL_PAYOUT - (THREE_SYMBOL_PAYOUT * (storedHold/100.0))); } else if (shipTwoMatchCount> 0) { winnings =wagered * (TWO_SPACESHIP_PAYOUT - (TWO_SPACESHIP_PAYOUT * (storedHold/100.0))); } else if (shipOneMatchCount> 0) { winnings =wagered * (ONE_SPACESHIP_PAYOUT - (ONE_SPACESHIP_PAYOUT * (storedHold/100.0))); } else if (twoMatchCount> 0) { winnings =wagered * (TWO_SYMBOL_PAYOUT - (TWO_SYMBOL_PAYOUT * (storedHold/100.0))); } else { winnings =0; } signed long roundWinnings =(signed long) round(winnings); owedExcess +=winnings - roundWinnings; // owedExcess is the change; credits between -1 and 1. if (owedExcess>=1 || owedExcess <=-1) { // if we can pay out some excess int roundOwedExcess =(int) round(owedExcess); roundWinnings +=roundOwedExcess; // add the rounded portion to the winnings owedExcess -=roundOwedExcess; // subtract out what we added to continue to track the excess } roundWinnings -=wagered; // you pay for your bet whether you won or not! // winnings -=wagered; return roundWinnings;// return((signed long) round(winnings));}void calcStored(signed long winnings) { storedPayedOut +=winnings; storedWagered +=wagered; startingCreditBalance =storedCreditBalance; storedCreditBalance +=winnings; storedPlays +=1; // calcStored is called one time per play storedTwoMatchCount +=twoMatchCount; storedThreeMatchCount +=threeMatchCount; storedShipOneMatchCount +=shipOneMatchCount; storedShipTwoMatchCount +=shipTwoMatchCount; storedShipThreeMatchCount +=shipThreeMatchCount;}void storeMetrics() { beepAuto(); // so we know we're not hung in auto mode. updateStoredPayedOut(); updateStoredWagered(); updateStoredPlays(); updateStoredTwoMatchCount(); updateStoredThreeMatchCount(); updateStoredShipOneMatchCount(); updateStoredShipTwoMatchCount(); updateStoredShipThreeMatchCount(); storedEEpromWrites++; updateStoredEEpromWrites(); updateStoredCreditBalance(); updateStoredHold();}void displayCredits() {//debug("displayCredits()"); int xmitIncrement; if ((STATE_AUTO ==(machineState &STATE_AUTO))) { // display the credits here if we're in auto mode. xmitIncrement =abs(startingCreditBalance - storedCreditBalance); // we don't want the display slave to count up/down } else { xmitIncrement =DISP_CREDIT_INCREMENT; // set increment back to what it should be during manual play } Wire.beginTransmission(CREDITS_I2C_SLAVE_ADDR); Wire.write( startingCreditBalance &0xFF); Wire.write((startingCreditBalance &0xFF00)>> 8); Wire.write((startingCreditBalance &0xFF0000)>> 16); Wire.write((startingCreditBalance &0xFF000000)>> 24); // most sigificant byte sent last if (startingCreditBalance> storedCreditBalance) { // if the player lost, xmitIncrement *=-1; // flip the sign on increment so we count down } Wire.write( xmitIncrement &0xFF); Wire.write((xmitIncrement &0xFF00)>> 8); Wire.write( storedCreditBalance &0xFF); Wire.write((storedCreditBalance &0xFF00)>> 8); Wire.write((storedCreditBalance &0xFF0000)>> 16); Wire.write((storedCreditBalance &0xFF000000)>> 24); // most sigificant byte sent last byte error =Wire.endTransmission(); if (error==4) { debug(F("Unknown error at address")); // I've never seen this happen. } }bool allReelsStopped(byte reelsStopped[]) { byte sumStopped =0; for (int i; i  
SlotMachine.hC Header File
const byte reel[] ={ // 0 star B10011001, //0 B01011010, B00111100, B11111111, B11111111, B00111100, B01011010, B10011001, // 1 one spot on dice B00000000, // 8 B00000000, B00000000, B00011000, B00011000, B00000000, B00000000, B00000000, // 2 three bars B11111111, // 16 B11111111, B00000000, B11111111, B11111111, B00000000, B11111111, B11111111, // 3 heart B01100110, // 24 B11111111, B11111111, B11111111, B11111111, B01111110, B00111100, B00011000, // 4 two spots on dice B00000000, // 32 B01100000, B01100000, B00000000, B00000000, B00000110, B00000110, B00000000, // 5 seven B00000000, // 40 B01111110, B01111110, B00001100, B00011000, B00111000, B00111000, B00000000, // 6 dollar sign B00011000, // 48 B00111100, B01011010, B00111000, B00011100, B01011010, B00111100, B00011000, // 7 three spots on dice B00000000, B01100000, B01100000, B00011000, B00011000, B00000110, B00000110, B00000000, // 8 inverse 9 spots, hashtag # B00100100, B00100100, B11111111, B00100100, B00100100, B11111111, B00100100, B00100100, // 9 one bar B00000000, B00000000, B00000000, B11111111, B11111111, B00000000, B00000000, B00000000, // 10 four on dice B00000000, B01100110, B01100110, B00000000, B00000000, B01100110, B01100110, B00000000, // 11 inverse seven B11111111, B10000001, B10000001, B11110011, B11100111, B11000111, B11000111, B11111111, // 12 9 spots B11011011, B11011011, B00000000, B11011011, B11011011, B00000000, B11011011, B11011011, // 13 five on dice B00000000, B01100110, B01100110, B00011000, B00011000, B01100110, B01100110, B00000000, // 14 two bars B00000000, B11111111, B11111111, B00000000, B00000000, B11111111, B11111111, B00000000, // 15 Alien 0 (120) B01000010, B00100100, B01111110, B11011011, B11111111, B11111111, B10100101, B00100100, // 16 smile face (128) B00000000, B00100100, B00000000, B00011000, B01000010, B01000010, B00111100, B00011000, // 17 6 on dice (136) B00000000, B11011011, B11011011, B00000000, B00000000, B11011011, B11011011, B00000000, // 18 SpaceShip (144) B00000000, B00000000, B00111100, B01111110, B10101011, B01111110, B00111100, B00000000, // 19 Alien 1 (152) B00011000, B00111100, B01111110, B11011011, B11111111, B00100100, B01011010, B10100101, // 20 Alien 2 (160) B00011000, B00111100, B01111110, B11011011, B11111111, B00100100, B01011010, B01000010, // 21 Alien 3 (168) B00000000, B10000001, B11111111, B11011011, B11111111, B01111110, B00100100, B01000010, // 22 one B00010000, B00110000, B00010000, B00010000, B00010000, B00010000, B00010000, B00111000, // 23 two B00111000, B01000100, B10000010, B00000100, B00001000, B00010000, B00100000, B11111110, // 24 three B11111111, // 192 B00000010, B00000100, B00011100, B00000010, B00000100, B00001000, B11100000};/************************************************* * Public Constants *************************************************/#define NOTE_B0 31#define NOTE_C1 33#define NOTE_CS1 35#define NOTE_D1 37#define NOTE_DS1 39#define NOTE_E1 41#define NOTE_F1 44#define NOTE_FS1 46#define NOTE_G1 49#define NOTE_GS1 52#define NOTE_A1 55#define NOTE_AS1 58#define NOTE_B1 62#define NOTE_C2 65#define NOTE_CS2 69#define NOTE_D2 73#define NOTE_DS2 78#define NOTE_E2 82#define NOTE_F2 87#define NOTE_FS2 93#define NOTE_G2 98#define NOTE_GS2 104#define NOTE_A2 110#define NOTE_AS2 117#define NOTE_B2 123#define NOTE_C3 131#define NOTE_CS3 139#define NOTE_D3 147#define NOTE_DS3 156#define NOTE_E3 165#define NOTE_F3 175#define NOTE_FS3 185#define NOTE_G3 196#define NOTE_GS3 208#define NOTE_A3 220#define NOTE_AS3 233#define NOTE_B3 247#define NOTE_C4 262#define NOTE_CS4 277#define NOTE_D4 294#define NOTE_DS4 311#define NOTE_E4 330#define NOTE_F4 349#define NOTE_FS4 370#define NOTE_G4 392#define NOTE_GS4 415#define NOTE_A4 440#define NOTE_AS4 466#define NOTE_B4 494#define NOTE_C5 523#define NOTE_CS5 554#define NOTE_D5 587#define NOTE_DS5 622#define NOTE_E5 659#define NOTE_F5 698 #define NOTE_FS5 740#define NOTE_G5 784#define NOTE_GS5 831#define NOTE_A5 880#define NOTE_AS5 932#define NOTE_B5 988#define NOTE_C6 1047 #define NOTE_CS6 1109#define NOTE_D6 1175#define NOTE_DS6 1245#define NOTE_E6 1319#define NOTE_F6 1397 #define NOTE_FS6 1480#define NOTE_G6 1568 #define NOTE_GS6 1661#define NOTE_A6 1760 #define NOTE_AS6 1865#define NOTE_B6 1976#define NOTE_C7 2093#define NOTE_CS7 2217#define NOTE_D7 2349#define NOTE_DS7 2489#define NOTE_E7 2637#define NOTE_F7 2794#define NOTE_FS7 2960#define NOTE_G7 3136#define NOTE_GS7 3322#define NOTE_A7 3520#define NOTE_AS7 3729#define NOTE_B7 3951#define NOTE_C8 4186#define NOTE_CS8 4435#define NOTE_D8 4699#define NOTE_DS8 4978
slotCreditsDisplaySlave.inoArduino
/*slotCreditsDisplaySlave.ino Version:1.0 Date:2018/07/01 - 2018/07/29 Device:ATMega328P-PU @ 16mHz Language:C Purpose =======`The .purpose of this program is to function as an I2C slave responsible for displaying credits in a slot machine Known Defects =============- TODO ====- is 38400 an efficient baud rate for arduino running at 16mhz? - include a 100 ohm resistor with the piezo buzzer - is 100kHz the fastest setting we can accomodate w/ Wire library? Warnings ========- Suggestions ===========- Author ======- Copyright 2018, Daniel Murphy  License =======Daniel J. Murphy hereby disclaims all copyright interest in this program written by Daniel J. Murphy. This program is free software:you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Libraries =========- https://github.com/wayoda/LedControl The Program ===========- Includes */#include #include "LedControl.h"#define BAUD_RATE 38400 #define CREDITS_SLAVE_ADDR 16 #define DISPLAY_DELAY 5#define DEBUG 1#define BUZZER_DDR DDRB#define BUZZER_PORT PORTB#define BUZZER_PIN DDB1#define TONE_PIN 9 // Pin you have speaker/piezo connected to (be sure to include a 100 ohm resistor).#define BEEP_LENGTH 100 // Now we need a LedControl to work with. // pin 12 is connected to the DataIn // pin 11 is connected to the CLK // pin 10 is connected to LOAD // We have only a single MAX72XX.LedControl lc=LedControl(12,11,10,1);static const int slaveAddress =CREDITS_SLAVE_ADDR; long volatile theCredits[10] ={0L,0L,0L,0L,0L,0L,0L,0L,0L,0L};signed long volatile displayedBalance =0;signed long volatile startingCreditBalance =0;signed long volatile endingCreditBalance;signed int volatile increment;boolean volatile updateDisplayFlag =false;void debug(String text) { if (DEBUG) { Serial.println(text); }}void debugNoLF(String text) { if (DEBUG) { Serial.print(text); }}void debugInt(signed int anInt) { if (DEBUG) { char myInt[10]; itoa(anInt,myInt,10); debug(myInt); }}void debugLong(signed long aLong) { if (DEBUG) { char myLong[10]; ltoa(aLong,myLong,10); debug(myLong); }}void debugMetric(const char myString[], signed int anInt) { if (DEBUG) { debugNoLF(myString);debugNoLF(":"); debugInt(anInt); Serial.print("\r\n"); }}void debugMetricLong(const char myString[], signed long aLong) { if (DEBUG) { debugNoLF(myString);debugNoLF(":"); debugLong(aLong); Serial.print("\r\n"); }}void beep() { BUZZER_PORT |=(1 < 

回路図

slotmachine_1nXzMvYVPH.fzzThis spreadsheet was used to prove that the payout table is correct. Sheet password is "password". slotpayouttablecalc_v1_1_SfcpHOBOvf.xlsx
Close Encounters Slot Machine
link to files on Fritzing.orgSchematics on Fritzing.org The Fritzing Schematic

製造プロセス

  1. EEGマシン
  2. 自動販売機
  3. 投票機
  4. 両替機
  5. EKGマシン
  6. ミシン
  7. CNC工作機械
  8. 旋盤の部品
  9. 旋盤を理解する
  10. フライス盤の部品
  11. 機械を理解する