ATMEGA als Schalterwechsler mit 7-Segment

DerSchatten

Neues Mitglied
01. Mai 2009
19
0
0
Sprachen
Hallo Leute,

Ich möchte mir gerne für einen Arcade-Controllereigenbau einen AVR programmieren der mir nach belieben die Tastenzuordnung ändern kann.
Insgesammt sollen jeweils 6 Tasten geschalten werden.
Hierfür dachte ich mir sollte ein ATMEGA8 ausreichen.

Denkt ihr wäre sowas eher in C oder BASCOM einfacher zu realisieren?

Zusätzlich soll mittels einem Taster zwischen den einzelnen Konfigurationen weitergeschalten werden können, die dann am Segment-Display angezeigt werden (1-9)

In C hab ich bis jetzt folgendes zusammengebastelt:

Code:
//----------------------------------------
// Titel	: Arcade Tastenprogrammierung
//----------------------------------------
#include <avr/io.h>

typedef unsigned char BYTE;
typedef unsigned int WORD;

BYTE bPortC;
BYTE nKeyPress;

int main (void)
{

    PORTC = 0x01;	// Pull-Up auf Port D, Pin 0 aktivieren
    DDRD = 0x00;	// Port D als Eingang
	DDRB = 0xFF;	// Port B als Ausgang

    bPortC = 1;	// Variable initialisieren
	nKeyPress = 1;

    while(1)
	{
		Auswahl();
		if ((nKeyPress) == 1) Konf1();
		if ((nKeyPress) == 2) Konf2();
		if ((nKeyPress) == 3) Konf3();
	}
	return 0;
}

void Auswahl(void)
{
    if (bit_is_clear (PINC, PINC0))
	{
        if (bPortC)
		{
            nKeyPress++;
            bPortC = 0;
        }
    }
    else
	{
        bPortC = 1;
    }
}

void Konf1(void)
{
	PORTC.0 = PORTD.0
	PORTC.1 = PORTD.1
	PORTC.2 = PORTD.2
	PORTC.3 = PORTD.3
	PORTC.4 = PORTD.4
	PORTC.5 = PORTD.5
}

void Konf2(void)
{
	PORTC.0 = PORTD.2
	PORTC.1 = PORTD.3
	PORTC.2 = PORTD.4
	PORTC.3 = PORTD.5
	PORTC.4 = PORTD.0
	PORTC.5 = PORTD.1
}

void Konf3(void)
{
	PORTC0 = PIND5;
	PORTC1 = PIND4;
	PORTC2 = PIND3;
	PORTC3 = PIND2;
	PORTC4 = PIND1;
	PORTC5 = PIND0;
}

Weitere komme ich leider nicht da meine Kenntnisse nicht ausreichen.

Nachtrag:
Kann es sein das man absolut nichts über Ansteuerung einer 7-Segment Anzeige im Internet findet?
Weder in BASCOM, noch in C?
 
Hallo,

Nachtrag:
Kann es sein das man absolut nichts über Ansteuerung einer 7-Segment Anzeige im Internet findet?
Weder in BASCOM, noch in C?
also mit C und Bascom steh ich ein wenig auf Kriegsfuß :rolleyes:
Aber 7Segment-Anzeigen sollten hier zur genüge im Forum behandelt werden ;)

Schau mal in die FAQs oder bei Schaltungen ...

Gruß
Dino
 
Hier hab ich auch schon alles abgegrast.
Für ASSEMBLER hätte ich ein fertiges Beispiel, aber damit komme ich nicht zurecht. Vor allem weil ich ja noch einiges dazubasteln möchte.
 
Hallo,

Hier hab ich auch schon alles abgegrast.
Für ASSEMBLER hätte ich ein fertiges Beispiel, aber damit komme ich nicht zurecht.
Geht es jetzt nur um eine 7-Segment-Anzeige oder um 2 oder mehr die im
Multiplex-Betrieb laufen sollen ? (Ich schätze mal letzteres ? )

Bei einer ist es einfach so als wenn du 7 LEDs ansteuern willst.

Bei mehreren ist der Multiplexbetrieb auch recht einfach ;) Es wird einfach
nacheinander Stelle für Stelle der anzuzeigenden Zahl an die Anzeige angelegt.

Gruß
Dino
 
Hallo,

nein, kein Multiplex.
Ein einziges stinknormales 7-Segmentteil.

So simpel wie du schreibst ist es wohl nicht.
 
nein, kein Multiplex.
Ein einziges stinknormales 7-Segmentteil.

Hallo,

wenn du eine Siebensegment-Anzeige statisch ansteuern möchtest, dann kannst du die Werte für die 7 Bits zum Beispiel in einem Array ablegen, das sich im Flash befindet. Wenn es sich um eine Stelle handelt, musst du deine Zählvariable o.ä. nichtmal in BCD-Teile zerlegen.

Beim GCC legst du das Array so an:

#include <avr/pgmspace.h>
const unsigned char Tabelle[] PROGMEM = {x0, x1, x2, x3, x4, ...x9}; // xn sind die Werte für die Segmente, die du am Port ausgibst.


Auf das Array greifst du so zu:

i = pgm_read_byte(&Tabelle[zahl]);
PORTn = i; // Display mit gem. Anode: 0 am Portpin -> Segment an


Schau dir auch vielleicht mal das GCC Tutorial bei den Kollegen vom Mikrocontroller.net an.

Dirk
 
Meinst du so?

Code:
//----------------------------------------
// Titel	: Arcade Tastenprogrammierung
//----------------------------------------
#include <avr/io.h>
#include <avr/pgmspace.h>

typedef unsigned char BYTE;
typedef unsigned int WORD;

BYTE bPortC;
BYTE nKeyPress;

const unsigned char Tabelle[] PROGMEM = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};

int main (void)
{

    PORTB = 0x01;	// Pull-Up Port B0 aktivieren
    DDRB = 0x01;	// Port B0 als Eingang
	DDRD = 0xFF;	// Port D als Ausgang

    bPortC = 1;	// Variable initialisieren
	nKeyPress = 1;


    while(1)
	{
		PORTD = pgm_read_byte(&Tabelle[3]);
	}
	return 0;
}

void Auswahl(void)
{
    if (bit_is_clear (PINC, PINC0))
	{
        if (bPortC)
		{
            nKeyPress++;
            bPortC = 0;
        }
    }
    else
	{
        bPortC = 1;
    }
}

Das bringt mir zwar etwas auf das Segment, aber keine Lesbaren zeichen.
 
Hallo Schatten!

Ich kann zwar nicht in C programmieren, aber ein wenig in BASCOM. ;)

Eigentlich gibt es im Internet auch Beispiele zum Ansteuern von Siebensegment-Anzeigen unter BASCOM......
OK, vielleicht keine fix und fertigen Lösungen, aber einige Hinweise! :cool:


Ich kann dir ja hier mal kurz beschreiben, wie ich es gemacht habe...
Allerdings ist es nur ein BEISPIEL und ich sage nicht, dass es die einzige oder gar ultimative Lösung ist!

Da A und O ist das Zerlegen der Zahlen, die du anzeigen möchtest.... wenn sie mal mehr als eine Stelle haben sollten.

In meinem Beispiel geht es um das Anzeigen einer Uhrzeit.
Rechts (neben den Doppelpunkten) sind die Minuten.
Links (neben den Doppelpunkten) sind die Stunden.
Beide Zahlen sind natürlich zweistellig und müssen daher in einzelne Ziffern zerlegt werden!

Das erledige ich hier mit:


CodeBox Bascom

Einer = Rechts Mod 10

Rechts = Rechts - Einer
Rechts = Rechts / 10

Zehner = Rechts Mod 10

'-------------------------

Hunderter = Links Mod 10

Links = Links - Hunderter
Links = Links / 10

Tausender = Links Mod 10


Die Variablen (Einer, Zehner, Hunderter & Tausender) bedeuten folgendes:

Einer sind die Minuten-Einer.
Zehner sind die Minuten-Zehner.

Hunderter sind die Stunden-Einer.
Tausender sind die Stunden-Zehner.

Nun hast du die Zahlen (jeweils zweistellig) in zwei einzelne Ziffern zerlegt.


Damit deine 7-Segmente auch nun etwas anzeigen können, musst du dir eine "Tabelle" schreiben.
Je nach Typ deiner Anzeigen (gemeinsame Kathode oder gemeinsame Anode) vermerkst du, welche Ausgänge auf High oder Low zu setzen sind.

Gehen wir mal von aus, du hast Anzeigen mit gemeinsamer Anode....

--a--
f ..... b
--g--
e ..... c
--d--

Um eine 1 anzeigen zu lassen müssen also: Segmente B und C auf Low geschaltet werden. Alle anderen beiben High !
Binär wäre es demnach: &B1111_1001 und in Hex ist es gleich: &HF9

Deine "Tabelle" hält dann also alle Ziffern in Hexadezimaler-Schreibweise bereit.
Beispiel:
Code:
Zahl_rechts:
Data &HC0 , &HF9 , &HA4 , &HB0 , &H99 , &H92 , &H82 , &HF8 , &H80 , &H90


Jetzt kommt der interessante Teil, denn du musst deine Ziffer in die Hex-Daten "umwandeln".
Dies geschieht z.B. mit einem "Lookup".
Siehe hier:


CodeBox Bascom

E = Lookup(einer , Zahl_rechts)
Z = Lookup(zehner , Zahl_rechts)
H = Lookup(hunderter , Zahl_rechts)
T = Lookup(tausender , Zahl_rechts)



Nun musst du nur noch den Port dazu veranlassen, die gewünschte Ziffer als Hex-Daten auszugeben.
Dies kannst du folgendermaßen realisieren:


CodeBox Bascom

Anzeigen:
Portc = T
Portd = H
Portb = Z
Porta = E



Tja, dass war es auch schon! :)
Jezt wird deine 7-Segment-Anzeige auch genau die Segmente leuchten lassen, die deine Ziffer ergeben.

Kleiner Tipp am Rande....
Du kannst (wie du in meinen Beispielen sehen kannst) das "Zerlegen", "Umwandeln" und "Anzeigen" deiner Ziffern ruhig in Subroutinen verpacken.
So musst du nur die Ziffern in die Variablen übergeben (Links & Rechts) und die Subroutinen nacheinander aufrufen. :)

Wie bei meiner Uhr..... zum Beispiel so:


CodeBox Bascom

Links = _hour
Rechts = _min

Gosub Zerlegen
Gosub Umsetzen
Gosub Anzeigen



Ich hoffe, auch wenn es nun in BASCOM gewesen ist, dass du das Prinzip verstanden hast.

Schöne Grüße,
Cassio
 
Danke Cassio für deine Mühe.
Muß mich jetzt jedoch auf irgendeine Sprache einigen.

Darum hab ich mal das Beispiel von Dirk weiterentwickelt und folgendermaßen zum laufen bekommen:

Code:
//----------------------------------------
// Titel	: Arcade Tastenprogrammierung
//----------------------------------------
#include <avr/io.h>
#include <avr/pgmspace.h>

typedef unsigned char BYTE;
typedef unsigned int WORD;

BYTE bPortB;
BYTE nKeyPress;

const unsigned char Tabelle[] PROGMEM = {249, 164, 176, 153, 146, 130, 248, 128, 144};

int main (void)
{

    PORTB = 0x01;	// Pull-Up Port B0 aktivieren
    DDRB = 0x01;	// Port B0 als Eingang
	DDRD = 0xFF;	// Port D als Ausgang

    bPortB = 1;	// Variable initialisieren
	nKeyPress = 0;


    while(1)
	{
		PORTD = pgm_read_byte(&Tabelle[nKeyPress]);
		if (bit_is_clear (PINB, PINB0))
		{
        	if (bPortB)
			{
            	
				if (nKeyPress < 8)
				{
					nKeyPress++;
					bPortB = 0;
				}
				else
				{
					nKeyPress = 0;
					bPortB = 0;
				}
        	}
    	}
    	else
		{
        	bPortB = 1;
    	}
	}
	return 0;
}

Der Taster zählt nun immer um einen Wert hoch.
Weiß nicht ob das die feine Lösung ist oder man das auch besser machen könnte. Vielleicht hat noch jemand einen Tip dazu.

Jetzt möchte ich noch die Funktion der Tastenzuordnung implementieren.

Also je nach Konfiguration soll zb:

Eingang 1 mit Ausgang 2 verbunden sein
Eingang 2 mit Ausgang 5 verbunden sein.
etc....

Kann mir da jemand einen Tip geben?
 
Hallo,

const unsigned char Tabelle[] PROGMEM = {249, 164, 176, 153, 146, 130, 248, 128, 144};[/CODE]

Jetzt möchte ich noch die Funktion der Tastenzuordnung implementieren.

Also je nach Konfiguration soll zb:

Eingang 1 mit Ausgang 2 verbunden sein
Eingang 2 mit Ausgang 5 verbunden sein.
etc....

Kann mir da jemand einen Tip geben?
Dann tippe ich mal ... Ein Tip ... ;)
Das kann man ganz genauso wie die Zuordnung der Segmente zu den Ziffern
auch mit einer Tabelle machen. Für jede Taste eine Tabelle und da steht drin
welcher Ausgang bei dem Tastendruck auf 1 gehen soll.

Und wenn man mehrere Einzelne Tabellenwerte (zB 000001, 010000, 000100)
wieder zu einem Wert zusammenfassen muß dann man das mit einer logischen
ODER-Funktion machen => Ergebnis bei den 3 Werten 010101 ;)

Genug Tip ? ;) Also einfach das was du für deine 7Segmente schonmal
gemacht hast für jede Taste auch nochmal machen.

Gruß
Dino
 
Kannst du mir ein Beispiel geben wie so eine Tabelle aussehen muß?

In Assembler hab ich dieses Beispiel gefunden:

Code:
    .db  0b11000000     ; 0: a, b, c, d, e, f
    .db  0b11111001     ; 1: b, c
    .db  0b10100100     ; 2: a, b, d, e, g
    .db  0b10110000     ; 3: a, b, c, d, g
    .db  0b10011001     ; 4: b, c, f, g
    .db  0b10010010     ; 5: a, c, d, f, g
    .db  0b10000010     ; 6: a, c, d, e, f, g
    .db  0b11111000     ; 7: a, b, c
    .db  0b10000000     ; 8: a, b, c, d, e, f, g
    .db  0b10010000     ; 9: a, b, c, d, f, g

Funktioniert das in C genauso?

Was ich noch gerne machen möchte ist, abzufragen ob die Taste kurz oder lang gedrückt wurde.
Weiß jemand wie man das anstellt?
 
Hallo,

Kannst du mir ein Beispiel geben wie so eine Tabelle aussehen muß?

In Assembler hab ich dieses Beispiel gefunden:

Code:
    .db  0b11000000     ; 0: a, b, c, d, e, f
    .db  0b11111001     ; 1: b, c
    .db  0b10100100     ; 2: a, b, d, e, g
    .db  0b10110000     ; 3: a, b, c, d, g
    .db  0b10011001     ; 4: b, c, f, g
    .db  0b10010010     ; 5: a, c, d, f, g
    .db  0b10000010     ; 6: a, c, d, e, f, g
    .db  0b11111000     ; 7: a, b, c
    .db  0b10000000     ; 8: a, b, c, d, e, f, g
    .db  0b10010000     ; 9: a, b, c, d, f, g

Funktioniert das in C genauso?
leider nicht. Aus dem einfachen Grund weil es zwei verscheidene Arten von
Tabellen sind. Das was du in Assembler gefunden hast ist eigentlich nur ein
Datenfeld im Speicher das über einen Zeiger angesprochen wird. Der Wert
wird dann über eine Adressierung mit den 16Bit-Registerpaaren X,Y oder Z
in ein Arbeitsregister geladen und dann weiterverwendet.

Du hast doch oben in deinem Programm schon eine Tabelle/Liste drin ...

const unsigned char Tabelle[] PROGMEM = {249, 164, 176, 153, 146, 130, 248, 128, 144};

Ich weiß jetzt nicht wie das in C geht aber im Prinzip holst du die Werte
doch in der Art ...

Wert = Tabellenname (Listenstelle)

aus der Tabelle raus. Ob jetzt mit eckigen oder was weiß ich für Klammern.
Das nennt sich in Perl zB assoziatives Array (glaube ich). Und die Listenstellen
fangen je nach Programmiersprache und Listentyp mit 0 oder 1 an. Also
entweder 0,1,2,3,4,... oder 1,2,3,4,5,... .

Was ich noch gerne machen möchte ist, abzufragen ob die Taste kurz oder lang gedrückt wurde.
Weiß jemand wie man das anstellt?
:confused: Wie willst du das dann auf die Ausgänge übertragen :confused:
Willst du 6 Tasten auf 6 verschiedene Ausgänge umsetzten und sagen welcher
der Ausgänge jetzt zu welcher Taste gehört oder willst du mit 6 Tasten
ne PS2-Tastatur für Gaming simulieren :confused: :confused:
Da wär jetzt glaube ich etwas mehr Info gut was du da genau vorhast ...

Gruß
Dino
 
Hi,
also den kurzen oder langen tastendruck möchte ich nur auf dieser einen taste abfragen:

Wird kurz gedrückt soll zur nächsten Ziffer gesprungen werden
Wird länger gedrückt, soll der aktuelle Wert im EEPROM gespeichert werden.

Die 6-Tasten sollen ohne weitere Funktion einfach nur auf beliebige Ausgänge durchgeschalten werden.

Ich hab schon mal ein wenig herumgebastelt und folgendes draus gemacht:
Passierend auf dem Beispiel von hier: Taster-Abfrage in C


Code:
//----------------------------------------
// Titel	: Arcade Tastenprogrammierung
//----------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include "taster.h"

typedef unsigned char BYTE;
typedef unsigned int WORD;

BYTE bPortB;
BYTE nKeyPress;
uint8_t eeFooByte;

volatile uint8_t gKeyCounter;
volatile signed char taster = NO_TASTER;
taste_t tasten[NUM_TASTER];

const unsigned char Tabelle[] PROGMEM = {249, 164, 176, 153, 146, 130, 248, 128, 144};

SIGNAL (SIG_OVERFLOW0)
{
    static unsigned char count_ovl0;
    unsigned char ovl0 = count_ovl0+1;

    if (ovl0 >= 39)
    {
        get_taster (1, PINB & (1<<PB4));
        ovl0 = 0;
    }
    count_ovl0 = ovl0;
}

void ioinit()
{
    PORTB |= 1 << PB4;
	DDRD = 0xFF;
    TCCR0 = 1 << CS00;
    TIMSK |= (1 << TOIE0);
}

int main (void)
{
    ioinit();
	
	bPortB = 1;
	nKeyPress = 0;
	// nKeyPress = eeprom_read_byte(&eeFooByte);
	gKeyCounter = 0;

    tasten[0].mode = TM_SHORT;
    tasten[1].mode = TM_LONG;
    tasten[2].mode = TM_REPEAT;

    while(1)
	{
        signed char tast = taster;
		PORTD = pgm_read_byte(&Tabelle[nKeyPress]);

 		switch (tast)
        {
            default:
            case NO_TASTER:
                break;
    
            case 1:
				if (nKeyPress < 8)
				{
					nKeyPress++;
				}
				else
				{
					nKeyPress = 0;
				}
                break;
    
            case 1+TASTER_LONG:
                eeprom_write_byte(&eeFooByte, nKeyPress);
                break;
        }
        if (tast != NO_TASTER)
            taster = NO_TASTER;
	}
	return 0;
}

void get_taster (const unsigned char num, unsigned char tast) 
{
    const taste_t * const ptast = & tasten[num];
    const unsigned char taster_old = ptast->old;
    unsigned char pressed, press, release, mode, delay;

#if TASTER_LEVEL
    tast = !!tast;
#else
    tast = !tast;
#endif

    /* Taster bleibt gedrueckt */
    pressed =  taster_old &  tast;
    /* Taster neu gedrueckt */
    press   = ~taster_old &  tast;
    /* Taster losgelassen */
    release =  taster_old & ~tast;

    *((unsigned char *) & ptast->old) = tast;
 
    tast = NO_TASTER;
 
    mode  = ptast->mode;
    delay = ptast->delay;
 
    if (press)
    {
        if (mode != TM_LONG)
            tast = num;
   
        delay = 0;
    }
    else if (pressed)
    {
        if (delay < 0xfe)
            delay++;
    }
    else if (release)
    {
        if (mode == TM_LONG && delay != 0xff)
            tast = num;
    }
 
    if (mode == TM_LONG)
    {
        if (delay == TASTER_DELAY_LONG)
        {
            tast = TASTER_LONG + num;
            delay = 0xff;
        }
    }
    else if (mode == TM_REPEAT)
    {
        if (delay == TASTER_REPEAT_DELAY)
        {
            tast = num;
            delay = TASTER_REPEAT_DELAY - TASTER_REPEAT;
        }
    }

    if (taster == NO_TASTER)
        taster = tast;
  
    *((unsigned char *) & ptast->delay) = delay;
}


Leider ist da noch irgendwo ein Hund begraben. Den beim tastendruck passiert nichts. Mir ist nicht ganz klar wo der Fehler liegt.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)