Zurück (C) Christof Ermer, Regensburg
"Retro Ping Pong"


Erneuert
11.04.2019
07.23

AVR LEDDISPLAY , 
Ein PingPong Spiel von Conrad, mit einem ATMEga 8 Controller.  damals ~10€
Einfach suchen nach "Retro Ping Pong"
Da kann man selbst Software schreiben und aufspielen !! Nur ein ISP Stecker muss aufgelötet werden
Missbraucht als Kostengünsteiges LED Array , z.B für ein Software Oszilloscope


HARDWARE
8TMega8, Shift register CD4094, 10x10 LEDs, ISP Port
Files
4094.c    Shift Register Baustein    .c   Ansteuerung     12DatenBit anlegen, Aufrufen, Dazu die passende Anodenleitung mit Pin +5V  aufschalten. Fertig
4094.h    Shift Register Baustein    .h   Definitionen
Retroboard.zip   Alle WINAVR Files im Zip  um mal grundlegend mit dem Retroboard zu arbeiten ( ist nur ein Softwarebeispiel )

Projekt Fraktalgenerator: C_Ermer_FRAKTAL_RetroBoard-PingPong.zip



Hier das PingPong, Modul zu beziehen vom Conrad. Für nur 7€ !!!
Darin werkelt ein AVR ATMega 8 im SO Gehäuse
Programmiert wird er über ien 2x3 ISP Stecker, den man aber erst noch einlöten muss ( von unten ! , und Einbau-Drehrichtung beachten )
Damit kann man selbst z.B. allerle Proggrammieren,
z.B. einen  Oszillografen programmieren.
Als Projektidee, Oder eine Uhr.
Uhrenquarz dran. Fuse Bits richtig setzen, fertig-
Die LEDsKathoden werden über ein Shift Register( CMOS 4094 ) angesteuert ..



Schaltplan klein:

Gut aufgelöster Schaltplan:





Beispiel Software AUSZUG
noch unfertig: Fahrrad Blinker mit IR Fernbedienung

======================================================================
#ifndef OUTPUTSHIFT_4094_HEADER
#define OUTPUTSHIFT_4094_HEADER

//---------------------------------------------
// 4094 OPUTSHIFT SECTION
//---------------------------------------------

#define TWO_CLK_CYCLES() __asm__ __volatile__( "rjmp 1f\n 1:" );
   
#define CMOS4094_DATA_PORT            PORTB
#define CMOS4094_CLK_PORT            PORTB
#define CMOS4094_STROBE_PORT        PORTB
#define CMOS4094_DIR_REG            DDRB
#define CMOS4094_DIR_REG_BITMSK        0x1C

#define CMOS4094_DATA_BIT            0x10    //PB4 //Daten rausshiften
#define CMOS4094_CLK_BIT            0x08    //PB3 Shift clock ( LowToHigh transition )
#define CMOS4094_STROBE_BIT            0x04    //PB2

#define CMOS4094_INITDIRREG()    ( CMOS4094_DIR_REG |= CMOS4094_DIR_REG_BITMSK )

#define CMOS4094_STROBE_LOW()    ( CMOS4094_STROBE_PORT &= ~CMOS4094_STROBE_BIT ) //Clear    ShiftReg mit HighFlanke RCK
#define CMOS4094_STROBE_HIGH()    ( CMOS4094_STROBE_PORT |=  CMOS4094_STROBE_BIT )     //Enable SHiftreg

#define CMOS4094_DATA_LOW()        ( CMOS4094_DATA_PORT &= ~CMOS4094_DATA_BIT ) //Daten rausshiften
#define CMOS4094_DATA_HIGH()    ( CMOS4094_DATA_PORT |= CMOS4094_DATA_BIT ) //Daten rausshiften

#define CMOS4094_CLK_LOW()    ( CMOS4094_CLK_PORT &= ~CMOS4094_CLK_BIT ) //Shift clock
#define CMOS4094_CLK_HIGH()    ( CMOS4094_CLK_PORT |= CMOS4094_CLK_BIT ) //Shift clock

extern void Write_OUT4094( uint16_t  u16Val, uint8_t u8BitCnt );  // WERT, ShiftBits; // WERT, ShiftBits


#endif //OUTPUTSHIFT_4094_HEADER
======================================================================

#include <ctype.h>
#include <inttypes.h>
#include <avr\io.h>
#include <util\delay.h>
#include "4094.h"


///GLOBAL VAR
//SU_SHIFT_CMOS4094_TYPE gSU_CMOS4094; //Struct Union#


// Folge Write one Position on X Position !
// *******************************************************************
void Write_OUT4094( uint16_t  u16Val, uint8_t u8BitCnt )  // WERT, ShitBits
// *******************************************************************
{
u8BitCnt--;

//CMOS4094_INITDIRREG();   //NICHT Vergessen dass im main.c zu machen
//CMOS4094_STROBE_LOW();
//CMOS4094_CLK_LOW();
//__asm__ __volatile__( "rjmp 1f\n 1:" );    // 2 cycles
//_delay_us(1);
do
    {  // Clock out bits from the eo array
     if( u16Val  & (1U << u8BitCnt ) )     // Ist es undiert eine EINS ?
        {     
        CMOS4094_DATA_HIGH();    
        }         
     else
        {   
        CMOS4094_DATA_LOW();   
        };     
TWO_CLK_CYCLES();   // 2 cycles
//_delay_us(1);
    CMOS4094_CLK_HIGH();    //Shift clock
TWO_CLK_CYCLES();
//_delay_us(1);
    CMOS4094_CLK_LOW();
  }while( u8BitCnt-- );
TWO_CLK_CYCLES();
//_delay_us(1);
CMOS4094_STROBE_HIGH();
TWO_CLK_CYCLES();
//_delay_us(1);
CMOS4094_STROBE_LOW();
};

=====================================================================

/*
Zwangstypecast wegen Pointerarrithemetik --> (u8NN*2) oder (u8NN<<1)
PGM_VOID_P  gppmZeichen = gpmaPfeil_Rechts;
gu16aMatrix[ u8NN ] = pgm_read_word_near( gppmZeichen + (u8NN<<2)  );
file:///D:/WinAVR-20100110/doc/avr-libc/avr-libc-user-manual/group__avr__stdlib.html#g114aeb1751119382aaf3340355b22cfd
------------------------------------------------------------------------------
 Programmed by Christof Ermer
05.04.2019
------------------------------------------------------------------------------
*/
// ORG FUSE PING PONG L=E4  H= D9 Ext = FD  Kalob= ADADADAC
// MIt 16MHz Quarz BrownOut 4.7Volt CKOPT    L=3F  H=C9
//-U lfuse:w:0x7f:m -U hfuse:w:0xc9:m
//http://www.engbedded.com/fusecalc

//SYSINFO
#define DATUM        "19.03.2015"
#define FUNKTION    "PROJEKT PINGPONG 4094 "
#define HARDWARE    "Atmel ATMega16 V3.3"
#define UHRZEIT        "12:00"
#define AUTOR        "Christof Ermer"

#define IHAVENOBRAIN    "I have no brain."   
#define USEYOURS        "Use your own"

/*  HISTORY
In Interupts...alle Vars deklarieren mit
volatile uint32_t Tickscounter..
*/
#include "main.h"        //with Hardware assigns

//CONSTANT ARRAYs IN .TEXT = ROM ARREA   .DATA IST SRAM !! .BSS SRAM
const uint16_t gpmaAchtung[] PROGMEM = {0x300,0x2C0,0x270,0x20C,0x202,0x2DD,0x2DD,0x202,0x20C,0x230,0x2C0,0x300};
const uint16_t gpmaNull10x12[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0};
const uint16_t gpmaPfeil_Links[] PROGMEM = {0x222,0x51,0x88,0x104,0x222,0x51,0x88,0x104,0x222,0x51,0x88,0x104};
const uint16_t gpmaPfeil_Rechts[] PROGMEM = {0x82,0x44,0x228,0x111,0x82,0x44,0x228,0x111,0x82,0x44,0x228,0x111};
const uint16_t gpmaWarnBlink1[] PROGMEM = {0x10,0x28,0x44,0x92,0x129,0x00,0x00,0x129,0x92,0x44,0x28,0x10};
const uint16_t gpmaWarnBlink2[] PROGMEM = {0x28,0x44,0x92,0x129,0x244,0x82,0x82,0x244,0x129,0x92,0x44,0x28};


volatile uint8_t gu8Status;
volatile uint32_t gu32_Ticks; //  T2 timeCounter, only NN_Counter for Keypressings
volatile uint16_t gu16aMatrix[ 12 ];

PGM_VOID_P  gppmZeichen =  gpmaNull10x12;
uint8_t gu8ZeichenSelect = PFEIL_DUNKEL;

//#define TICK_1000MS 977
ISR( TIMER2_COMP_vect ) //TIMER2_OVF_vect TIMER2_COMP_vect
{
static uint8_t u8Val=0;
// UPDATE BILDSCHIRM
u8Val++;
u8Val %= 12; // Ou8Val ist nur eine Variable
Write_OUT4094( 0xFFF, 12 ); // WERT, ShiftBits
//Lege Daten an   
PORTC &= ~0x0F;
PORTC |=  gu16aMatrix[ u8Val ] & VAL_PORTC_MSK;

PORTD &= ~0xF0;
PORTD  |= gu16aMatrix[ u8Val ] & VAL_PORTD_MSK;

PORTB &= ~0x03;
PORTB |= ((gu16aMatrix[ u8Val ] & VAL_PORTB_MSK) >> 8);
//Schreibe Daten
Write_OUT4094( ~(1U << u8Val), 12); // WERT, ShitBits

gu32_Ticks++;   
//if( !(gu32_Ticks % (977U)) )
if( !(gu32_Ticks % (1000U)) )
    {
    gu8Status |= TICK_EVENT;   
    };    

if( !(gu32_Ticks % (977U)) )
    {
    gu8Status |= TICK_100MS_EVENT;   
    };    
};
   
// PRESCALER 3,6864 /  32 = 115200 50-200Khz gewünscht
// REM ADC4-ADC5 = 8 BIT;
// 4+2 Channel.
//****************************************************************
uint16_t ADC_10Bit(uint8_t ucChan)
//****************************************************************
{
DDRC &= ~(1<<ucChan);   //port A Chanel Bit Input 
PORTC &= ~(1<<ucChan); //Wegen Pullup abschalten
  // Activate ADC with Prescaler 16 --> 16Mhz/128 = 125 khz
ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);   // 1MHZ / 8
 // Select pin ADC0 using MUX
ADMUX = (ucChan ); //ADC_MUX_MASK = 0b00000111
   
ADCSRA |= _BV(ADSC);  //Start conversion
while (ADCSRA & _BV(ADSC) ) // wait until converstion completed
    {
    wdt_reset();
    };      
return ADC;// get converted value
};


//  *************
void CLrMatrix( void)
//  *************
{
register uint8_t u8NN =11;
do
    {
    gu16aMatrix[u8NN]=0;
    }while( u8NN--);
};


// *******************************************************************
// *******************************************************************
int main(void)
// *******************************************************************
// *******************************************************************
{
uint8_t u8NN;
uint8_t u8Shifter=0;

CMOS4094_INITDIRREG();
CMOS4094_STROBE_LOW();
CMOS4094_CLK_LOW();

DDRD |= _BV( PD2 ) | _BV( PD1 );
PORTD &= ~_BV( PD2 ); // Potiground auf 0;

CMOS4094_INITDIRREG();
DDRC |= BLOCK1_DDRC;
DDRD |= BLOCK2_DDRD;
DDRB |= BLOCK3_DDRB;


//SFIOR = (1<<PUD); //Pullup Disable

//Pointer and Strings init
wdt_enable(WDTO_2S); //Set 1.9Sec !!WatchDog ENABLE
wdt_reset();   //WATCHDOG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

TCNT2 = 0;
OCR2 = 250;
TCCR2 =  (1 << WGM21) | (1 << CS22) ;    // CTC  /64 250000
TIMSK |= (1<< OCIE2); //OVF-Interrupt TOIE2

uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) );
ResetRxBuff();

rc5_init(RC5_ALL);
sei();
       
gppmZeichen = gpmaAchtung;
gu8ZeichenSelect = PFEIL_ACHTUNG;

for(u8NN=0; u8NN < 12; u8NN++)
        {       
        gu16aMatrix[ u8NN ] = pgm_read_word_near( gppmZeichen + (u8NN <<1) );
        };

wdt_reset();   //WATCHDOG
_delay_ms(1000);       
wdt_reset();   //WATCHDOG
gu8ZeichenSelect  = PFEIL_DUNKEL;

gu8Status =0;
while(1)
    {
    wdt_reset();   //WATCHDOG
    //gu16aMatrix[0] = 0xFF;       
    if( gu8Status & TICK_100MS_EVENT)
        {       
        gu8Status &= ~TICK_100MS_EVENT;                

        switch( gu8ZeichenSelect )
            {
             
            case PFEIL_ACHTUNG:
                {
                gppmZeichen = gpmaAchtung;
                u8Shifter = 0;       
                break;
                }
            case PFEIL_LINKS:
                {
                gppmZeichen = gpmaPfeil_Links;
                if(u8Shifter)
                    {
                    u8Shifter--;
                    }
                else
                    {
                    u8Shifter = 11;
                    }
                break;
                }
            case PFEIL_RECHTS:
                {
                gppmZeichen = gpmaPfeil_Rechts;
                u8Shifter++;
                u8Shifter %= 12;       
                break;
                }
            case WARN_BLINK1:
                {
                gppmZeichen = gpmaWarnBlink1;
                u8Shifter = 0;       
                break;
                }
            case WARN_BLINK2:
                {
                gppmZeichen = gpmaWarnBlink2;
                u8Shifter = 0;       
                break;
                }
            case PFEIL_DUNKEL:
                {
                gppmZeichen = gpmaNull10x12;
                u8Shifter = 0;       
                break;
                }
            default:
                {
                gppmZeichen = gpmaNull10x12;
                u8Shifter = 0;       
                break;
                };
               
            };       
        for(u8NN=0; u8NN < 12; u8NN++)
            {
            //Multipliziere *2
            gu16aMatrix[ u8NN ] = pgm_read_word_near(gppmZeichen + ( ( (u8NN + u8Shifter) % 12)<<1) );
            };   
        };
       
    if( gu8Status & TICK_EVENT )
        {
        gu8Status &= ~TICK_EVENT;   
        if( !(gu32_Ticks % random() % 3) )
            {
            gu8ZeichenSelect = random() % 6;
            };
        };

    if( gu8Status & UART_RX_EVENT )
        {
        gu8Status &= ~UART_RX_EVENT;
        UART_TXRX_Check();
        };
       
    };

};
======================================================================