Jackeder
02.08.2017, 11:25
Hallo zusammen,
ich hab mir vor einiger Zeit ein Matrix-LED-Display zusammen gebaut aus 4 5x7 Matrixmodulen. Den Schaltplan und Quelcode hab ich aus dem Buch "AVR Hardeware und C-Programmierung in der Praxis" von Florian Schäffer.
Der Quelcode funktioniert und ist für mich, als Anfänger, einfach und zu verstehen.
/************************************************** *
* Textausgabe auf 4 LED Modulen am Atmega 8 *
* 5x7 Matrixmodule mit gemeinsamer Anode *
* angesteuert über ULN2003A an PortB PB0 - PB6 *
* Multiplexing über 3 Schieberegister 74HCT164 *
* PC4 --> Bit setzen ; PC5 --> Tackt schieben *
* *
* Created: 13.02.2016 18:23:54 *
* Author: Hendrik *
************************************************** */
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "charset.h" // beinhaltet Zahlen, keine und große Buchstaben sowie Sonderzeichen
#include "lcd-routines.c"
void set_row (uint8_t);
void write_row (uint8_t);
int main (void);
#define DISPCOLS 20 // Anzahl der Spalten
#define MEMCOLS 200 // Displayspeicher fuer 200 Spalten reservieren (>= 6 x Anzahl der Zeichen in Zeichenkette + 2 x DISPCOLS)
#define CHARWIDTH 5 // Spalten je Zeichen
#define CHARHEIGHT 7 // Zeilen je Zeichen
#define DELAY 50 // Textgeschwindigkeit (ca. 10..200: schnell..langsam)
volatile uint8_t memory[DISPCOLS]; // Speicher für Display, spaltenweise orientiert, Index 0=links
volatile uint8_t pos=0; // ab welcher Speicherposition soll dargestellt werden
volatile uint8_t zeile=0; // Zeilenzähler welche Zeile aktuell ist
volatile uint8_t durchlauf=0; // Anzahl der Durchlaeufe
volatile uint8_t chars=0; // Anzahl der Zeichen in Zeichenkette
// *** Textausgabe ***
uint8_t text[]= " Hallo Roboternetz "; // Zeichenkette Ausgabe
void set_row (uint8_t row)
{
int8_t i;
// Alle Spalten des Displays durchlaufen. Mit rechter Spalte beginnen
for (i = DISPCOLS-1; i>=0; i--)
{
// Bit in der Spalte + Verschiebungswert pos an der übergebenden Zeile gesetzt?
if ((memory[i+pos] >> (6-row)) & 1) //
{
PORTC |= (1 << PC4); // Data Bit setzen
}
else
{
PORTC &= ~(1 << PC4); // Data Bit löschen
}
PORTC |= (1 << PC5); // Takt HIGH -> Flanke
PORTC &= ~(1 << PC5); // Takt LOW
}
}
void write_row (uint8_t row)
{
PORTB = 0; // alle Zeilen aus
set_row (row); // Daten für aktuelle Zeile in Schieberegister schieben
PORTB = (1 << row); // aktuelle Zeile an
}
int main()
{
lcd_init();
uint8_t i, row;
DDRC |= (1 << DDC4) | (1 << DDC5); // PC4, PC5 als Ausgang
PORTC &= ~((1 << PC4) | (1 << PC5)); // PC4, PC5 aus
DDRB = 0xFF; // PortB als Ausgang
PORTB = 0; // PortB aus
// Leerspalten am Anfang, damit Text von rechts kommt
for (row=0; row<DISPCOLS; row++)
memory[row]=1; // Eigentlich 0 aber für besseres Verständnis 1, damit eine LED leuchtet
// Zeichenkette in Spaltenbeschreibung umsetzen
while (text[chars] != 0) // solange Zeichen in Zeichenkette
{
memory[row]=charset[text[chars]-32][0]; row++; // aktuelle Spalte = 1. Spalte des Fonts
memory[row]=charset[text[chars]-32][1]; row++; // aktuelle Spalte = 2. Spalte des Fonts
memory[row]=charset[text[chars]-32][2]; row++; // usw.
memory[row]=charset[text[chars]-32][3]; row++;
memory[row]=charset[text[chars]-32][4]; row++;
memory[row]=0; row++; // Leerspalte: Abstand zwischen 2 Buchstaben
chars++; // Anzahl der Zeichen zählen
}
// Leerspalten am Ende, damit Textende aus Display geschoben wird
for (i=0; i<DISPCOLS; i++)
memory[i+row]=1; // Eigentlich 0 aber für besseres Verständnis 1, damit eine LED leuchtet
OCR1A = (uint16_t)(F_CPU/1024.0*0.003); // Vergleichwert für 0,003s laden: Takt= 8MHz/1024 = 7812,5 Zählerschritte pro s
TIMSK |= (1<<OCIE1A); // Interrupt wenn Timer Vergleichswert erreicht
TCCR1B |= (1<<CS12) | (1<<CS10) | (1<<WGM12); // Timer mit Div 1024 starten und Clear Counter on Compare Match
sei();
lcd_clear();
lcd_setcursor(0,1);
lcd_string("20x7 LED Matrix Text");
lcd_setcursor(3,3);
lcd_string("Hallo Thomas!");
while(1)
{
asm volatile ("nop"); // nichts machen
}
return 0;
}
// Wird vom 16 Bit Timer ausgelöst, wenn dieser den Vergleichwert erreicht
ISR (TIMER1_COMPA_vect)
{
write_row (zeile); // schreibe aktuelle Zeile
zeile++; // nächste mal naechste Zeile
if (zeile == CHARHEIGHT) // wenn alle Zeilen ausgegeben, wieder von vorne beginnen
zeile = 0;
durchlauf++; // Durchlaufzaehler: wie oft wurde das Display unverändert refresht
if (durchlauf == DELAY) // Anzahl der Durchläufe erreicht
{
durchlauf = 0;
pos++; // Displayinhalt eins verschieben
}
// Wenn der gesamte Speicherinhalt einmal durchlaufen wurde
if (pos >= (chars*(CHARWIDTH+1)+(DISPCOLS)))
pos = 0; // von vorne beginnen
}
Allerdings wird hier auch nur das auf dem Display angezeigt als Laufschrift,
was in folgender Zeile eingefügt wird
// *** Textausgabe ***
uint8_t text[]= " Hallo Roboternetz "; // Zeichenkette Ausgabe
Meine Frage,
ich würde gerne das Matrix-Display so ansteuern wie ich das LCD ansteuere, sprich einfach write_Matrix(" Hallo Roboternetz "); , oder über UART vom PC Text ans Display senden, oder Werte anzeigen lassen von ADC zum Beispiel ob als Laufschrift oder fest.
Könnte ich da den obrigen Code weiterhin verwenden und abändern, oder müsste was neues schreiben ?
LG Hendrik
ich hab mir vor einiger Zeit ein Matrix-LED-Display zusammen gebaut aus 4 5x7 Matrixmodulen. Den Schaltplan und Quelcode hab ich aus dem Buch "AVR Hardeware und C-Programmierung in der Praxis" von Florian Schäffer.
Der Quelcode funktioniert und ist für mich, als Anfänger, einfach und zu verstehen.
/************************************************** *
* Textausgabe auf 4 LED Modulen am Atmega 8 *
* 5x7 Matrixmodule mit gemeinsamer Anode *
* angesteuert über ULN2003A an PortB PB0 - PB6 *
* Multiplexing über 3 Schieberegister 74HCT164 *
* PC4 --> Bit setzen ; PC5 --> Tackt schieben *
* *
* Created: 13.02.2016 18:23:54 *
* Author: Hendrik *
************************************************** */
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "charset.h" // beinhaltet Zahlen, keine und große Buchstaben sowie Sonderzeichen
#include "lcd-routines.c"
void set_row (uint8_t);
void write_row (uint8_t);
int main (void);
#define DISPCOLS 20 // Anzahl der Spalten
#define MEMCOLS 200 // Displayspeicher fuer 200 Spalten reservieren (>= 6 x Anzahl der Zeichen in Zeichenkette + 2 x DISPCOLS)
#define CHARWIDTH 5 // Spalten je Zeichen
#define CHARHEIGHT 7 // Zeilen je Zeichen
#define DELAY 50 // Textgeschwindigkeit (ca. 10..200: schnell..langsam)
volatile uint8_t memory[DISPCOLS]; // Speicher für Display, spaltenweise orientiert, Index 0=links
volatile uint8_t pos=0; // ab welcher Speicherposition soll dargestellt werden
volatile uint8_t zeile=0; // Zeilenzähler welche Zeile aktuell ist
volatile uint8_t durchlauf=0; // Anzahl der Durchlaeufe
volatile uint8_t chars=0; // Anzahl der Zeichen in Zeichenkette
// *** Textausgabe ***
uint8_t text[]= " Hallo Roboternetz "; // Zeichenkette Ausgabe
void set_row (uint8_t row)
{
int8_t i;
// Alle Spalten des Displays durchlaufen. Mit rechter Spalte beginnen
for (i = DISPCOLS-1; i>=0; i--)
{
// Bit in der Spalte + Verschiebungswert pos an der übergebenden Zeile gesetzt?
if ((memory[i+pos] >> (6-row)) & 1) //
{
PORTC |= (1 << PC4); // Data Bit setzen
}
else
{
PORTC &= ~(1 << PC4); // Data Bit löschen
}
PORTC |= (1 << PC5); // Takt HIGH -> Flanke
PORTC &= ~(1 << PC5); // Takt LOW
}
}
void write_row (uint8_t row)
{
PORTB = 0; // alle Zeilen aus
set_row (row); // Daten für aktuelle Zeile in Schieberegister schieben
PORTB = (1 << row); // aktuelle Zeile an
}
int main()
{
lcd_init();
uint8_t i, row;
DDRC |= (1 << DDC4) | (1 << DDC5); // PC4, PC5 als Ausgang
PORTC &= ~((1 << PC4) | (1 << PC5)); // PC4, PC5 aus
DDRB = 0xFF; // PortB als Ausgang
PORTB = 0; // PortB aus
// Leerspalten am Anfang, damit Text von rechts kommt
for (row=0; row<DISPCOLS; row++)
memory[row]=1; // Eigentlich 0 aber für besseres Verständnis 1, damit eine LED leuchtet
// Zeichenkette in Spaltenbeschreibung umsetzen
while (text[chars] != 0) // solange Zeichen in Zeichenkette
{
memory[row]=charset[text[chars]-32][0]; row++; // aktuelle Spalte = 1. Spalte des Fonts
memory[row]=charset[text[chars]-32][1]; row++; // aktuelle Spalte = 2. Spalte des Fonts
memory[row]=charset[text[chars]-32][2]; row++; // usw.
memory[row]=charset[text[chars]-32][3]; row++;
memory[row]=charset[text[chars]-32][4]; row++;
memory[row]=0; row++; // Leerspalte: Abstand zwischen 2 Buchstaben
chars++; // Anzahl der Zeichen zählen
}
// Leerspalten am Ende, damit Textende aus Display geschoben wird
for (i=0; i<DISPCOLS; i++)
memory[i+row]=1; // Eigentlich 0 aber für besseres Verständnis 1, damit eine LED leuchtet
OCR1A = (uint16_t)(F_CPU/1024.0*0.003); // Vergleichwert für 0,003s laden: Takt= 8MHz/1024 = 7812,5 Zählerschritte pro s
TIMSK |= (1<<OCIE1A); // Interrupt wenn Timer Vergleichswert erreicht
TCCR1B |= (1<<CS12) | (1<<CS10) | (1<<WGM12); // Timer mit Div 1024 starten und Clear Counter on Compare Match
sei();
lcd_clear();
lcd_setcursor(0,1);
lcd_string("20x7 LED Matrix Text");
lcd_setcursor(3,3);
lcd_string("Hallo Thomas!");
while(1)
{
asm volatile ("nop"); // nichts machen
}
return 0;
}
// Wird vom 16 Bit Timer ausgelöst, wenn dieser den Vergleichwert erreicht
ISR (TIMER1_COMPA_vect)
{
write_row (zeile); // schreibe aktuelle Zeile
zeile++; // nächste mal naechste Zeile
if (zeile == CHARHEIGHT) // wenn alle Zeilen ausgegeben, wieder von vorne beginnen
zeile = 0;
durchlauf++; // Durchlaufzaehler: wie oft wurde das Display unverändert refresht
if (durchlauf == DELAY) // Anzahl der Durchläufe erreicht
{
durchlauf = 0;
pos++; // Displayinhalt eins verschieben
}
// Wenn der gesamte Speicherinhalt einmal durchlaufen wurde
if (pos >= (chars*(CHARWIDTH+1)+(DISPCOLS)))
pos = 0; // von vorne beginnen
}
Allerdings wird hier auch nur das auf dem Display angezeigt als Laufschrift,
was in folgender Zeile eingefügt wird
// *** Textausgabe ***
uint8_t text[]= " Hallo Roboternetz "; // Zeichenkette Ausgabe
Meine Frage,
ich würde gerne das Matrix-Display so ansteuern wie ich das LCD ansteuere, sprich einfach write_Matrix(" Hallo Roboternetz "); , oder über UART vom PC Text ans Display senden, oder Werte anzeigen lassen von ADC zum Beispiel ob als Laufschrift oder fest.
Könnte ich da den obrigen Code weiterhin verwenden und abändern, oder müsste was neues schreiben ?
LG Hendrik