Zurück (C) Christof Ermer, Regensburg


Erneuert
11.04.2019

AVR LEDDISPLAY , 
Ein PingPong Spiel von Conrad, mit einem ATMEga 8 Bontroller.
Da kann man selbst Software aufspielen !! Nur ein ISP Stecker muss aufgelötet werden
Missbraucht als Kostengünsteiges LED Array , z.B für ein Software Oszilloscope
Gab es mal bei CONRAD.de. Einfach suchen nach "Retro Ping Pong"


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. 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();
        };
       
    };

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