Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Caça-níqueis com tema ATmega Alien

Componentes e suprimentos

Tecnologia Microchip ATmega328
ATmega328P-PU, para ser mais preciso. $ 3,00 Um para o SlotMachine, um para o display LED de crédito I2C escravo.
× 2
Exibição de sete segmentos com 8 dígitos
$ 1,20 Para exibir o saldo de crédito do jogador.
× 1
matriz 8x8, 4 segmentos, MAX7219
$ 3,78 Para simular bobinas giratórias e exibir os símbolos. Apenas três dos quatro segmentos são usados.
× 1
Módulo LCD Serial Blue Backlight I2C 2004 20 X 4 2004
$ 3,00 Para exibir o menu de opções. Compre no AliExpress. Não pague pelo frete!
× 1
Breadboard (genérico)
830 pontos US $ 4,00
× 2
Botões de contato momentâneo
$ 1,00 por 50. Um controla o giro das bobinas, três para navegar no menu, dois para o pino de aterramento 1 do ATmegas.
× 6
Cátodo comum difuso RGB
Usado para sinalizar várias coisas.
× 1
LED (genérico)
Indica se a alimentação está sendo fornecida às placas.
× 1
Resistor 10k ohm
4 para puxar cada um dos botões, 2 para o pino 1 do ATmegas.
× 6
Resistor 1k ohm
Entre cada um dos botões e os pinos de entrada ATmega.
× 4
Resistor 330 ohm
Para os terminais vermelho, verde e azul do LED RGB.
× 3
Cristal 16 MHz
Um para ATmega328P-PU do SlotMachine e um para ATmega328P-PU do display de LED escravo. Ambos funcionam a 16 MHz.
× 2
Slide Switch
Para a fonte de alimentação.
× 1
Buzzer
Dois são necessários, um para o chip SlotMachine e um para o chip escravo do monitor. Seria bom modificar o circuito de forma que apenas um deles seja necessário e possa ser compartilhado por ambos os microcontroladores.
× 2
Capacitor 22 pF
× 4
0,10 uF Capacitor
× 6
Capacitor 100 nF
Isso é opcional e apenas necessário se você estiver usando o adaptador serial Arduino Mini USB para programar o SlotMachine chip, como eu.
× 1
Capacitor 10 µF
Para ajudar a suavizar a tensão de alimentação.
× 2
Regulador linear (7805)
Para regular o fornecimento de tensão, 5 V.
× 1
Fios de jumpers (genérico)
Você precisará de uma boa quantidade disso. Na maior parte, eu faço o meu, mas também uso os fios de jumper.
× 1
Uma fonte de alimentação 5v
× 1
Adaptador serial Arduino Mini USB
$ 13,20 Isso é opcional, você pode usar seu Arduino Uno para programar os chips ATmega 328p-pu.
× 1
Adaptador FTDI USB para TTL Serial
$ 1,66 x 2 =$ 3,32 Para programar ATmega328P-PUs no lugar. Não representado no esquema.
× 1
Tábua de ensaio capaz de soldar
Uma placa de ensaio soldável de tamanho normal.
× 1
Tábua de ensaio com solda SparkFun - Mini
× 1
Pocket Solder- 60/40 Rosin Core 0.031 "diâmetro
× 1
Compartimento de caixa de projeto eletrônico à prova de água de plástico transparente
US $ 13,00 Este é o gabinete.
× 1

Ferramentas e máquinas necessárias

Ferro de soldar (genérico)
Mãos que ajudam

Aplicativos e serviços online

Arduino IDE
Timer Free Tone Library
Biblioteca de controle de LED
LiquidCrystal / Biblioteca LCD
Biblioteca LiquidCrystal I2C

Sobre este projeto





Caça-níqueis com tema ATmega Alien




Este projeto é a minha implementação de uma máquina caça-níqueis com tema alienígena usando dois microcontroladores ATmega328P-PU. Eu fui inspirado pelo Alien Invasion Slot Machine de Cory Potter, e eu queria expandir essa ideia. A máquina caça-níqueis é apenas para fins educacionais e de entretenimento. Eu tentei o meu melhor para fazer o jogo simular um caça-níqueis real o mais próximo possível. O projeto está atualmente em andamento. Um gabinete será adicionado assim que as peças chegarem da China e eu tiver a chance de soldar tudo. O projeto levou cerca de dois meses para eu construir no meu tempo livre. A parte mais difícil da construção para mim foi entender toda a matemática envolvida em fazer o jogo se comportar da maneira que a indústria de cassinos esperaria que uma simples máquina de caça-níqueis se comportasse depois de meio bilhão de simulações.









Como o jogo funciona


O jogo tem três rolos com os mesmos 25 símbolos exclusivos aparecendo em cada rolo (uma das matrizes 8x8 no componente com 4 matrizes 8x8 não é usada). Existem cinco maneiras diferentes de ganhar. Se você conseguir três naves espaciais, você ganha o jackpot. Se você conseguir uma ou duas espaçonaves, também ganhará alguns créditos. Se você conseguir dois ou três símbolos iguais, você também ganha. Se você conseguir uma nave espacial e dois símbolos correspondentes, conforme ilustrado abaixo, o jogo será pago com base no evento vencedor com a menor probabilidade / maior pagamento; em outras palavras, os eventos vencedores são mutuamente exclusivos, você não pode ganhar de duas maneiras diferentes em uma única rodada dos rolos. Isso manteve a programação um pouco mais simples. Havia muitos outros desafios para mim.





Recursos


A máquina caça-níqueis tem vários recursos interessantes que são acessados ​​através do display LCD compatível com 20 x 4 I2C usando dois botões de navegação e um botão de seleção. Os botões usam um algoritmo de de-bouncing bastante sofisticado que aproveita a capacidade de interrupção externa do microcontrolador. Este é o menu principal.





Uma vez que existem seis linhas no menu, você deve rolar para baixo usando o botão 'navegar para baixo' para ver o menu inteiro. Existe um botão dedicado a 'girar' as bobinas. Além disso, você também pode selecionar 'Play' no menu principal. Você pode alterar sua aposta a qualquer momento.

O recurso mais interessante é que o jogo pode ser jogado no modo 'automático'; ou seja, você seleciona a opção de modo automático no menu de configurações na tela LCD e o jogo é reproduzido continuamente até que você selecione a opção novamente ou 1 milhão de jogadas tenham ocorrido. Esta é uma função crítica para testar o jogo. Você também pode desativar o som aqui.

Através do menu do LCD também é possível visualizar todas as métricas geradas a partir da simulação. Essas métricas também são emitidas e podem ser visualizadas no monitor serial se você conectar seu microcontrolador ao monitor por meio dos pinos RX e TX usando um cabo USB. A lista de métricas exibida inclui seu saldo de crédito, o número de vezes que você acertou o jackpot e o número de vezes que você ganhou créditos por qualquer outro meio. Isso me permitiu executar simulações com base nos vários pagamentos e foi útil para estabelecer e provar a tabela de pagamentos. A tabela de pagamentos em si não é configurável; uma vez definido, deve permanecer o mesmo. Suponho que seria possível tornar o índice de volatilidade configurável usando-o para conduzir as tabelas de pagamento, mas isso exigiria muito mais trabalho.



A opção Redefinir permite redefinir todas as métricas (exceto gravações EEprom), de volta a zero. O chip funcionará por cerca de 100.000 gravações no EEprom. Como há 512k de EEprom disponíveis no chip e estamos usando apenas uma fração disso, seria possível mover a localização das métricas em EEprom conforme nos aproximamos de 100.000 gravações. Não implementei esse recurso, mas seria um meio de estender a vida útil do chip.

Finalmente, a retenção, ou a porcentagem de cada aposta mantida pela casa (ao longo do tempo), é configurável. Lembre-se de que, após realizar uma operação de reinicialização, a retenção precisa ser configurada novamente.

O saldo de crédito do jogador é sempre mostrado em um display de oito dígitos e sete segmentos.





A matemática


Muito trabalho foi feito para garantir que o jogo fosse realista. As probabilidades foram calculadas e a tabela de pagamentos foi desenhada para que o jogo tivesse um Índice de Volatilidade (VI) aceitável. Este índice mede o quão previsível é o comportamento da máquina. Uma máquina com um VI maior tem mais probabilidade de gerar mais dinheiro para o jogador (ou para a casa). É menos previsível do que uma máquina com um VI inferior. É verdade que o mesmo jogo exacto existirá em casinos diferentes (ou mesmo no mesmo casino) com VIs ​​diferentes. O VI é alterado pela manipulação da programação de pagamento. Para o nosso jogo, aqui estão as probabilidades e os pagamentos para cada tipo de vitória.

Observe que as probabilidades (extrema direita) e o pagamento (extrema esquerda) são dramaticamente diferentes. Se este jogo foi programado de forma que a tabela de pagamentos corresponda ou acompanhe de perto as probabilidades, seu VI seria inaceitavelmente alto. A retenção é calculada como uma porcentagem do pagamento e é a parte de uma aposta mantida pela casa / cassino. Conforme declarado, você pode definir a retenção por meio do menu LCD. Lembre-se de que diferentes jurisdições têm diferentes regulamentos que regem a retenção máxima para caça-níqueis nessa jurisdição. Uma retenção máxima típica é de 15%. Entenda que definir a retenção para o máximo permitido por lei não necessariamente maximiza o lucro gerado por aquela máquina, porque uma retenção maior pode desencorajar os jogadores de usar a máquina. Suspeito, no entanto, que muitos jogadores ignoram o bloqueio, que normalmente é escondido em letras pequenas, e que a curva de demanda para uma máquina é relativamente vertical (o que significa que o custo de usar a máquina, o bloqueio, é amplamente ignorado), e que o lucro gerado pela máquina depende muito mais da localização ou colocação da máquina, bem como do design do jogo em si. Mas isso é apenas especulação. Tenho certeza de que existem alguns jogadores experientes que são sensíveis ao bloqueio.

A planilha, disponibilizada com o código, com três tabelas foi construída para comprovar que o jogo está funcionando corretamente (a primeira tabela aparece acima). A primeira etapa na construção da planilha foi calcular com precisão as chances de cada tipo de vitória (as colunas de probabilidade calculada).

Três naves espaciais

A probabilidade de que três espaçonaves apareçam é o inverso do número total de combinações possíveis. O número de combinações vencedoras, um, sobre o número total de combinações possíveis, 15625. Existem 25 símbolos únicos em cada rolo, então a probabilidade é 1 / (25 x 25 x 25), ou 0,000064. Isso faz com que as probabilidades, 1 / probabilidade - 1, sejam iguais a 1 a 15624. Aprendi como calcular as probabilidades a partir da probabilidade aqui.

Correspondência de três símbolos (exceto naves espaciais)

A probabilidade de que três símbolos, além das naves espaciais, correspondam é 24 (o número de símbolos únicos em cada bobina menos as naves espaciais) dividido pelo número de combinações possíveis. 24 é o numerador porque existem 24 combinações de três símbolos correspondentes. 24/15625 =0,001536. Isso torna as probabilidades de cerca de 1 a 650,04.

Duas naves espaciais

Existem 24 x 3 combinações totais de duas naves espaciais correspondentes. Isso porque existem três maneiras de fazer duas combinações de uma nave espacial. Dê X =nave espacial e Y =qualquer outro símbolo, XXY, XYX e YXX. Existem 24 valores possíveis para Y. Portanto, 24 X 3/15625 =0,004608. As chances são de 1 a 216,01.

Aparece uma nave espacial

Para cada bobina, existem 24 x 24 combinações possíveis para o aparecimento de uma única nave espacial.

Uma nave espacial pode aparecer em qualquer bobina, então você precisa multiplicar o número de combinações disponíveis em uma única bobina por três bobinas. Portanto, a probabilidade é 24 x 24 x 3/15625 =0,110592. As probabilidades são de 1 a 8,04.

Correspondência de dois símbolos

Para quaisquer dois símbolos dados, exceto as naves espaciais, há 23 (25 menos uma nave menos um símbolo que faria uma combinação de três símbolos) x 3 rolos x 24 símbolos que não são naves espaciais. A probabilidade é (23 X 3 X 24) / 15625 =0,105984. As probabilidades são de 1 a 8,44.

Agora que tenho as probabilidades para cada tipo de vitória, posso usar a planilha para projetar a tabela de pagamentos de uma forma que torne o índice de volatilidade aceitável (<~ 20). Para entender como fazer isso, confiei muito neste post. Entrei os valores na coluna Renda da casa da primeira tabela, usando um processo de tentativa e erro, até que o VI fosse inferior a 20 e o Total na célula J10 fosse o mais próximo de zero que eu pudesse obter. Usando esses valores, configurei THREE_SPACESHIP_PAYOUT, THREE_SYMBOL_PAYOUT, TWO_SPACESHIP_PAYOUT, ONE_SPACESHIP_PAYOUT e TWO_SYMBOL_PAYOUT em SlotMachine.ino de acordo. Em seguida, primeiro usando uma retenção de zero por cento, executei cinco simulações de 1.000.000, 001 execuções e inseri os valores do menu de métricas nas linhas e colunas apropriadas na tabela Resultados reais (a terceira tabela).

Observei que as probabilidades reais eram acompanhadas de perto com as probabilidades calculadas e que a coluna Pct Diff Prob era razoável. Eu também comparei os valores na linha do House Pays com o intervalo de valores das colunas Income High e Income Low da linha 1, 000, 000 da tabela Understanding Potential Income (a segunda tabela), e observei que os valores de a tabela Resultados reais estavam dentro do intervalo especificado pelas colunas Renda alta e Renda baixa. A tabela Compreendendo a receita potencial define a faixa esperada de receita para um determinado valor de retenção com um intervalo de confiança de 90%. No exemplo abaixo, a espera é definida como 0, portanto, a probabilidade de vitória corresponde à probabilidade de perda. Se você jogar o jogo 1 milhão de vezes, há 90% de probabilidade de que a receita seja entre 16, 432 e - 16, 432.

Depois de trabalhar com a planilha e o programa e rodar milhões de simulações, consegui descobrir os defeitos do programa, resolver os defeitos na planilha e definir valores para a tabela de pagamentos que mantinha o VI <20. Finalmente mudei a retenção para 15% e rodou outro conjunto de 5 simulações para verificar se a receita do jogo está de acordo com as expectativas se fosse aplicada em uma situação do mundo real. Aqui está a tabela de receita para uma retenção de 15%.

E aqui estão os resultados reais.

Se você quiser realmente entender toda a matemática por trás da definição dos valores de pagamento, eu o encorajo a examinar as fórmulas da planilha. Se você encontrar algum erro, por favor, indique-o para mim; Eu não sou um matemático (ou um programador C) por profissão, então a isenção de responsabilidade padrão se aplica.





O Código


Não irei mostrar o código linha por linha. É amplamente comentado e não há nada complicado acontecendo em qualquer lugar. Portanto, use a Força, leia a fonte. Se você não está familiarizado com a manipulação de registros no ATmega386 e gostaria de entender mais sobre como escrever código para o microcontrolador AVR sem depender da biblioteca Arduino, encorajo você a obter uma cópia do livro de Elliott William excelente livro, "Make:AVR Programming". Se por acaso você tiver uma assinatura do safaribooksonline.com, você a encontrará lá. Caso contrário, está disponível aqui na Amazon. Nesses programas, uso as funções do Arduino em alguns lugares e, em outros, manipulo os registros diretamente. Desculpe por isso.

A primeira coisa que você notará é que o programa faz uso extensivo de variáveis ​​globais. Há uma boa discussão sobre esse tópico no Stack Overflow. Não vou promover ou defender o uso pesado de variáveis ​​globais aqui, mas gostaria de encorajá-lo a entender todas as perspectivas sobre o assunto e reconhecer que há um forte argumento para usá-las em um projeto de aplicativo incorporado com um único programador e recursos limitados .

Faço uso de algumas bibliotecas, sem as quais este projeto teria sido impossível para mim. A Timer Free Tone Library é usada para conduzir várias frequências através do alto-falante piezoelétrico passivo. Em SlotMachine.h, você notará que há uma série de definições para notas musicais. Você pode usar isso para montar qualquer melodia que desejar. Eu só uso um punhado deles para tocar parte do tema de "Contatos Imediatos do Terceiro Tipo" quando o microcontrolador do SlotMachine é iniciado e a função de configuração é executada. Selecionei a biblioteca livre de cronômetro porque pensei que precisaria do cronômetro para algo, mas acabei não usando o cronômetro. Está disponível se você precisar. A biblioteca de controle de LED é usada em SlotMachine.ino e slotCreditDisplaySlave.ino. No primeiro, é usado para controlar as três matrizes de LED 8 x 8 que funcionam como bobinas das slot machines. Em slotCreditDisplaySlave.ino, a biblioteca facilita o acesso ao display de 8 dígitos e sete segmentos que exibe o saldo de crédito do jogador. Este seria um bom momento para mencionar que tentei evitar o uso de outro chip AVR (ATmega328) apenas para atender o saldo de crédito, mas não consegui encontrar uma maneira de controlar as matrizes 8 x 8 e o display de 8 dígitos e sete segmentos do um único microcontrolador. Então, no final, tive que criar um escravo I2C para servir a esse propósito. Definitivamente, você poderia usar um AVR mais barato para fazer o trabalho de exibir o saldo de crédito, mas para manter as coisas simples neste artigo, optei por usar outro chip ATmega328P-PU. Pelo lado bom, quando você ganha um grande jackpot, os créditos continuam a contar no escravo de exibição de crédito enquanto você pode ir em frente e girar novamente. As bibliotecas LiquidCrystal / LCD e LiquidCrystal I2C são necessárias para facilitar o acesso ao display LCD de 20 linhas x 4 linhas. Como mencionado, você pode substituir um LCD 20 x 2 se isso for tudo o que você tiver em mãos, apenas alterando a definição de LCD_SCREEN_HEIGHT de 4 para 2. Certifique-se de que o visor LCD que você adquiriu para este projeto é compatível com I2C. Se não for, você precisará adquirir um módulo de porta da placa de interface serial I2C SPI para a placa adaptadora LCD1602, número da peça PCF8574, ilustrado abaixo, e soldá-lo ao monitor LCD1602.

O jogo pode estar em vários estados diferentes ao mesmo tempo, e a variável machineState rastreia os estados. Por exemplo, pode estar 'girando' e em 'modo automático' ao mesmo tempo. Eu realmente não uso muito esse conceito dentro do programa; não tanto quanto eu fiz em outros programas, de qualquer maneira. Mas há alguma ramificação condicional com base no estado. Também existe o conceito de eventos, e os eventos são despachados e manipulados na função ProcessEvents. Provavelmente seria melhor se houvesse uma fila de eventos, mas não fui tão longe.

Há uma lista de defeitos conhecidos e tarefas pendentes na seção de comentários do SlotMachine.ino. Às vezes, quando você 'gira' os rolos (pressionando o botão de rotação ou selecionando a opção 'Jogar' no menu LCD), um ou mesmo dois dos rolos não se movem. Isso ocorre porque o gerador de números aleatórios nos bastidores escolheu o símbolo que já está sendo exibido para aquela bobina. Isso poderia ser consertado para tornar o jogo mais realista, mas não é realmente um defeito. As bobinas não terminam de girar da esquerda para a direita, como acontece na maioria das máquinas caça-níqueis. Isso é feito por design, para manter as coisas simples. Seria possível fazer com que as bobinas terminassem de girar da esquerda para a direita, classificando os três números aleatórios que são gerados para cada giro em ordem crescente antes que as bobinas realmente girassem, e eu não me incomodei.

Quanto a 'todos', eu gostaria em algum momento de adicionar proteção contra brown out e proteção de cão de guarda, apenas para fazer o exercício e aprender como fazê-lo. Observe que 80% do espaço alocado para variáveis ​​globais já foi consumido. Este é o ponto em que as coisas podem começar a se tornar instáveis ​​com os programas ATmega386 e Arduino. Estamos nesse ponto com este programa. Tive que fazer um orçamento para manter as coisas funcionando e não recomendo adicionar mais nenhum global ao programa. Isso tornaria difícil adicionar mais funcionalidade à parte Configurações do menu, por exemplo, porque o menu consome muito espaço de variável global. Eu tentei resolver o problema da variável global movendo os menus para a memória do programa, mas não consegui fazer isso para reduzir o espaço usado pelos globais, acho que porque o compilador precisa pré-alocar todo o espaço para os menus de qualquer maneira . Mais trabalho poderia ser feito para apimentar um pouco o jogo; Eu poderia usar mais o LED RGB e a campainha piezo, festejar um pouco mais uma vitória, talvez fazer um som melhor quando se perde dinheiro, mas deixo isso para quem quiser brincar com ele.

Tive que desenhar todos os símbolos do jogo. Alguns deles vão lembrá-lo do clássico jogo de arcade 'Space Invaders', e posso tê-los emprestado de algum lugar. O resto eu desenhei à mão, e alguns deles não têm aparência profissional. Usei este site para ajudar a projetar os símbolos. Se você quiser ajustar os símbolos, pode fazer isso em SlotMachine.h e brincar com eles o quanto quiser. Isso não afetará a lógica do programa. Para os símbolos, represento os números na base 2 / binário para que você possa projetá-los com seu editor de texto.

O código está disponível aqui no GitHub.





Construindo o caça-níqueis


Usei um FTDI USB para placa serial para programar os dois microcontroladores ATmega328P-PU no local. Essas conexões não são representadas no esquema de Fritzing. Para obter instruções sobre como configurar a placa break out FTDI em sua placa de ensaio sem solda, siga este link. Você pode precisar pesquisar um pouco no Google para acertar a configuração. Acredito que esta postagem também me ajudou a solucionar um problema que estava tendo ao tentar fazer o microcontrolador reiniciar automaticamente no início da programação por meio da placa de breakout FTDI. Lembre-se de colocar um capacitor de 100 nF em série com a conexão entre o pino de reinicialização ATmega328 (posição 1 / PC6 / pino de reinicialização) e RTS na placa de ruptura FTDI para que você não tenha que segurar o botão de reinicialização quando quiser para programar o chip. Se você optar por usar seu Arduino Uno para programar os chips, as instruções podem ser encontradas aqui. Se você pretende programar os chips apenas uma vez com o código fornecido, provavelmente é mais rápido e fácil programá-los apenas no Arduino Uno.

Ambos os mico-controladores são configurados com o chip 'Arduino' (o ATmega328P-PU) na placa de ensaio. 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

  • Ferro de soldar
  • Helping Hands





Esquemático


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





Resumo


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.

Código

  • 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 Tw o 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 see 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 r ate for the Serial monitor #define NUMFRAMES 25 // Number of symbols in each "reel" or "slot". 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 DDC 2 // 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 B ET_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#define 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 < 

Esquemas

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

Processo de manufatura

  1. Máquina EEG
  2. Máquina de venda automática
  3. Máquina de votação
  4. Alterar máquina
  5. Máquina EKG
  6. Máquina de Costura
  7. Partes da máquina de torno
  8. Entendendo o torno mecânico
  9. Componente da fresadora
  10. Entendendo a Máquina