| Weitere Artikel aus dem Elo-Magazin |
Ping-Pong Wettbewerb
Aus Ping Pong wird Bing Bong: eine Uhr mit Big Ben Melodie
Hier wird das Ping Pong umfunktioniert zu einem Bing Bong: Eine Uhr mit Anzeige der Uhrzeit im LED-Display und dem Abspielen der bekannten Melodie und des Glockenschlags von Big Ben, dem berühmten Uhrturm in London, zu jeder Viertelstunde. Die Melodien werden über eine an der Ping-Pong-Platine angeschlossenen Zusatzhardware mit wenig Bauteilaufwand, dem sogenannten "Simple SD Audio Player", abgespielt.
von Michael Gaus
Hier wird das Ping Pong umfunktioniert zu einem Bing Bong: Eine Uhr mit Anzeige der Uhrzeit im LED-Display und dem Abspielen der bekannten Melodie und des Glockenschlags von Big Ben, dem berühmten Uhrturm in London, zu jeder Viertelstunde.
Die Melodien werden über eine an der Ping-Pong-Platine angeschlossenen Zusatzhardware mit wenig Bauteilaufwand, dem sogenannten "Simple SD Audio Player", abgespielt.
Der "Simple SD Audio Player" kann WAV-Dateien von einer SD-Karte abspielen und benötigt nur einen ATtiny85 mit wenigen externen Bauteilen. Er wurde so modifiziert, dass per I2C-Bus ein bestimmter Sound von der SD-Karte abgespielt werden kann. Für Big Ben werden insgesamt 5 WAV-Dateien benötigt.
Zusätzlich benötigte Hardware
Ganzen Artikel lesen...

a) 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.
b) Ein Uhrenquarz mit 32,768 kHz muss an die Pins PB6 und PB7 angelötet werden. Damit der Oscillator im Atmega8 aktiv wird, muss das Fusebit CKOPT gesetzt werden. Getaktet wird der ATmega8 aber unverändert durch den internen 8 MHz Oszillator, der 32,768 kHz Quarz taktet lediglich den Timer2.
c) Bauteile für "Simple SD Audio Player": ATTiny85, SD-Kartenhalter, 4 Kondensatoren, Lautsprecher, Spannungsregler ADP3303-3.0
Ein Schaltplan ist in der Datei bingbong_schaltplan.png zu finden.
Da die SD-Karte mit Spannungspegeln von 2,7 ... 3,3V arbeitet, wurde ein 3,0V LowDrop Linearspannungsregler ADP3303-3.0 verwendet, der zusätzlich über einen Shutdown-Pin verfügt. Wenn Shutdown auf GND gezogen wird, dann werden die 3V abgeschaltet und der Spannungsregler verbraucht im Standbymodus nur wenige µA. Der Shutdown-Pin wird am Portpin D.1 der Ping Pong Platine angeschlossen, sodass der Atmega8 die Spannungsversorgung für den Simple SD Audio Player ein- und ausschalten kann.
Da mit einer minimalen Anzahl von Bauelementen ausgekommen werden soll, wurde auf den eigentlich erforderlichen Tiefpass am PWM-Ausgang des ATtiny85 verzichtet. Stattdessen wird über einen Elko direkt ein kleiner Lautsprecher angeschlossen. Zu beachten ist, dass hier kein Verstärker und keine Aktivboxen angeschlossen werden dürfen, da diese ohne Tiefpass zerstört werden könnten.
Simple SD Audio Player
Der Attiny85 liest die Daten einer WAV-Datei von der SD-Karte ein und erzeugt über eine integrierte PWM-Einheit eine Soundausgabe.
Unterstützt werden Dateien im RIFF-WAVE format/LPCM, 8/16-bit, mono/stereo und bis zu 48kHz Samplingrate.
Trotz des geringen Hardwareaufwands wird eine erstaunliche gute Soundqualität erreicht, wenn die WAV-Dateien eine entsprechend gute Qualität haben, z.B. 44 kHz Samplingrate.
Das Originalprojekt mit Beschreibung stammt von einem Japaner und ist hier zu finden:
http://elm-chan.org/works/sd8p/report.html
Die Software wurde so modifiziert, dass per I2C-Bus ein bestimmter Sound von der SD-Karte abgespielt werden kann. Benötigt werden hier 5 Sounds: Sounddatei 1-4 sind die Sounds für 1/4, 1/2, 3/4 und volle Stunde, Sounddatei 5 ist der Sound, der bei jeder vollen Stunde anschließend an Sound 4 noch entsprechend des Stundenwerts x-mal als Glockenschlag abgespielt wird, sozusagen das "Bong". Der Simple SD Audio Player ist dabei ein I2C-Slave, der über das USI realisiert wurde. Da die I2C-Pins des ATtiny85 eigentlich schon für die Ansteuerung der SD-Karte belegt sind, wurde hier eine softwaremäßige Umschaltung vorgenommen: nach PowerOn werden diese als I2C geschaltet und es wird gewartet, bis die Soundnummer empfangen wurde. Anschließend werden die Pins als SPI Interface für die SD-Kartenansteuerung verwendet. Der Atmega8 der Ping Pong Platine ist der I2C-Master und nutzt das on-chip I2C-Interface. Die erforderlichen Pullups für I2C werden im ATmega8 intern hinzugeschaltet. Nachdem die Soundnummer übertragen wurde, wird im Atmega8 das I2C-Interface abgeschaltet und beide Pins SCL und SDA werden als Eingänge beschaltet. Hierüber kann dann erkannt werden, wann der Sound zu Ende ist, da dann keine Pegelwechsel mehr auf der CLK-Leitung der SD-Karte vorhanden sind.
In der ZIP-Datei ist im Unterverzeichnis bingbong_attiny85 die Hexdatei sd8p_mo.hex sowie ein Screenshot attiny85_fusebits.jpg mit den notwendigen Fusebits für den ATtiny85 enthalten. Die Programmierung des ATtiny85 kann über ISP erfolgen. Hierzu sollte noch keine SD-Karte eingelegt sein.
Nach dem Einschalten der Spannung erscheint die Anzeige der Uhr: ein Kreis mit 12 LEDs symbolisiert die Stunden, wobei die aktuelle Stunde mit voller Helligkeit angezeigt wird und die übrigen 11 LEDs gedimmt angezeigt werden. Innerhalb des Kreises werden die Minuten als 2-stelliger Dezimalwert gedimmt angezeigt. Direkt nach dem Einschalten startet die Uhr mit 0:00 Uhr.
Durch kurzes Drücken des Bedientasters kann die Dezimalanzeige umgeschaltet werden zwischen Minuten und Sekunden.
Durch langes Drücken des Bedientasters wird in den Modus zur Einstellung der Uhrzeit gewechselt. Der Taster muss solange gedrückt gehalten werden, bis die Dezimalanzeige innerhalb des Kreises erlischt. Die Uhr wird gestoppt und im Kreis wird nun derjenige Stundenwert mit voller Helligkeit angezeigt, der entsprechend der Stellung des rechten Potis eingestellt ist. Mit dem Poti kann nun der aktuelle Stundenwert eingestellt werden, hierzu ist der Einstellbereich in 12 Schritte unterteilt. Anschließend wird mit einem kurzen Tastendruck bestätigt.
Nun wird in der Mitte des Kreises die entsprechend den beiden Potis eingestellten Minuten in voller Helligkeit dargestellt. Mit dem linken Poti oberhalb des Münzschlitzes kann die Zehnerstelle (0-5) und mit dem rechten Poti die Einerstelle (0-9) des Minutenwerts eingestellt werden. Es sollte der aktuelle Minutenwert plus 1 Minute eingestellt werden. Anschließend wird wieder mit einem kurzen Tastendruck bestätigt.
In der Dezimalanzeige wird nun der Wert 00 gedimmt angezeigt, was den Sekunden entspricht. Wenn der vorhin eingestellte Minutenwert sekundengenau erreicht wurde, dann muss durch einen kurzen Tastendruck bestätigt werden. Beim Loslassen des Tasters startet dann die Uhr entsprechend der eingestellten Stunden- und Minutenwerte und mit Sekundenwert Null. Die Uhrzeiteinstellung ist damit beendet. In der Dezimalanzeige werden die Sekunden angezeigt, durch eine kurzen Tastendruck wird umgeschaltet auf die Minutenanzeige.
Jede Viertelstunde wird ein Sound abgespielt, entsprechend den Sounddateien 1-4 (1/4, 1/2, 3/4, volle Stunde) auf der SD-Karte. Zu jeder vollen Stunde wird anschließend die Sounddatei 5 noch entsprechend des Stundenwerts x-mal als Glockenschlag abgespielt, um die aktuelle Stunde zu verkünden.
Sounddateien
Auf der SD-Karte werden 5 Sounddateien benötigt: bigben1.wav, bigben2.wav, bigben3.wav, bigben4.wav und bong.wav
bigben1-4.wav enthalten die Sounds für 1/4, 1/2, 3/4 und die volle Stunde, bong.wav enthält den Sound für einen Glockenschlag, der entsprechend de aktuellen Stundenwerts x-mal abgespielt wird.
Die Dateien müssen folgendes Format aufweisen: RIFF-WAVE format/LPCM, 8/16-bit, mono/stereo und bis zu 48 kHz Samplingrate.
Die Dateien werden beim Abspielen mit dem Simple SD Audio Player in der Reihenfolge des Kopierens durchnummeriert. Am besten kopiert man die 5 Dateien einzeln in folgender Teihenfolge auf die SD-karte: bigben1.wav bis bigben4.wav und dann bong.wav. Durch Aufspielen eigener Dateien könnte z.B. auch eine Kuckucksuhr realisiert werden.
Download: Alle Sound-Dateien
Quellcode
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 ausreicht. Das komplette Projekt ist in der ZIP-Datei enthalten (Projektdatei für CodeVison AVR ist bingbong.prj).
Der Code für den Simple SD Audio Player auf dem ATtiny85 wurde mit der Freeware WinAVR (Version WinAVR-20100110.exe) erstellt. Hierzu wurde der Originalcode für das Bing Bong Projekt so modifiziert, dass nach PowerOn zunächst gewartet wird, bis über I2C-Bus die Nummer des abzuspielenden Sounds (WAV-Datei) empfangen wurde. Anschließend wird der gewünschte Sound abgespielt, falls vorhanden und danach gestoppt.
Download: Quelltexte und Hex-Dateien
/*****************************************************
Compiler : CodeVisionAVR 2.04.6 Evaluation
Chip type : ATmega8
Clock frequency : 8 MHz (int. RC-OSC)
*****************************************************/
//***************************************************
// Bing Bong - eine Uhr mit Big Ben Melodie
// 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>
#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 P_SHUTDOWN_SD PORTD.1 // Portpin for /Shutdown of SD card player
#define DP_SHUTDOWN_SD DDRD.1
#define SD_PLAYER_OFF (P_SHUTDOWN_SD = 0)
#define SD_PLAYER_ON (P_SHUTDOWN_SD = 1)
#define P_SDA PORTC.4 // Portpin for SDA
#define DP_SDA DDRC.4
#define PIN_SDA PINC.4
#define P_SCL PORTC.5 // Portpin for SCL
#define DP_SCL DDRC.5
#define PIN_SCL PINC.5
#define WIDTH 12 // number of fields in horizontal direction
#define HEIGHT 10 // number of fields in vertical direction
unsigned char ledState[WIDTH*HEIGHT]; // current state of each LED
enum { LED_OFF = 0, LED_ON, LED_DIM }; // possible states of a LED
#define BLINKING 0x80 // to set a LED blinking, it is ORed with 0x80
unsigned char seconds = 0; // current time: seconds
unsigned char minutes = 0; // current time: minutes
unsigned char hours = 0; // current time: hours
bit bSound = 0; // 1=play sound
flash unsigned char ledHours[12] = // LED numbers for all 12 hours (0..11)
{
50, 81, 103, 105, 107, 89, 59, 29, 7, 5, 3, 21
};
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*HEIGHT); i++)
{
ledState[i] = LED_OFF;
}
}
// 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 0 overflow interrupt service routine
// multiplexing of LEDs
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
#define FRAME_MASK 0x03
static unsigned char count = 0;
static unsigned char framecount = 0;
static unsigned int blinkcounter = 0;
static bit bBlinkOn = 1;
bit bLed;
unsigned char state, i, value1, value2, value3;
unsigned char *pState;
blinkcounter++;
if(blinkcounter == 1000)
{
bBlinkOn = ~bBlinkOn;
blinkcounter = 0;
}
count++;
if(count >= 12)
{
count = 0;
P_DATA = 0;
framecount++;
}
else
{
P_DATA = 1;
}
P_CLK = 1;
P_CLK = 0;
pState = &ledState[count*HEIGHT];
value1 = 0;
for(i = 0; i < 4; i++)
{
value1 >>= 1;
state = (*pState) & (~BLINKING);
bLed = 0;
if(state == LED_ON)
{
bLed = 1;
}
else if(state == LED_DIM)
{
if((framecount & FRAME_MASK) == FRAME_MASK)
bLed = 1;
}
if((*pState) & BLINKING)
{
if(!bBlinkOn)
bLed = 0;
}
if(bLed)
{
value1 |= 0x08;
}
pState++;
}
value2 = 0;
for(i = 0; i < 4; i++)
{
value2 >>= 1;
state = (*pState) & (~BLINKING);
bLed = 0;
if(state == LED_ON)
{
bLed = 1;
}
else if(state == LED_DIM)
{
if((framecount & FRAME_MASK) == FRAME_MASK)
bLed = 1;
}
if((*pState) & BLINKING)
{
if(!bBlinkOn)
bLed = 0;
}
if(bLed)
{
value2 |= 0x80;
}
pState++;
}
value3 = 0;
for(i = 0; i < 2; i++)
{
value3 >>= 1;
state = (*pState) & (~BLINKING);
bLed = 0;
if(state == LED_ON)
{
bLed = 1;
}
else if(state == LED_DIM)
{
if((framecount & FRAME_MASK) == FRAME_MASK)
bLed = 1;
}
if((*pState) & BLINKING)
{
if(!bBlinkOn)
bLed = 0;
}
if(bLed)
{
value3 |= 0x02;
}
pState++;
}
PORTC &= (~0x0F);
PORTD &= (~0xF0);
PORTB &= (~0x03);
P_STROBE = 1;
P_STROBE = 0;
PORTC |= (value1);
PORTD |= (value2);
PORTB |= (value3);
}
// initialization of Timer0
void initTimer0(void)
{
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
TCCR0=0x02;
TCNT0=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK |= 0x01;
}
// Timer 2 overflow interrupt service routine
// clock interrupt
// occurs every 1 second
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
if(seconds < 59)
{
seconds++;
}
else
{
seconds = 0;
if(minutes < 59)
minutes++;
else
{
minutes = 0;
if(hours < 23)
hours++;
else
hours = 0;
}
if((minutes % 15) == 0)
{ // play sound every 15 minutes
bSound = 1;
}
}
}
// initialization of Timer2
void initTimer2(void)
{
// Timer/Counter 2 initialization
// Clock source: TOSC1 pin
// Clock value: PCK2/128
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x08;
TCCR2=0x05;
TCNT2=0x00;
OCR2=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK |= 0x40;
}
// stop Timer2
void stopTimer2(void)
{
TCCR2=0x00;
TCNT2=0x00;
}
// 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;
P_SHUTDOWN_SD = 0;
DP_SHUTDOWN_SD = 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 minute lower digit
// return: selected minute lower digit (0...9)
unsigned char selectMinutes1(void)
{
unsigned char x;
x = 9 - (read_adc(7) / (1023/10 + 1));
return(x);
}
// select minute upper digit
// return: selected minute upper digit (0...5)
unsigned char selectMinutes10(void)
{
unsigned char x;
x = (read_adc(6) / (1023/6 + 1));
return(x);
}
// select hour
// return: selected hour (0...11)
unsigned char selectHour(void)
{
unsigned char x;
x = 11 - (read_adc(7) / (1023/12 + 1));
return(x);
}
// initialize I2C interface
void initI2C(void)
{
// Two Wire Bus initialization
// Bit Rate: 25,000 kHz
TWBR=0x98;
// Two Wire Bus Slave Address: 0h
// General Call Recognition: Off
TWAR=0x00;
// Generate Acknowledge Pulse: On
// TWI Interrupt: Off
TWCR=0x44;
TWSR=0x00;
}
// disable I2C interface
void disableI2C(void)
{
TWCR=0x00;
TWSR=0x00;
}
#define TWINT 7
#define TWSTA 5
#define TWSTO 4
#define TWEN 2
// I2C start condition
void i2cStart(void)
{
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
}
// I2c stop condition
void i2cStop(void)
{
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}
// I2C send a byte
// c: byte to send
void i2cSend(unsigned char c)
{
TWDR = c;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
}
// show decimal value on display
// d: value to be displayed (0...99)
// state: display as dimmed or ON (LED_DIM or LED_ON)
void showDecimal(unsigned char d, unsigned char state)
{
unsigned char i, j, k, value, col, divisor, pattern;
col = 2;
divisor = 10;
for(k = 0; k < 2; k++)
{
value = d / divisor;
for(j = 0; j < 3; j++)
{ // show decimal using stored font
pattern = decimals[value*3 + j];
for(i = 0; i < 5; i++)
{
if( pattern & (0x01 << i) )
ledState[col*HEIGHT + 3 + i] = state;
else
ledState[col*HEIGHT + 3 + i] = LED_OFF;
}
col++;
}
col++;
d = d % divisor;
divisor = divisor / 10;
}
}
// show clock on display:
// 1 LED for each hour, current hour LED is ON, other 11 LEDs are dimmed
// minutes or seconds are displayed as 2 digits decimal
// cShowMinutes: 1=show minutes, 0=show seconds
// cDecimalState: display decimals as dimmed or ON (LED_DIM or LED_ON)
void showClock(unsigned char cShowMinutes, unsigned char cDecimalState)
{
unsigned char i, cValue, cHour, state;
if(cShowMinutes)
cValue = minutes;
else
cValue = seconds;
cHour = hours;
if(cHour >= 12)
cHour -= 12;
for(i = 0; i < 12; i++)
{
if(i == cHour)
state = LED_ON;
else
state = LED_DIM;
ledState[ledHours[i]] = state;
}
showDecimal(cValue, cDecimalState);
}
// main routine
void main(void)
{
unsigned char d, d10, index=0, i, bongCounter=0;
unsigned int iCountSCL;
bit bShowMinutes = 1;
bit bCheckSoundEnd = 0;
init();
initTimer0();
initTimer2();
initADC();
initInt0();
clearScreen();
#asm("sei") // Global enable interrupts
while(1)
{
if(KEY_PRESSED)
{
delay_ms(20);
i = 50;
while( keyPressed() && (i != 0) ) // check for short or long keypress
{
i--;
}
if(i == 0)
{ // long keypress => set time
stopTimer2();
showClock(1, LED_OFF);
waitUntilKeyreleased();
do
{
d = selectHour(); // select hour (0-11)
hours = d;
showClock(1, LED_OFF);
}
while(!keyPressed());
waitUntilKeyreleased();
do
{
d10 = selectMinutes10(); // select minutes upper digit (0-5)
d = selectMinutes1(); // select minutes lower digit (0-9)
minutes = d10*10 + d;
showClock(1, LED_ON);
}
while(!keyPressed());
waitUntilKeyreleased();
seconds = 0;
showClock(0, LED_DIM);
bShowMinutes = 0; // show seconds in display after setting clock
waitUntilKeypressed();
waitUntilKeyreleased();
initTimer2();
}
else
{ // short keypress => toggle between display of minutes and seconds
bShowMinutes = ~bShowMinutes;
}
}
showClock(bShowMinutes, LED_DIM); // show current time on display
if(bSound) // check if sound has to be played
{
index = minutes / 15; // sound 1-4: 1/4, 1/2, 3/4, 4/4 hour
if(index == 0)
{
index = 4;
}
bSound = 0;
if(index == 4) // each hour, "bong" current hours
{
bongCounter = hours;
if(bongCounter > 12)
bongCounter -= 12;
if(bongCounter == 0)
bongCounter = 12;
}
}
if(index) // check if SD card player has to be started
{
P_SCL = 1; // enable pullups for I2C
P_SDA = 1;
SD_PLAYER_ON;
delay_ms(100);
initI2C();
i2cStart();
i2cSend(0xAA); // I2C address
i2cSend(index); // I2C data
i2cStop();
disableI2C();
delay_ms(50);
index = 0;
iCountSCL = 0;
bCheckSoundEnd = 1;
}
if(bCheckSoundEnd)
{ // check for sound end, if SCL is permanent HIGH
if(PIN_SCL)
{
iCountSCL++;
}
else
{
iCountSCL = 0;
}
if(iCountSCL >= 1000)
{
bCheckSoundEnd = 0;
if(bongCounter)
{
index = 5; // sound 5: "bong"
bongCounter--;
}
else
{
P_SCL = 0; // disable pullups for I2C
P_SDA = 0;
SD_PLAYER_OFF; // switch OFF SD card player
}
}
}
}
}
![]() | Franzis Ping-Pong Produktart: Softwarebox 29,95 € |













