Durch Einwurf einer Münze wird Long gestartet. Im Display erscheint kurz ein Startbildschirm. Anschließend wird bereits der Zufallsgenerator für die Erzeugung der Lottozahlen gestartet, was auch im Display angezeigt wird. Durch einen Tastendruck wird dies gestoppt und es wird abhängig von der Potistellung eine der 6 erzeugten Lottozahlen auf dem Display angezeigt. Über das rechte Poti können die 6 Zahlen nacheinander angewählt werden, hierzu ist der Einstellbereich in 6 Schritte unterteilt. Ein 2 Pixel breiter horizontaler Balken in der untersten LED-Reihe zeigt die aktuelle Poti-Position an.
Nach einem weiteren Tastendruck geht Long in den stromsparenden Standbymodus. Durch einen erneuten Münzeinwurf kann der Lottozahlengenerator neu 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 long.prj).
/*****************************************************
Compiler : CodeVisionAVR 2.04.6 Evaluation
Chip type : ATmega8
Clock frequency : 8 MHz (int. RC-OSC)
*****************************************************/
//***************************************************
// Lottozahlengenerator Long: Lottozahlen ohne nachzudenken generieren
// 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 lotto[6]; // array for 6 random values (1..49)
flash unsigned char decimals[] =
{ // Font for decimal values
0x3E,0x51,0x49,0x45,0x3E, // 0
0x00,0x42,0x7F,0x40,0x00, // 1
0x42,0x61,0x51,0x49,0x46, // 2
0x22,0x41,0x49,0x49,0x36, // 3
0x18,0x14,0x12,0x7F,0x10, // 4
0x27,0x45,0x45,0x45,0x39, // 5
0x3C,0x4A,0x49,0x49,0x30, // 6
0x01,0x71,0x09,0x05,0x03, // 7
0x36,0x49,0x49,0x49,0x36, // 8
0x06,0x49,0x49,0x29,0x1E // 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 x-position
// return: selected x-position (0...5)
unsigned char selectX(void)
{
unsigned char x;
x = 5 - (read_adc(7) / (1023/6 + 1));
return(x);
}
// set blinking status for upper 8 LED rows
// blink: 0=blinking off, 0xFF=blinking on
void blinkScreen(unsigned char blink)
{
unsigned char i;
for(i = 0; i < 12; i++)
ledsBlink[i] = blink;
}
// show decimal value on display
// d: value to be displayed (0...99)
void showDecimal(unsigned char d)
{
unsigned char j, k, value, col, divisor;
unsigned int ledsLocal[12];
for(j = 0; j < 12; j++)
{
ledsLocal[j] = leds[j] & 0x200;
}
col = 0;
divisor = 10;
for(k = 0; k < 2; k++)
{
value = d / divisor;
for(j = 0; j < 5; j++)
{ // show decimal using stored font
if( (k == 0) && (value == 0) )
ledsLocal[col++] |= 0; // suppress leading zero
else
ledsLocal[col++] |= ((unsigned int)decimals[value*5 + j] << 1);
}
col++;
d %= divisor;
divisor /= 10;
}
for(j = 0; j < 12; j++)
{
leds[j] = ledsLocal[j];
}
}
// generate 6 random values (1..49)
void generateLotto(void)
{
unsigned char i, j;
bit bReady;
do
{
for(i = 0; i < 6; i++)
{
lotto[i] = (rand() % 49) + 1;
srand(TCNT0); //initialize random generator
}
showDecimal(lotto[0]);
}
while(!keyPressed());
waitUntilKeyreleased();
for(i = 1; i < 6; i++) // ensure that we get no similar values
{
for(j = 0; j < 6; j++)
{
do
{
if( (lotto[i] == lotto[j]) && (i != j) )
{
lotto[i] = (rand() % 49) + 1;
bReady = 0;
}
else
{
bReady = 1;
}
}
while(!bReady);
}
}
}
// show startlogo logo on LED display
void showStartLogo(void)
{
leds[0] = 31;
leds[1] = 16;
leds[2] = 1008;
leds[3] = 80;
leds[4] = 128;
leds[5] = 992;
leds[6] = 14;
leds[7] = 17;
leds[8] = 465;
leds[9] = 558;
leds[10] = 672;
leds[11] = 928;
}
// show selected postion on display with a 2 pixels wide horizontal line
// x: selected position (0..5)
void showSelection(unsigned char x)
{
unsigned char i, col = 0;
for(i = 0; i < 6; i++)
{
if(i == x)
{
leds[col++] |= 0x200;
leds[col++] |= 0x200;
}
else
{
leds[col++] &= (~0x200);
leds[col++] &= (~0x200);
}
}
}
// main routine
void main(void)
{
unsigned char x;
init();
initTimers();
initADC();
initInt0();
#asm("sei") // Global enable interrupts
while(1)
{
clearScreen();
showStartLogo();
delay_ms(2000);
clearScreen();
srand(TCNT0); //initialize random generator
generateLotto();
do
{
x= selectX();
showDecimal(lotto[x]);
showSelection(x);
}
while(!keyPressed());
waitUntilKeyreleased();
setStandbyMode();
}
}