亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

ATmega 外星人主题老虎机

组件和用品

Microchip Technology ATmega328
准确的说是ATmega328P-PU。$3.00 SlotMachine 一台,I2C 信用LED 显示屏一台奴隶。
× 2
七段显示8位数
$1.20 显示玩家的信用余额。
× 1
8x8 矩阵,4 段,MAX7219
$3.78 模拟旋转卷轴并显示符号。仅使用了四个段中的三个。
× 1
I2C 2004 串行蓝色背光 LCD 模块 20 X 4 2004
$3.00 用于显示选项菜单。在 aliexpress 上货比三家。不用付运费!
× 1
面包板(通用)
830 点 $4.00
× 2
瞬时联系按钮
$1.00 for 50。一个控制旋转卷轴,三个用于导航菜单,两个用于接地引脚 1的 ATmegas。
× 6
RGB 扩散共阴极
用于表示各种事物。
× 1
LED(通用)
指示是否为电路板供电。
× 1
电阻 10k ohm
4 个用于拉起每个按钮,2 个用于 ATmegas 的引脚 1。
× 6
电阻 1k ohm
在每个按钮和 ATmega 输入引脚之间。
× 4
电阻 330 ohm
用于RGB LED的红绿蓝引线。
× 3
16 MHz 晶振
一个用于SlotMachine的ATmega328P-PU,一个用于LED显示从机的ATmega328P-PU。两者都以 16MHz 运行。
× 2
滑动开关
用于电源。
× 1
蜂鸣器
需要两个,一个用于SlotMachine芯片,一个用于显示从芯片。最好修改电路,以便其中只有一个是必要的,并且可以由两个微控制器共享。
× 2
电容 22 pF
× 4
0.10 uF 电容
× 6
电容 100 nF
这是可选的,仅当您使用 Arduino Mini USB 串行适配器对 SlotMachine 进行编程时才需要芯片,就像我一样。
× 1
电容 10 µF
帮助平滑电源电压。
× 2
线性调节器 (7805)
调节电源电压,5V。
× 1
跳线(通用)
你需要很多这样的东西。大多数情况下,我自己制作,但我也使用跳线。
× 1
5v 电源
× 1
Arduino Mini USB 串行适配器
$13.20 这是可选的,您可以使用 Arduino Uno 对 ATmega 328p-pu 芯片进行编程。
× 1
FTDI USB 转 TTL 串行适配器
$1.66 x 2 =$3.32 用于对 ATmega328P-PU 进行适当的编程。原理图中没有描述。
× 1
可焊面包板
一个全尺寸的可焊接面包板。
× 1
SparkFun 可焊面包板 - 迷你
× 1
袖珍焊锡 - 60/40 松香芯 0.031" 直径
× 1
透明塑料防水电子工程箱
$13.00 这是外壳。
× 1

必要的工具和机器

烙铁(通用)
伸出援手

应用和在线服务

Arduino IDE
定时器免费音色库
LED 控制库
LiquidCrystal/LCD 库
LiquidCrystal I2C 库

关于这个项目

ATmega外星人主题老虎机

<人物>

这个项目是我使用两个 ATmega328P-PU 微控制器实现的外星人主题老虎机。我的灵感来自 Cory Potter 的 Alien Invasion Slot Machine,我想扩展这个想法。老虎机仅用于娱乐和教育目的。我尽我最大的努力让游戏尽可能模拟真实的老虎机。该项目目前处于起步阶段。一旦零件从中国运来,我就会添加一个外壳,我有机会把所有东西都焊接起来。这个项目花了我大约两个月的时间来构建。对我来说,构建过程中最困难的部分是理解让游戏按照赌场行业期望的简单老虎机在大约 5 亿次模拟后表现的方式所涉及的所有数学运算。

<人物>

游戏如何运作

该游戏具有三个卷轴,每个卷轴上出现相同的唯一 25 个符号(未使用具有 4 个 8x8 矩阵的组件上的 8x8 矩阵之一。)有五种不同的获胜方式。如果你得到三艘宇宙飞船,你就会赢得头奖。如果你得到一两艘宇宙飞船,你也会赢得一些积分。如果您获得两个或三个匹配的符号,您也将获胜。如果您获得一艘宇宙飞船和两个匹配的符号,如下图所示,游戏将根据最低概率/最高支出的获胜事件进行支出;换句话说,获胜的事件是相互排斥的,您不能在转轴的一次旋转中以两种不同的方式获胜。这使编程更简单一些。对我来说还有很多其他挑战。

<人物>

特点

老虎机有几个有趣的功能,可以通过 20 x 4 I2C 液晶显示器使用两个导航按钮和一个选择按钮访问。这些按钮使用了一种相当复杂的去抖动算法,该算法利用了微控制器的外部中断功能。这是主菜单。

<人物>

<人物>

由于菜单中有六行,您必须使用“向下导航”按钮向下滚动才能查看整个菜单。有一个专门用于“旋转”卷轴的按钮。除此之外,您还可以从主菜单中选择“播放”。您可以随时更改赌注。

<人物>

最令人兴奋的功能是游戏可以在“自动”模式下进行;即您从 LCD 屏幕上的设置菜单中选择自动模式选项,游戏会一遍又一遍地播放,直到您再次选择该选项或已播放 100 万次。这是测试游戏的关键功能。您也可以在此处禁用声音。

<人物>

通过 LCD 上的菜单,还可以查看模拟生成的所有指标。如果您使用 USB 电缆通过 RX 和 TX 引脚将微控制器连接到监视器,这些指标也会输出并可在串行监视器中查看。显示的指标列表包括您的积分余额、您中奖的次数以及您通过任何其他方式赢得积分的次数。这使我能够根据各种支出运行模拟,并且对于建立和证明支出表很有用。支付表本身是不可配置的;一旦设置,它应该保持不变。我想可以通过使用波动率指数来驱动支付表来配置波动率指数,但这需要做更多的工作。

<人物>

<人物>

重置选项允许您将所有指标(EEprom 写入除外)重置为零。该芯片将工作大约 100, 000 次写入 EEprom。由于芯片上有 512k 的 EEprom 可用,而我们只使用其中的一小部分,因此当我们接近 100, 000 次写入时,实际上可以移动 EEprom 中度量的位置。我还没有实现这个功能,但这将是一种延长芯片寿命的方法。

最后,庄家(随着时间的推移)保留的每个赌注或每个赌注的百分比是可配置的。请记住,执行复位操作后,需要再次设置保持。

<人物>

玩家的信用余额始终以八位七段显示方式显示。

<人物>

数学

为了确保游戏的真实性,我们做了很多工作。计算了概率并设计了支付表,以便游戏具有可接受的波动率指数 (VI)。该指数衡量机器行为的可预测性。具有更高 VI 的机器更有可能让玩家(或房子)赚更多的钱。它比具有较低 VI 的机器更难预测。确实,具有不同 VI 的不同赌场(甚至同一赌场)中将存在相同的完全相同的游戏。 VI 通过操纵支付计划而改变。对于我们的游戏,以下是每种获胜的概率和支出。

<人物>

请注意,赔率(最右侧)和支出(最左侧)有很大不同。如果这个游戏被编程为使得赔率表匹配或密切关注赔率,那么它的 VI 将高得令人无法接受。保留按支付的百分比计算,是赌场/赌场保留的赌注的一部分。如前所述,您可以通过 LCD 菜单设置保持。请记住,不同的司法管辖区有不同的法规来管理该司法管辖区老虎机的最大持有量。典型的最大持有量为 15%。了解将保留设置为法律允许的最大值并不一定会使该机器产生的利润最大化,因为更高的保留可能会阻止玩家使用该机器。然而,我怀疑许多玩家忽略了通常隐藏在细则中的保留,并且机器的需求曲线相对垂直(意味着使用机器的成本,保留,在很大程度上被忽略了),并且机器产生的利润更多地取决于机器的位置或放置以及游戏本身的设计。但这只是猜测。我相信有一些精明的赌徒对保持敏感。

电子表格与代码一起提供,包含三个表格,用于证明游戏运行正常(第一张表格出现在上面)。构建电子表格的第一步是准确计算每种类型获胜的几率(计算概率列)。

三艘飞船

三艘飞船出现的概率是可能组合总数的倒数。获胜组合的数量为 1,超过可能组合的总数 15625。每个转轴上有 25 个独特的符号,因此概率为 1 / (25 x 25 x 25),即 0.000064。这使得赔率 1/probability - 1 等于 1 到 15624。我在这里学习了如何根据概率计算赔率。

三个符号匹配(宇宙飞船除外)

除宇宙飞船外的三个符号匹配的概率是 24(每个卷轴上唯一符号的数量减去宇宙飞船)除以可能的组合数。 24 是分子,因为匹配的三个符号有 24 种组合。 24/15625 =0.001536。这使得赔率约为 1 到 650.04。

两艘宇宙飞船

两艘宇宙飞船匹配的总共有 24 x 3 种组合。那是因为有多种方法可以使一艘宇宙飞船进行两次匹配。给出 X =宇宙飞船和 Y =任何其他符号,XXY、XYX 和 YXX。 Y 有 24 个可能的值。所以 24 X 3 / 15625 =0.004608。赔率是 1 比 216.01。

一艘宇宙飞船出现

对于每个卷轴,单个宇宙飞船可能有 24 x 24 种组合。

宇宙飞船可以出现在任何卷轴上,因此您需要将单个卷轴上的可用组合数乘以三个卷轴。所以概率是 24 x 24 x 3 / 15625 =0.110592。赔率是 1 到 8.04。

两个符号匹配

对于任何给定的两个符号,除了宇宙飞船,有 23 个(25 减去一艘宇宙飞船减去一个符号,使其成为三个符号匹配)x 3 个卷轴 x 24 个不是宇宙飞船的符号。概率为 (23 X 3 X 24)/15625 =0.105984。赔率是 1 到 8.44。

现在我有了每种获胜的概率,我可以使用电子表格以一种使波动率指数可接受(<~20)的方式设计支付表。为了了解如何做到这一点,我非常依赖这篇文章。我在第一个表的 House Income 列中输入值,使用反复试验的过程,直到 VI 低于 20 并且单元格 J10 中的总计尽可能接近零。使用这些值,我在 SlotMachine.ino 中相应地设置了 THREE_SPACESHIP_PAYOUT、THREE_SYMBOL_PAYOUT、TWO_SPACESHIP_PAYOUT、ONE_SPACESHIP_PAYOUT 和 TWO_SYMBOL_PAYOUT。然后,首先通过使用 0% 的保持,我运行了 1、000、001 次播放的五次模拟,并将指标菜单中的值输入到实际结果表(第三个表)中的相应行和列中。 <人物>

我观察到实际概率与计算概率密切跟踪,并且 Pct Diff Prob 列是合理的。我还将 House Pays 行中的值与“Understanding Potential Income”表(第二个表)的 1, 000, 000 行的 Income High 和 Income Low 列的值范围相匹配,并观察到来自实际结果表在收入高和收入低列指定的范围内。了解潜在收入表定义了具有 90% 置信区间的给定持有值的预期收入范围。在下面的示例中,hold 设置为 0,因此获胜的可能性与失败的可能性相匹配。如果您玩游戏 100 万次,则收入在 16, 432 和 - 16, 432 之间的可能性为 90%。

<人物>

在使用电子表格和程序并运行数百万次模拟后,我能够找出程序中的缺陷,解决电子表格中的缺陷,并定义支付表的值,使 VI <20。最后我改变了持有 15% 并运行另一组 5 次模拟,以验证游戏的收入是否符合预期,如果它在现实世界的情况下被投放。这是 15% 持有的收入表。

<人物>

以下是实际结果。

<人物>

如果您想真正了解设置支付值背后的所有数学知识,我鼓励您检查电子表格中的公式。如果您发现任何错误,请向我指出;我不是专业的数学家(或 C 程序员),因此适用标准免责声明。

代码

我不会逐行带您完成代码。它得到了广泛的评论,任何地方都没有什么棘手的事情。所以使用原力,阅读源代码。如果您不熟悉 ATmega386 上的寄存器操作,并且想了解更多关于如何在不依赖 Arduino 库的情况下为 AVR 微控制器编写代码,我鼓励您获取一份 Elliott William 的副本优秀的书,“Make:AVR 编程”。如果您碰巧订阅了 safaribooksonline.com,您会在那里找到它。否则,它可以在亚马逊上找到。在这些程序中,我在某些地方使用 Arduino 函数,而在其他地方我直接操作寄存器。很抱歉。

您可能会注意到的第一件事是该程序大量使用了全局变量。 Stack Overflow 上有一个关于这个主题的很好的讨论。我不会在这里提倡或捍卫全局变量的大量使用,但我会鼓励您了解有关该主题的所有观点,并认识到在单个程序员和有限资源的嵌入式应用程序项目中使用它们是一个强有力的论据.

我确实使用了一些库,否则这个项目对我来说是不可能的。 Timer Free Tone Library 用于通过无源压电扬声器驱动各种频率。在 SlotMachine.h 中,您会注意到有许多音符定义。你可以用它来组合你想要的任何旋律。当 SlotMachine 的微控制器启动并且设置功能运行时,我只使用其中的一小部分来播放“第三类近距离接触”的部分主题。我选择了计时器免费库,因为我认为我需要计时器来做某事,但最终我根本没有使用计时器。如果你需要它,它是可用的。 LED 控制库用于 SlotMachine.ino 和 slotCreditDisplaySlave.ino。在前者中,它用于控制用作老虎机卷轴的三个 8 x 8 LED 矩阵。在 slotCreditDisplaySlave.ino 中,该库便于访问显示玩家信用余额的 8 位七段显示器。这将是提及我试图避免使用另一个 AVR 芯片 (ATmega328) 只是为了提供信用余额的好时机,但我找不到一种方法来控制 8 x 8 矩阵和 8 位七段显示器单个微控制器。所以最后我不得不创建一个 I2C 从设备来达到这个目的。绝对可以使用更便宜的 AVR 来完成显示信用余额的工作,但为了使本文保持简单,我选择使用另一个 ATmega328P-PU 芯片。从好的方面来说,当您赢得大头奖时,积分会继续在积分显示奴隶上计数,而您可以继续并再次旋转。需要 LiquidCrystal/LCD 和 LiquidCrystal I2C 库以方便访问 20 行 x 4 行 LCD 显示器。如前所述,如果您手头只有 20 x 2 LCD,只需将 LCD_SCREEN_HEIGHT 的定义从 4 更改为 2,就可以替换它。请确保您为此项目获得的 LCD 显示器支持 I2C。如果不是,您需要为 LCD1602 适配器板购买一个 I2C SPI 串行接口板端口模块,部件号为 PCF8574,如下所示,并将其焊接到您的 LCD1602 显示器上。

<人物>

游戏可以同时处于多个不同的状态,machineState 变量跟踪这些状态。例如,它可以同时处于“旋转”和“自动模式”。我并没有在程序中大量使用这个概念;无论如何,不​​像我在其他程序中那样多。但是有一些基于状态的条件分支。还有事件的概念,事件是在ProcessEvents函数中调度和处理的。如果有事件队列可能会更好,但我没有走那么远。

SlotMachine.ino 的评论部分列出了已知缺陷和“待办事项”。有时,当您“旋转”卷轴(通过按下旋转按钮或从 LCD 菜单中选择“播放”选项)时,一个或两个卷轴不会移动。那是因为幕后的随机数生成器选择了已经为该卷轴显示的符号。这可以修复以使游戏看起来更逼真,但这并不是真正的缺陷。卷轴不会像大多数老虎机那样从左到右完成旋转。这是由设计完成的,以保持简单。通过在卷轴实际旋转之前按升序对每次旋转生成的三个随机数进行排序,可以让卷轴从左到右完成旋转,我没有打扰。

至于“待办事项”,我想在某个时候添加掉电保护和看门狗保护,只是为了通过练习并学习如何去做。请注意,分配给全局变量的空间的 80% 已被消耗。这是 ATmega386 和 Arduino 程序开始变得不稳定的时候。我们就在那个时候使用这个程序。我不得不做一些预算以保持工作正常,我不建议向程序添加更多全局变量。这将使向菜单的设置部分添加更多功能变得困难,例如,因为菜单消耗了大量全局变量空间。我确实尝试通过将菜单移动到程序内存中来解决全局变量问题,但是我无法减少全局变量使用的空间,我认为是因为编译器无论如何都需要为菜单预先分配所有空间.可以做更多的工作来增加游戏的趣味性;我可以更多地使用 RGB LED 和压电蜂鸣器,多庆祝胜利,也许输钱时发出更好的声音,但我会把它留给任何想玩的人。

我必须为游戏设计所有符号。其中一些会让你想起经典的街机游戏“太空入侵者”,我可能是从某个地方借来的。其余的都是我手工设计的,其中一些看起来不太专业。我使用这个网站来帮助设计符号。如果您想调整符号​​,您可以在 SlotMachine.h 中进行调整,然后尽情发挥。它不会影响程序逻辑。对于符号,我以 2 进制/二进制表示数字,以便您可以使用文本编辑器设计它们。

代码可在 GitHub 上找到。

构建老虎机

我使用 FTDI USB 转串口板对两个 ATmega328P-PU 微控制器进行就地编程。 These connections are not depicted in the Fritzing schematic. For instructions on setting up the FTDI break out board on your solder-less breadboard follow this link. You may need to google around a bit to nail the setup. I believe this post also helped me troubleshoot an issue I was having trying to get the micro-controller to automatically reset at the start of programming via the FTDI breakout board. Remember to place a 100 nF capacitor in series with the connection between the ATmega328 reset pin (position 1/PC6/reset pin) and RTS on the FTDI break out board so that you don't have to hold down the reset button when you want to program the chip. If you elect to use your Arduino Uno to program the chips, instructions are found here. If you're just going to program the chips once with the supplied code it's probably quickest and easiest to just program them from the Arduino Uno.

Both mico-controllers are set up with the 'Arduino' chip (the ATmega328P-PU) on the breadboard. If you're planning on ultimately building this project by soldering the components together, or if you just want to copy what I've done here when you breadboard the project, you'll want to understand how to set up the Arduino on a breadboard. Follow the excellent instructions here for doing that. Those instructions include the procedure necessary to follow if you need to load the Arduino bootloader on the two chips, which you will most likely need to do if you purchase the chips from a supplier in China and/or via e-bay, as suggested here in the part's list. To do that you'll need an AVR programmer like the AVRISP mk II or the USBTiny ISP. You can also just use your Arduino, if you have one, to burn the bootloader. All of your options are explained when you follow the link above.

Parts

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.

Software

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

Summary

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.如果没有,请参阅 。 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.如果没有,请参阅 。 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. 脑电图机
  2. 自动售货机
  3. 投票机
  4. 更换机器
  5. 心电图机
  6. 缝纫机
  7. 数控机床
  8. 挤奶机
  9. 车床零件
  10. 了解车床
  11. 铣床的组成部分
  12. 了解机器