Forum: Mikrocontroller und Digitale Elektronik LED Matrix | Atmega8 | C


von Timo B. (troxan)


Lesenswert?

Guten Tag,
ich bin noch recht frisch in C und versuche mich gerade an der 
Programmierung einer kleinen selbsgebastelten 6x6 LED-Matrix.
Der Aufbau ist so einfach wie möglich gehalten, keine Schieberegister, 
keine Transistoren nur Widerstände.
Die Kathoden laufen mit Widerstand auf PB0-5 und die Anoden auf PD2-7.

Die ersten versuche LED's anzusteuern sind auch geglückt, jedoch ist die 
Programmierung noch sehr unschön.

Bspl. Buchstabe "H"
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
int main(void)
5
{
6
 int t; 
7
 t = 5; // Delay
8
9
 DDRD = 0xFF; // Spalten als Ausgang
10
 DDRB = 0xFF; // Zeilen als Ausgang
11
12
while(1)
13
{
14
  PORTD = 0b00000100;
15
  PORTB = 0b11111111;
16
  _delay_ms(t);
17
18
  PORTD = 0b00001000;
19
  PORTB = 0b11000001;
20
  _delay_ms(t);
21
22
  PORTD = 0b00010000;
23
  PORTB = 0b11110111;
24
  _delay_ms(t);
25
26
  PORTD = 0b00100000;
27
  PORTB = 0b11110111;
28
  _delay_ms(t);
29
30
  PORTD = 0b01000000;
31
  PORTB = 0b11000001;
32
  _delay_ms(t);
33
34
  PORTD = 0b10000000;
35
  PORTB = 0b11111111;
36
  _delay_ms(t);
37
38
    }
39
}

Jetzt würde ich gerne Programmiertechnisch das ganze einen kleinen 
Schritt weiter führen und den Buchstaben in einem Array abspeichern und 
animieren, so das er von rechts nach links über die Matrix wandert.

Mir fällt es leider schwer passende Beispiele zu finden, da die meisten 
für Arduinos Programmiert sind und ich mir mit der anderen Schreibweise 
ein wenig schwer tue.
Andere Beispiele sind nur darauf ausgelegt das man sie 1 zu 1 für seine 
Matrix übernehmen kann und sind mit ettlichen für mich noch unnötigen 
Funktionen aufgbelasen.

Ich stehe gerade aber etwas auf dem Schlauch und weiß nicht wie ich am 
besten vorgehen soll. Ich würde mich über Tips und ggf. über einfache 
Beispiele freuen.
Das Beispiel bräuchte nicht an meine Matrix angepasst sein, es sollte 
nach möglichkeit nur so simpel wie möglich aufgezogen sein.
Für den Anfang würde es mir vermutlich schon helfen, die Darstellung 
eines Buchstabens oder sonst eines "Bildes" über ein Array ausgegeben zu 
sehen.


Viele Grüße
Timo

von Karl M. (Gast)


Lesenswert?

Timo B.,

Warum nur einen atmega8 ? das ist die alte Garde.

von MaWin (Gast)


Lesenswert?

Timo B. schrieb:
> Mir fällt es leider schwer passende Beispiele zu finden

Na ja, das nennt man Programmieren.

Du hast bereits alles was man braucht, sozusagen den ganzen Legokasten 
gefüllt mit Teilen. Du musst sie bloss noch zusammensetzen.

Am Ende der Schleife, nach dem ein Buchstabe ein mal dargestellt wurde, 
nicht unbedingt jedes mal sondern vielleicht jedes 33. mal also 
sekündlich, kannst du ein wenig zusätzliche Arbeit tun um den nächsten 
Buchstaben darzustellen, oder diesen etwas verschoben darzustellen.

Natürlich greifen dann deine 0b Konstanten für PORTB nicht mehr auf 
Konstanten zu sondern variable Werte, die du am Ende der Schleife 
passend geupdatet hast.

von Timo B. (troxan)


Lesenswert?

Ich habe auf ebay günstig ein MyAVR Board bekommen, da war der bei.
Ich dachte mir für die ersten Schritte mit µC ist der Ok.
Genau genommen ist es ein Atmega8A-PU, ich kenne mich mit den Modellen 
nicht so gut aus, aber ich glaube der ist etwas neuer.

Gruß
Timo

von Wolfgang (Gast)


Lesenswert?

Timo B. schrieb:
> Genau genommen ist es ein Atmega8A-PU, ich kenne mich mit den Modellen
> nicht so gut aus, aber ich glaube der ist etwas neuer.

Auch das würde z.B. an der Größe des verfügbaren Speichers nichts 
ändern.

von MaWin (Gast)


Lesenswert?

Timo B. schrieb:
> Ich dachte mir für die ersten Schritte mit µC ist der Ok.

Er reicht jedenfalls nicht bloss zur Darstellung eines Buchstabens auf 
einer 6 x 6 Matrix, sondern eines ganzen Terminbildschirms (40 x 24?) 
auf einem TV (also mit 50Hz wiederholtes BAS Signal), wenn man 
programmieren kann.

Das kann Karl wohl nicht.

Einfacher würde man es sich mit einem Arduino machen.

Das kann auch Wolfgang.

von MaWin (Gast)


Lesenswert?

Achso, den wollte ich mitliefern
https://www.youtube.com/watch?v=zP_7qus4aac

von Timo B. (troxan)


Lesenswert?

Danke schon mal für die Antworten,
mein aktueller Stand der Dinge sieht wie folgt aus.

1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
int main(void)
5
{
6
 int t,i;
7
 t = 5;
8
 
9
 DDRD = 0xFF; // Spalten auf Ausgang
10
 DDRB = 0xFF; // Zeilen auf Ausgang
11
12
13
14
15
  char Zeilen[6] = { // H
16
        0b11111111, // °°°°°°
17
        0b11000001, // *****°
18
        0b11110111, // °°*°°°
19
        0b11110111, // °°*°°°
20
        0b11000001, // *****°
21
        0b11111111};// °°°°°°
22
23
24
  char Spalten[6] = {  
25
        0b00000100, // Spalte 1
26
        0b00001000,
27
        0b00010000,
28
        0b00100000,
29
        0b01000000,
30
        0b10000000}; // Spalte 6
31
32
33
34
    while(1)
35
    {
36
    for(i=0; i<=5; i++)
37
    {
38
      PORTD = Spalten[i];
39
      PORTB = Zeilen[i];
40
      _delay_ms(t);
41
    }
42
43
    }
44
}

Animiert ist noch nichts, aber zumindest bekomme ich den Buchstaben 
schon mal über ein Array ausgegeben.

Gruß
Timo

von Dirac Impuls (Gast)


Lesenswert?

Als erstes solltest du die Spalten per Interrupt nacheinander aufrufen.

Danach kannst du eine Funktion schreiben, z.B. LED_on(int x, int y) und 
LED_off(int x, int y), welche in das Zeilenarray schreibt.

Wenn das funktioniert, kannst du in der while Schleife deine gewünschte 
Animation zur Not mit der Delay Funktion realisieren.

von Dirac Impuls (Gast)


Lesenswert?

... der erste Satz war falsch formuliert: Den gesamten Bildaufbau 
solltest du nur im Interrupt machen. Die Animation dann in der while 
Schleife.

von Frank G. (frank_g53)


Lesenswert?

Timo B. schrieb:
> Ich würde mich über Tips und ggf. über einfache
> Beispiele freuen.

Vielleicht kannst du dir hier was abschauen:
http://www.elo-web.de/elo/mikrocontroller-und-programmierung/ping-pong/laufschrift

von Timo B. (troxan)


Lesenswert?

Danke,
ich bin mir noch nicht sicher ob ich es ganz verstanden habe, aber ich 
werde morgen mal versuchen das so umzusetzen.
Warum die Interruptroutine?

Gruß
Timo

von Dirac Impuls (Gast)


Lesenswert?

Weil der Bildaufbau ja eigentlich ein Hintergrund- oder Nebenprogramm 
ist und es unabhängig davon ist was du eigentlich für ein Bild ausgeben 
willst.

Danach hast du eine leere while(1){} Schleife und kannst dort angeben, 
was du eigentlich auf der Matrix ausgegeben willst und kannst zu jedem 
Zeitpunkt die jede beliebige LED ein- oder ausschalten. Somit kommt sich 
der Bildaufbau und die Animation nicht blöd in die Quere.

von Ralph S. (jjflash)


Lesenswert?

... auch wenn du scheinbar eine 5x6 Matrix verwendest könnte dir mein 
Post von einer 5x7 Matrix helfen.

Vor einiger Zeit habe ich das hier gepostet:

Beitrag "LED Dot-Matrix 5x7 Mäxle-Würfelspiel / 2er Würfel"

Das ist zwar ein Würfelspiel auf einer LED-Matrix, sie kann aber auch 
Buchstaben darauf ausgeben und es wird gezeigt, wie die Matrix mittels 
Timerinterrupt angesteuert wird.

Der Quellcode sollte ausreichend dokumentiert sein.

Eine Änderung mußt du hier allerdings machen:

Der ATMega8 hat kein  TIMSK1 - Register, sondern lediglich ein  TIMSK - 
Register, daher mußt du in der Funktion
1
void timer1_init(void)
2
{
3
  TCCR1B = 1<<WGM12 | 1<<CS10;
4
  OCR1A = F_CPU / t1reload;
5
  TCNT1 = 0;
6
7
  TIMSK1 = 1<<OCIE1A;
8
  sei();
9
}

TIMSK1 durch TIMSK ersetzen:
1
TIMSK = 1 << OCIE1A;

Einen Buchstaben kannst du hier mit:
1
d57_ascii('h');

darstellen.

Gruß, Ralph

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich frage gerade die Tastatur eines alten 4-Kanal Mulittrackers ab und 
lasse seine 7 Segments und LED leuchten.
Hier liegt eine 7*8 Matrix vor mit 4 extra Leitungen für die Buttons.

Meine ISR mit Timer0 (wird alle 2ms gezündet) auf dem Mega8 sieht so 
aus:
1
// there are 2 Latches data wired to Port B and latched through PortD
2
// PORTD
3
#define CONTROL_PORT PORTD
4
#define CONTROL_DIR DDRD
5
#define CONTROL_PIN PIND
6
#define COL_LATCH 7
7
#define ROW_LATCH 6
8
#define OE_PIN 5
9
// PORTB
10
#define DATA_PORT PORTB
11
// PORTC lower 4 bits are the keyboard return bits
12
#define KEY_PORT PORTC
13
#define KEY_PINS PINC
14
#define KEY_DIR DDRC
15
#define KEY_MASK 0x0F
16
17
// matrix variables for in and output
18
19
volatile uint8_t charbuff[7];
20
volatile uint8_t keybuff[7];
21
22
void set_row(uint8_t data) {
23
DATA_PORT = ~(data);  // invert bits for negative logic
24
_delay_us(2);
25
CONTROL_PORT |= (1 << ROW_LATCH);
26
_delay_us(2);
27
CONTROL_PORT &= ~(1 << ROW_LATCH);
28
_delay_us(2);
29
}
30
void set_col(uint8_t data) {
31
DATA_PORT = data;
32
_delay_us(2);
33
CONTROL_PORT |= (1 << COL_LATCH);
34
_delay_us(2);
35
CONTROL_PORT &= ~(1 << COL_LATCH);
36
_delay_us(2);
37
}
38
// multiplexer routine for Fostex Panel
39
// reads charbuff and sets keybuff
40
ISR(TIMER0_OVF_vect) {
41
static uint8_t col = 0x01;
42
static uint8_t row = 0;
43
// reading is not perfect, will implement PeDas debounce next
44
keybuff[i] = ~(KEY_PINS) & KEY_MASK; // first read keys from Fostex Panel
45
CONTROL_PORT |= (1 << OE_PIN);     // prevent ghosting by disabling Latch output
46
_delay_us(2);   // let OE settle
47
set_col(col);  // set the column
48
set_row(charbuff[row]);
49
_delay_us(2);
50
CONTROL_PORT &= ~(1 << OE_PIN);  // enable latches again 
51
col = (col << 1) & 0xFE;  // lets wander through the bits and make sure of a clear LSB
52
row++;          // prepare the next scan
53
// limit the matrix to 7 columns
54
if (col == 0x80) {
55
  col = 0x01; 
56
  row = 0;
57
  }
58
}
Der Mega 8 hat hier viel zu wenig Ports, deswegen habe ich 2 '573er 
Latches. Das Prinzip bleibt aber das gleiche. Ich lasse eine '0x01' von 
rechts nach links durch die Spalten wandern und setze entsprechend die 
Segmenttreiber. Gesetzt wird dabei das Bytemuster in charbuff[].

: Bearbeitet durch User
von Timo B. (troxan)


Lesenswert?

Danke für die Antworten,
ich habe versucht den Code von Matthias Sch. soweit wie möglich runter 
zu brechen, bekomme es aber bisher nicht hin.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define COL_LATCH 6
5
#define ROW_LATCH 6
6
7
8
volatile uint8_t charbuff[6]={ // Bild // PORTB // 0-5 + /0
9
10
0b11111111, // °°°°°°
11
0b11000001, // *****°
12
0b11110111, // °°*°°°
13
0b11110111, // °°*°°°
14
0b11000001, // *****°
15
0b11111111};// °°°°°°
16
17
void set_row(uint8_t data) { 
18
PORTB = data;  // 'Bild'
19
}
20
21
void set_col(uint8_t data) { 
22
PORTD = data;
23
}
24
25
ISR(TIMER0_OVF_vect) // alle 2ms zünden
26
{
27
static uint8_t col = 0x02; // Start bei PD2
28
static uint8_t row = 0; // Start bei Feld 0
29
30
set_col(col); 
31
set_row(charbuff[row]);
32
33
col = (col << 1);  // eine Spalte weiter
34
row++; // ein Feld weiter         
35
36
if (col == 0x07) { // Nach der 6ten Spalte wieder zum Anfang springen 2-7
37
  col = 0x02; 
38
  row = 0;
39
  }
40
}
41
42
int main(void)
43
{
44
while(1)
45
{
46
47
}
48
}

Ob der Code theoretisch funktionieren würde weiß ich noch nicht, bisher 
bekomme ich folgende Warnungen:
1
Build started 2.8.2016 at 17:58:05
2
avr-gcc  -mmcu=atmega8 -Wall -gdwarf-2 -std=gnu99 -DF_CPU=1000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT LED_Matrix_Interrupt.o -MF dep/LED_Matrix_Interrupt.o.d  -c  ../LED_Matrix_Interrupt.c
3
4
../LED_Matrix_Interrupt.c:26: warning: return type defaults to 'int'
5
../LED_Matrix_Interrupt.c: In function 'ISR':
6
../LED_Matrix_Interrupt.c:26: warning: type of '__vector_9' defaults to 'int'
7
../LED_Matrix_Interrupt.c:40: warning: control reaches end of non-void function
8
9
avr-gcc -mmcu=atmega8 -Wl,-Map=LED_Matrix_Interrupt.map LED_Matrix_Interrupt.o     -o LED_Matrix_Interrupt.elf
10
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  LED_Matrix_Interrupt.elf LED_Matrix_Interrupt.hex
11
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex LED_Matrix_Interrupt.elf LED_Matrix_Interrupt.eep || exit 0
12
avr-objdump -h -S LED_Matrix_Interrupt.elf > LED_Matrix_Interrupt.lss
13
14
AVR Memory Usage
15
----------------
16
Device: atmega8
17
18
Program:     166 bytes (2.0% Full)
19
(.text + .data + .bootloader)
20
21
Data:          9 bytes (0.9% Full)
22
(.data + .bss + .noinit)
23
24
25
Build succeeded with 3 Warnings...

Gruß
Timo

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Timo B. schrieb:
> if (col == 0x07) { // Nach der 6ten Spalte wieder zum Anfang springen
> 2-7

Nee, diese Bedingung wird nie erfüllt, denn du schiebts ja nur ein bit 
durch.
Es fängt an mit 0x02 = 0b00000010
das nächste ist 0x04 = 0b00000100
dann kommt      0x08 = 0b00001000
usw.
das letzte ist  0x80 = 0b10000000

danach wird das bit rausgeschoben und col ist 0.

also sollte die Bedingung heissen:
1
if (col == 0) {
2
 col = 0x02; 
3
 row = 0; 
4
 }
Es steht dir auch frei, row als Abbruchbedingung zu nehmen, dann würdest 
du auf 'if (row > 5)' abfragen.

Übrigens musst du natürlich den Timer initialisieren, sonst kommt da nie 
ein Interrupt.
Sowas hier sollte es tun, etwa 480 Hz Wiederholrate bei 1Mhz:
1
// rate at 488 Hz @ 1Mc
2
void init_timer0(void) {
3
TCNT0 = 0;
4
TCCR0 = (1 << CS01) ; // div 8 prescale
5
TIMSK = (1 << TOIE0);  // Timer 0 IRQ Freigabe
6
}
7
// und dann im Hauptprogramm noch ein
8
sei(); // alle IRQ freigeben
9
// vor die Hauptschleife

: Bearbeitet durch User
von Timo B. (troxan)


Lesenswert?

Vielen Dank es funktioniert jetzt :)

Ich hatte erst ein wenig Probleme den Timer richtig einzubinden, ich 
hatte zu beginn
1
void init_timer0(void) {
2
TCNT0 = 0;
3
TCCR0 = (1 << CS01) ; // div 8 prescale
4
TIMSK = (1 << TOIE0);  // Timer 0 IRQ Freigabe
5
}
genau so, außerhalb der main Funktion eingefügt, das hat jedoch nicht 
funktioniert.
Außerdem fehlten noch Sachen wie die Definition der Ausgänge und die 
Einbindung der header-Datei für die Interrupts.

Hier noch der aktuelle Code.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
#define COL_LATCH 6
6
#define ROW_LATCH 6
7
8
9
volatile uint8_t charbuff[6]={ // Bild // PORTB // 0-5 + /0
10
11
0b11111111, // °°°°°°
12
0b11000001, // *****°
13
0b11110111, // °°*°°°
14
0b11110111, // °°*°°°
15
0b11000001, // *****°
16
0b11111111};// °°°°°°
17
18
void set_row(uint8_t data) 
19
{ 
20
  PORTB = data;  // 'Bild'
21
}
22
23
void set_col(uint8_t data) 
24
{ 
25
  PORTD = data;
26
}
27
28
29
30
ISR(TIMER0_OVF_vect) 
31
{
32
  static uint8_t col = 0b00000100; // Start bei PD2
33
  static uint8_t row = 0; // Start bei Feld 0
34
35
  set_col(col); 
36
  set_row(charbuff[row]);
37
38
  col = (col << 1);  // eine Spalte weiter
39
  row++; // ein Feld weiter         
40
41
  if (row > 5) 
42
  {
43
    col = 0b00000100; 
44
    row = 0; 
45
  }
46
}
47
48
int main(void)
49
{
50
  DDRB = 0xFF; // Bild
51
  DDRD = 0xFF; // Spalten
52
53
  TCNT0 = 0;
54
  TCCR0 = (1 << CS01) ; // div 8 prescale
55
  TIMSK = (1 << TOIE0); 
56
  sei(); // Initialisieren der Interruptroutine
57
58
59
  while(1)
60
  {
61
62
  }
63
}
64
65
Mein nächster Schritt soll jetzt eine kleine Animation mit dem Buchstaben werden.
66
67
Gruß
68
Timo

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Timo B. schrieb:
> hatte zu beginn void init_timer0(void) {
> TCNT0 = 0;
> TCCR0 = (1 << CS01) ; // div 8 prescale
> TIMSK = (1 << TOIE0);  // Timer 0 IRQ Freigabe
> }
> genau so, außerhalb der main Funktion eingefügt, das hat jedoch nicht
> funktioniert.

Ja, das ist ein Unterprogramm. Man ruft es dann mit 'init_timer0();' aus 
dem Hauptprogramm auf.
Mit diesem grundlegenden Konzept solltest du dich beschäftigen.

> #define COL_LATCH 6
> #define ROW_LATCH 6

Das brauchst du nicht - kannste löschen.

: Bearbeitet durch User
von Timo B. (troxan)


Lesenswert?

Hat evtl. jmd. einen kleinen Tip zur animation für mich?
Ich bastel seit Stunden herum, aber außer viel gelöschtem Code ist noch 
nichts dabei herum gekommen.
In den meisten Fällen passiert garnichts oder der Delay kommt der 
Interruptroutine in die Quere.

Mein erster Gedanke dazu war, den über den Array ausgegeben Wert, über 
eine variable Bitverschiebung (i) zu ändern und den Vorgang zusammen mit 
einem delay() in der while-Schleife zu wiederhohlen.
Dabei passiert aber nichts.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
volatile uint8_t charbuff[6]={ // Bild // PORTB // 0-5 + /0
6
7
0b11111111, // °°°°°°
8
0b11000001, // *****°
9
0b11110111, // °°*°°°
10
0b11110111, // °°*°°°
11
0b11000001, // *****°
12
0b11111111};// °°°°°°
13
14
int i=0;  // <--------------------------
15
16
void set_row(uint8_t data) 
17
{ 
18
  PORTB = data;  // 'Bild'
19
}
20
21
void set_col(uint8_t data) 
22
{ 
23
  PORTD = (data<<i); // <--------------------------
24
}
25
26
// rate at 488 Hz @ 1Mc
27
void init_timer0(void) {
28
TCNT0 = 0;
29
TCCR0 = (1 << CS01) ; // div 8 prescale
30
TIMSK = (1 << TOIE0);  // Timer 0 IRQ Freigabe
31
}
32
33
34
ISR(TIMER0_OVF_vect) 
35
{
36
  static uint8_t col = 0b00000100; // Start bei PD2
37
  static uint8_t row = 0; // Start bei Feld 0
38
39
  set_col(col); 
40
  set_row(charbuff[row]);
41
42
  col = (col << 1);  // eine Spalte weiter
43
  row++; // ein Feld weiter         
44
45
  if (row > 5) 
46
  {
47
    col = 0b00000100; 
48
    row = 0; 
49
  }
50
}
51
52
int main(void)
53
{
54
  DDRB = 0xFF; // Bild
55
  DDRD = 0xFF; // Spalten
56
57
  init_timer0();
58
  sei(); // Initialisieren der Interruptroutine
59
60
61
  while(1)
62
  {
63
  i++; // <--------------------------
64
  _delay_ms(1000); // <--------------------------
65
  }
66
}

Gruß
Timo

von Dirac Impuls (Gast)


Lesenswert?

Timo B. schrieb:
> while(1)
>   {
>   i++; // <--------------------------
>   _delay_ms(1000); // <--------------------------
>   }

Die beiden Zeilen hättest du dir in dem aktuellen Programm sparen 
können. Was soll es bringen eine sonst nicht verwendete Variable nach 
oben zu zählen?

Probier doch mal sowas:
1
volatile uint8_t charbuff[6]={ 0,0,0,0,0,0 }
2
3
// ...
4
// ...
5
6
while(1)
7
  {
8
charbuff[i]++;
9
  i++; // <--------------------------
10
  _delay_ms(1000); // <--------------------------
11
if(i==6) i=0;
12
  }

von Timo B. (troxan)


Lesenswert?

Danke für die ANtwort,
ich habe versucht i nach oben zu zählen, damit ich eine Bitverschiebung 
durchführen kann.
1
while(1)
2
  {
3
  i++; // <--------------------------
4
  _delay_ms(1000); // <--------------------------
5
  }
1
void set_col(uint8_t data) 
2
{ 
3
  PORTD = (data<<i); // <--------------------------
4
}

Ich sehe aber gerade das ich oben quatsch geschrieben habe, nicht das 
Array wird verschoben sondern die Spalten.
Entschuldigt das war ein früher Versuch mit dem Array, bis ich gemerkt 
habe das der Buchstabe dann nach oben wandern würde, anstatt nach links 
oder rechts. :)

Der von dir genannte Code erschließt sich mit nicht ganz, aber das wird 
wohl an meiner Fehlinformation liegen.
Er zählt zwar irgendetwas aber es ist definitiv kein "H" mehr welches 
angezeigt wird. :D

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du kannst das ganze synchronisieren, wenn du in die Hauptschleife eine 
Routine einbaust, die auf den Timeroverflow IRQ wartet:
1
// wait for the timer 0 ovf event 
2
void timerWait(void) {
3
 TIFR = (1<<TOV0);
4
 while (!(TIFR & (1 << TOV0)));
5
}
6
// und dann in der Hauptschleife:
7
8
// hauptschleife wird mit etwa 488 Hz durchlaufen
9
// synchronisiert von Timer 0
10
uint8_t ticker;
11
while (1) {
12
//  
13
       timerWait(); // wait for the ISR 
14
// jetzt könnte man bequem ein neues Muster in den displaybuffer kopieren
15
// hier mit etwa 10 bildern pro Sekunde. 
16
       ticker++;
17
       if (ticker > 49) {
18
                 copynextpattern();    
19
                 ticker = 0;
20
            }
21
     }

Als nächstes brauchst du Daten, z.B. ein animiertes Bildchen, das du in 
einzelne Frames, nach dem gleichen Muster wie den charbuff, aufbaust.
Die Frames kopierst du dann in den displayspeicher.

: Bearbeitet durch User
von Dirac Impuls (Gast)


Lesenswert?

Timo B. schrieb:
> Der von dir genannte Code erschließt sich mit nicht ganz, aber das wird
> wohl an meiner Fehlinformation liegen.

Ich hatte nicht gesehen, dass i noch woanders verwendet wird und hatte 
den Code vorgeschlagen, um überhaupt mal irgendetwas zu sehen.

Ich finde die aktuelle Verwendung von i konzeptionell falsch. Die beiden 
Funktionen set_row und set_col brauchst du nicht. Eine Funktion mit 
einer Zeile Code, die nur einmalig aufgerufen wird, macht das ganze 
nicht viel übersichtlicher.

Meine Empfehlung: Die ISR sollte ausschließlich auf das charbuff Array 
und der Spaltenzählvariable zugreifen. Ein i wird dafür nicht gebraucht. 
In der main Funktion kannst du dann dein charbuff Array bearbeiten. 
Außerdem sollte man die LED Matrix vielleicht um 90° drehen, damit man 
den Buchstaben 'H' auch in dem Quellcode wiedererkennt. Bisher sieht die 
Initialisierung des charbuff ja eher aus wie ein 'I'.


So sieht das ganze doch schon viel übersichtlicher aus und sollte 
funktionieren:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
volatile uint8_t charbuff[6]={ // Bild // PORTB // 0-5 + /0
6
7
0b11111111, // °°°°°°
8
0b11000001, // *****°
9
0b11110111, // °°*°°°
10
0b11110111, // °°*°°°
11
0b11000001, // *****°
12
0b11111111};// °°°°°°
13
14
15
16
17
18
// rate at 488 Hz @ 1Mc
19
void init_timer0(void) {
20
TCNT0 = 0;
21
TCCR0 = (1 << CS01) ; // div 8 prescale
22
TIMSK = (1 << TOIE0);  // Timer 0 IRQ Freigabe
23
}
24
25
26
ISR(TIMER0_OVF_vect) 
27
{
28
  static uint8_t row = 0; // Start bei Feld 0
29
30
  PORTD = 0;  // Kurzzeitig alle LEDs aus, damit keine LED ungewollt leicht dimmt
31
  PORTB = charbuff[row];  // Setze Spalten-LEDs
32
  PORTD = 1<<(row+2); // Start bei PD2, schalte LEDs der aktuellen Zeile
33
34
  row++; // ein Feld weiter     
35
  if (row > 5) 
36
  {
37
    row = 0; 
38
  }
39
}
40
41
int main(void)
42
{
43
  int i;
44
  DDRB = 0xFF; // Bild
45
  DDRD = 0xFF; // Spalten
46
47
  init_timer0();
48
  sei(); // Initialisieren der Interruptroutine
49
50
51
  while(1)
52
  {
53
  _delay_ms(1000); // <--------------------------
54
  for(i=0;i<5;i++)
55
  {
56
    charbuff[i]=charbuff[i+1];
57
  }
58
  charbuff[5]=0b11111111;
59
  }
60
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.