| Weitere Artikel aus dem Elo-Magazin |
Ping-Pong Wettbewerb
Würfelspiel 36y13 auf der Pong Pong Platine von Franzis
Das Würfelspiel 36 wurde hier elektronisch zur Verwendung auf der Ping-Pong-Platine umgesetzt. 2 Spieler spielen gegeneinander und müssen versuchen, durch mehrfaches Würfeln mit einem Würfel möglichst dicht an die Summe von 36 zu kommen. Diese Summe darf jedoch nicht überschritten werden.
von Michael Gaus
Zwei Spieler spielen gegeneinander, es gibt einen Würfel im Spiel.
Spieler 1 beginnt zu würfeln und kann vor jedem Wurf entscheiden, ob er nochmals würfeln möchte oder nicht. Die Würfelergebnisse werden aufsummiert. Ziel ist es, möglichst dicht an die Summe von 36 zu kommen, jedoch darf diese Summe nicht überschritten werden. Nachdem Spieler 1 entschieden hat, nicht mehr weiterzuwürfeln oder aber die Summe von 36 überschritten hat, ist Spieler 2 an der Reihe. Nachdem auch Spieler 2 aufgehört hat zu würfeln oder die Summe von 36 überschritten hat, werden die Würfelergebnisse verglichen. Derjenige, der dichter an 36 dran ist, jedoch nicht darüber, bekommt einen Punkt.
Im zweiten Durchgang beginnt nun Spieler 2 zuerst zu würfeln. Bei jedem Durchgang wechseln sich die beginnenden Spieler ab. Wer zuerst 5 Punkte erzielt hat ist der Sieger des Spiels.
Ganzen Artikel lesen...

Zusätzlich benötigte Hardware:Ein zusätzlicher Taster (1-poliger Schließer), der zwischen PortD.3 (also Lötpad D3) und GND angeschlossen wird. Der benötigte Pullup-Widerstand wird im Controller intern hinzugeschaltet.
Durch Einwurf einer Münze wird das Würfelspiel 36 gestartet. Im Display erscheint kurz ein Startbildschirm. Anschließend erscheint ein blinkender Pfeil links, der symbolisiert, dass Spieler 1 an der Reihe ist. Durch einen Tastendruck bestätigt Spieler 1. Jetzt wird im Display oben links die aktuelle Würfelsumme angezeigt. Mit dem rechten Poti kann ausgewählt werden, ob er würfeln und somit die Summe erhöhen möchte (Symbol "+" links unten im Display) oder aber stattdessen die Summe so stehen lassen möchte (Pfeil rechts unten im Display). Die je nach Poti-Stellung aktivierte Auswahl wird blinkend dargestellt. Durch einen Tastendruck wird die Auswahl bestätigt. Falls "würfeln" ausgewählt wurde, so startet der Würfelvorgang, oben rechts im Display wird ein Würfel eingeblendet. Durch einen weiteren Tastendruck wird der Würfelvorgang gestoppt, das Würfelergebnis angezeigt und zur Summe hinzuaddiert. Dies wiederholt sich solange, bis der Spieler durch Anwahl des Pfeils entschieden hat, nicht mehr weiterzuwürfeln. Falls die Summe von 36 überschritten wurde, ist ein weiteres Würfeln nicht mehr möglich.
Nun ist der andere Spieler an der Reihe, was wiederum durch einen blinkenden Pfeil rechts im Display signalisiert wird. Der Spieler würfelt nun ebenfalls. Nachdem er das Würfeln beendet hat, werden die beiden Würfelsummen der Spieler angezeigt. Derjenige mit der höheren Summe, jedoch höchstens 36, erhält einen Punkt. Durch einen Tastendruck wird die nächste Runde gestartet. Der blinkende Pfeil rechts oder links signalisert, welcher Spieler die jeweilige Runde beginnt. Sobald einer der Spieler 5 Punkte erzielt hat, ist das Spiel beendet. Es wird das Gesamtergebnis angezeigt, wobei die Punktzahl des Gewinners blinkt.
Durch einen weiteren Tastendruck wird der Atmega8 in den stromsparenden Standbymodus versetzt. Durch einen erneuten Münzeinwurf kann das Spiel erneut gestartet werden.
Der Code für den ATmega8 auf der Ping Pong Platine wurde mit dem C-Compiler CodeVision AVR (Version 2.04.6 Evaluation) erstellt. Diese Evaluation-Version kann für den privaten nicht-kommerziellen Gebrauch kostenlos verwendet werden und ist auf eine Codegröße von 3 kB beschränkt, was für diese Anwendung gerade noch ausreicht. Das komplette Projekt ist in der ZIP-Datei enthalten (Projektdatei für CodeVison AVR ist 36.prj).
Download: Projektdateien und Hexfile
Quellen/Links:
C-Compiler CodeVision AVR: http://www.hpinfotech.ro/html/download.htm
/*****************************************************
Compiler : CodeVisionAVR 2.04.6 Evaluation
Chip type : ATmega8
Clock frequency : 8 MHz (int. RC-OSC)
*****************************************************/
//***************************************************
// Würfelspiel 36
// auf Basis des Franzis-Pingpong
// http://www.elo-web.de/ping-pong-start
//***************************************************
#include <mega8.h>
#include <stdio.h>
#include <delay.h>
#include <sleep.h>
#include <stdlib.h>
#define P_CLK PORTB.3
#define P_DATA PORTB.4
#define P_STROBE PORTB.2
#define PIN_COIN PIND.2
#define PULLUP_COIN PORTD.2
#define DIR_COIN DDRD.2
#define COIN_INSERTED (PIN_COIN == 0)
#define PIN_KEY PIND.3
#define PULLUP_KEY PORTD.3
#define KEY_PRESSED (PIN_KEY == 0)
#define WIDTH 12 // number of fields in horizontal direction
#define HEIGHT 10 // number of fields in vertical direction
unsigned int leds[WIDTH]; // current state of each LED (organized in columns)
unsigned int ledsBlink[WIDTH]; // current blink state of each LED (organized in columns)
unsigned char cPlayerScore[2]; // score for each player
unsigned char cDiceSum[2]; // dice sum for each player
unsigned char cPlayer; // current player (0/1)
bit bGameOver; // 1=game over
flash unsigned char dicefont[6*3] =
{ // font for dices
0x00, 0x02, 0x00, // 1
0x01, 0x00, 0x04, // 2
0x01, 0x02, 0x04, // 3
0x05, 0x00, 0x05, // 4
0x05, 0x02, 0x05, // 5
0x07, 0x00, 0x07 // 6
};
flash unsigned char decimals[] =
{ // Font for decimal values
0x1F, 0x11, 0x1F, // 0
0x04, 0x02, 0x1F, // 1
0x1D, 0x15, 0x17, // 2
0x15, 0x15, 0x1F, // 3
0x07, 0x04, 0x1F, // 4
0x17, 0x15, 0x1D, // 5
0x1F, 0x15, 0x1D, // 6
0x01, 0x01, 0x1F, // 7
0x1F, 0x15, 0x1F, // 8
0x17, 0x15, 0x1F // 9
};
// clear the whole screen, all LEDs off
void clearScreen(void)
{
unsigned char i;
for(i = 0; i < (WIDTH); i++)
{
leds[i] = 0;
}
}
// wait until key is pressed
void waitUntilKeypressed(void)
{
while(!KEY_PRESSED);
delay_ms(20);
}
// wait until key is released
void waitUntilKeyreleased(void)
{
while(KEY_PRESSED);
delay_ms(20);
}
// check if key is pressed
// return: 0=key not pressed, 1=key pressed
unsigned char keyPressed(void)
{
unsigned char result = 0;
if(KEY_PRESSED)
result = 1;
delay_ms(20);
return result;
}
// Timer 2 overflow interrupt service routine
// multiplexing of LEDs
// approx. every 1ms
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
static unsigned char count = 0;
unsigned char cValue, cValue2;
static unsigned char cBlink = 0x00;
static unsigned char cBlinkcnt = 0;
cBlinkcnt++;
if(cBlinkcnt >= 250)
{
cBlinkcnt = 0;
cBlink = ~cBlink;
}
count++;
if(count >= 12)
{
count = 0;
P_DATA = 0;
}
else
{
P_DATA = 1;
}
P_CLK = 1;
P_CLK = 0;
PORTC &= (~0x0F);
PORTD &= (~0xF0);
PORTB &= (~0x03);
P_STROBE = 1;
P_STROBE = 0;
cValue = (unsigned char)leds[count] & 0x0F;
cValue2 = (unsigned char)ledsBlink[count] & cBlink;
cValue &= (~cValue2);
PORTC |= cValue;
cValue = (unsigned char)leds[count] & 0xF0;
cValue &= (~cValue2);
PORTD |= cValue;
cValue = (unsigned char)(leds[count]>>8) & 0x03;
cValue2 = (unsigned char)(ledsBlink[count]>>8) & cBlink;
cValue &= (~cValue2);
PORTB |= cValue;
}
// initialization of Timer0 and Timer2
void initTimers(void)
{
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 250,000 kHz
// Mode: Normal top=FFh
// OC2 output: Disconnected
//ASSR=0x00;
TCCR2=0x03;
//TCNT2=0x00;
//OCR2=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
TCCR0=0x01;
//TCNT0=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;
}
// set controller in Powerdown mode
void setStandbyMode(void)
{
TCCR2 &= 0xF8; //stop Timer2
PORTC = 0;
PORTD = 0;
PORTB = 0;
ADCSRA &= 0x7F; // stopADC
DDRD.2 = 0;
PORTD.2 = 1;
GICR |= 0x40; //enable INT0
sleep_enable();
powerdown();
GICR &= (~0x40); //disable INT0
PULLUP_KEY = 1;
DDRD.2 = 1;
PORTD.2 = 0;
ADCSRA |= 0x80; //startADC
TCCR2 |= 0x03; //start Timer2
}
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
}
// initialization of INT0
void initInt0(void)
{
// External Interrupt(s) initialization
// INT0: disabled
// INT0 Mode: Low level
GICR &= (~0x40); //disable INT0
MCUCR &= 0xFC;
GIFR=0x40;
}
// initialization of ports
void init(void)
{
PORTB = 0;
DDRB = 0x1F;
PORTC = 0;
DDRC = 0x0F;
PORTD = 0;
DDRD = 0xF4;
PULLUP_KEY = 1;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
}
#define ADC_VREF_TYPE 0x00
// initialization of ADC
void initADC(void)
{
// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AREF pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x86;
}
// Read the AD conversion result
// adc_input: ADC channel (0..7)
// return: ADC value (0..1023)
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
// select next action
// return: selected action (0=roll the dice again, 1=keep dice sum)
unsigned char select(void)
{
unsigned char x;
x = 1 - (read_adc(7) / (1023/2 + 1));
return(x);
}
// switch on blinking for all LEDs
void blinkOn(void)
{
unsigned char i;
for(i = 0; i < 12; i++)
{
ledsBlink[i] = 0xFFFF;
}
}
// switch off blinking for all LEDs
void blinkOff(void)
{
unsigned char i;
for(i = 0; i < 12; i++)
{
ledsBlink[i] = 0x0000;
}
}
// show logo for player1
void showLogoPlayer1(void)
{
leds[0] = 0x020;
leds[1] = 0x070;
leds[2] = 0x0F8;
}
// show logo for player2
void showLogoPlayer2(void)
{
leds[11] = 0x020;
leds[10] = 0x070;
leds[9] = 0x0F8;
}
// show the symbol for rolling the dice
// blink: 1=symbol is blinking
void showSymbolRollDice(unsigned char blink)
{
unsigned char i;
leds[1] |= 0x0100;
leds[2] |= 0x0380;
leds[3] |= 0x0100;
for(i = 1; i <= 3; i++)
{
if(blink)
{
ledsBlink[i] |= 0x0380;
}
else
{
ledsBlink[i] &= (~0x0380);
}
}
}
// show the symbol for keeping the dice sum
// blink: 1=symbol is blinking
void showSymbolKeepSum(unsigned char blink)
{
unsigned char i;
leds[8] |= 0x0100;
leds[9] |= 0x0100;
leds[10] |= 0x0380;
leds[11] |= 0x0100;
for(i = 8; i <= 11; i++)
{
if(blink)
{
ledsBlink[i] |= 0x0380;
}
else
{
ledsBlink[i] &= (~0x0380);
}
}
}
// show a dice on display
// number: value of dice (1...6)
// row: row for start on display
// col: column for start on display
void showDice(unsigned char dice, unsigned char row, unsigned char col)
{
unsigned char i;
unsigned int localLeds[12];
for(i = 0; i < 12; i++)
{
localLeds[i] = leds[i];
}
for(i = 0; i < 3; i++)
{
localLeds[col] &= (~((unsigned int)0x7 << row));
localLeds[col] |= (unsigned int)dicefont[(dice - 1)*3 + i] << row;
col++;
}
for(i = 0; i < 12; i++)
leds[i] = localLeds[i];
}
// roll the dice
// return: dice value (1..6)
unsigned char rollDice(void)
{
unsigned char dice;
do
{
dice = (rand() % 6) + 1;
srand(TCNT0); //initialize random generator
showDice(dice, 1, 9);
}
while(!keyPressed());
waitUntilKeyreleased();
return(dice);
}
// show a decimal value with 2 digits on display
// d: value to be displayed (0...99)
// row: row on display
// col: column on display
void showDecimal(unsigned char d, unsigned char row, unsigned char col)
{
unsigned char j, k, value, divisor;
unsigned int ledsLocal[12];
for(j = 0; j < 12; j++)
ledsLocal[j] = leds[j];
divisor = 10;
for(k = 0; k < 2; k++)
{
value = d / divisor;
for(j = 0; j < 3; j++)
{ // show decimal using stored font
ledsLocal[col] &= (~((unsigned int)0x1F << row));
ledsLocal[col] |= ((unsigned int)decimals[value*3 + j] << row);
col++;
}
col++;
d = d % divisor;
divisor = divisor / 10;
}
for(j = 0; j < 12; j++)
leds[j] = ledsLocal[j];
}
// show a decimal value with 1 digit on display
// d: value to be displayed (0...9)
// row: row on display
// col: column on display
// blink: 1=blinking
void showDecimal1(unsigned char d, unsigned char row, unsigned char col, unsigned char blink)
{
unsigned char j, value;
value = d % 10;
for(j = 0; j < 3; j++)
{ // show decimal using stored font
leds[col] = ((unsigned int)decimals[value*3 + j] << row);
if(blink)
ledsBlink[col] |= ((unsigned int)0x1F << row);
col++;
}
}
// show startlogo logo on LED display
void showStartLogo(void)
{
leds[0] = 0;
leds[1] = 0;
leds[2] = 149;
leds[3] = 277;
leds[4] = 543;
leds[5] = 0;
leds[6] = 927;
leds[7] = 21;
leds[8] = 925;
leds[9] = 0;
leds[10] = 0;
leds[11] = 0;
}
// show total score of both players
void showTotalScore(void)
{
bit blink1 = 0, blink2 = 0;
clearScreen();
if(cPlayerScore[0] > cPlayerScore[1])
blink1 = 1;
else if(cPlayerScore[1] > cPlayerScore[0])
blink2 = 1;
showDecimal1(cPlayerScore[0], 2, 1, blink1);
showDecimal1(cPlayerScore[1], 2, 8, blink2);
}
// main routine
void main(void)
{
unsigned char i, x, dice;
bit blink1, blink2, bNextDice;
init();
initTimers();
initADC();
initInt0();
#asm("sei") // Global enable interrupts
while(1)
{
clearScreen();
showStartLogo();
delay_ms(2000);
clearScreen();
srand(TCNT0); //initialize random generator
cPlayerScore[0] = 0;
cPlayerScore[1] = 0;
cPlayer = 0;
bGameOver = 0;
do
{
cDiceSum[0] = 0;
cDiceSum[1] = 0;
for(i = 0; i < 2; i++)
{
clearScreen();
blinkOn();
if(cPlayer == 0)
showLogoPlayer1();
else
showLogoPlayer2();
waitUntilKeypressed();
waitUntilKeyreleased();
blinkOff();
clearScreen();
do
{
do
{
x = select();
if(x == 0)
blink1 = 1;
else
blink1 = 0;
if(x == 1)
blink2 = 1;
else
blink2 = 0;
showDecimal(cDiceSum[cPlayer], 0, 0);
showSymbolRollDice(blink1);
showSymbolKeepSum(blink2);
}
while(!keyPressed());
waitUntilKeyreleased();
showSymbolRollDice(0);
showSymbolKeepSum(0);
if(x == 0)
{
bNextDice = 1;
dice = rollDice();
cDiceSum[cPlayer] += dice;
if(cDiceSum[cPlayer] > 36)
bNextDice = 0;
}
else
{
bNextDice = 0;
}
}
while(bNextDice);
if(cDiceSum[cPlayer] > 36)
{
showDecimal(cDiceSum[cPlayer], 0, 0);
showSymbolKeepSum(1);
waitUntilKeypressed();
waitUntilKeyreleased();
showSymbolKeepSum(0);
}
cPlayer++;
if(cPlayer > 1)
cPlayer = 0;
}
clearScreen();
showDecimal(cDiceSum[0], 0, 0);
showDecimal(cDiceSum[1], 5, 5);
if(cDiceSum[0] <= 36)
{
if(cDiceSum[0] > cDiceSum[1])
cPlayerScore[0]++;
}
if(cDiceSum[1] <= 36)
{
if(cDiceSum[1] > cDiceSum[0])
cPlayerScore[1]++;
}
waitUntilKeypressed();
waitUntilKeyreleased();
if( (cPlayerScore[0] == 5) || (cPlayerScore[1] == 5) )
{
bGameOver = 1;
}
cPlayer++;
if(cPlayer > 1)
cPlayer = 0;
}
while(!bGameOver);
showTotalScore();
waitUntilKeypressed();
waitUntilKeyreleased();
blinkOff();
clearScreen();
setStandbyMode();
}
}
![]() | Franzis Ping-Pong Produktart: Softwarebox 29,95 € |












