This page is german language only.But you can view a translated version using Google Translator by clickingthis link!
Das Matrixmodul
Das Matrixmodul ist ein CILE1088A/B das bei ebay im 10er-Pack für ca. 12€ Versandkostenfrei aus Hongkong erhältlich ist.
Die Pinbelegung ist chaotisch. Da kein Datenblatt im Netz zu finden ist habe mir die Mühe gemacht, die Belegung selbst herauszufinden.
Die Orientierung des Moduls für die Pinbelegung ist dabei so, dass der Nummernaufdruck "6088" von einem weg zeigt, sich also an der oberen Stirnseite befindet. Würde man jetzt von unten gucken, sähe man die durch die Vergußmasse erscheinende Typenbezeichnung auf dem Kopf stehend.
Die LEDs leuchten schon sehr hell wenn man sie mit knapp 4mA ansteuert.
Pinouts
Pinout des LED-Treiberchips AS1107
Ansteuerung
Um das Modul ohne Multiplexing direkt von einem Microcontroller anzusteuern, bräuchte man eigentlich 16 I/O Pins. Die haben wir aber nicht. Der Arduino Duemilenove1 hat maximal 13, und selbst wenn würde man nicht so viele I/O-Pins nur für die Anzeige opfern wollen. Die Lösung heißt Multiplexing. Dabei werden Reihen und Spalten sehr schnell nacheinander durchgeschaltet und die gewünschten LEDs leuchten sehr kurz, aber dafür mit überhöhtem Strom und dadurch sehr hell auf. Wenn das schnell genug passiert, hat man den Eindruck eines stehenden Bildes (Fernsehprinzip, Persistance of Vision).
Ansteuerung mit dem AS1107 von austriamicrosystems
Der Chip AS1107 ist ein Treiber-IC der acht 7-Segment-Anzeigen oder auch eine einzelne LED-Matrix ansteuern kann. Er ist Pin- und Softwarekompatibel mit dem MAX7221 von Maxim, aber erheblich preiswerter. Er wird seriell angesteuert und belegt damit erfreulicherweise nur drei Output-Pins am Arduino für die Signale /CSN,CLCK und DIN. Da der Chip außerdem LED-Konstantstromquellen besitzt, kann er direkt ohne Vorwiderstände an die LED-Matrix angeschlossen werden. Es ist lediglich ein externer Widerstand zur Einstellung des LED-Stroms nötig.
Die Treiber sind kaskadierbar. Um mehrere Module anzusteuern braucht man also auch nur drei I/O Leitungen.
Verdrahtung
Pin IC
Name
Funktion
Verbinden mit
1
DIN
Serial Data Input
Arduino Pin 4
2
DIG0
Digit Line 0
Matrix Pin 16 (A)
3
DIG4
Digit Line 4
Matrix Pin 10 (E)
4
GND
Ground
Minus/Masse/Ground
5
DIG6
Digit Line 6
Matrix Pin 6 (G)
6
DIG2
Digit Line 2
Matrix Pin 11 (C)
7
DIG3
Digit Line 3
Matrix Pin 3 (D)
8
DIG7
Digit Line 7
Matrix Pin 13 (H)
9
GND
Ground
Minus/Masse/Ground
10
DIG5
Digit Line 5
Matrix Pin 5 (F)
11
DIG1
Digit Line 1
Matrix Pin 15 (B)
12
/CSN
Chip Select
Arduino Pin 2
13
CLK
Serial-Input Clock
Arduino Pin 3
14
SEGA
Segment Drive Line A
Matrix Pin 7 (2)
15
SEGF
Segment Drive Line F
Matrix Pin 14 (7)
16
SEGB
Segment Drive Line B
Matrix Pin 2 (3)
17
SEGG
Segment Drive Line G
Matrix Pin 9 (8)
18
ISET
Set Segment Current
über 10KOhm Widerstand an +5V
19
VDD
Positive Supply Voltage
+5V
20
SEGC
Segment Drive Line C
Matrix Pin 8 (4)
21
SEGE
Segment Drive Line E
Matrix Pin 1 (6)
22
SEGDP
Segment Drive Line Decimal Point
Matrix Pin 4 (1)
23
SEGD
Segment Drive Line D
Matrix Pin 12 (5)
24
DOUT
Serial Data Output
damit kann man mehrere Chips kaskadieren um größere LED Matrizen anzusteuern (Also DOUT Chip1 an DIN Chip2).
Software
Zur Ansteuerung der Matrix habe ich eine Arduino-Library geschrieben, die in der neuesten Version auch mit mehreren kaskadierten Chips und Modulen zurechtkommt. Der Zeichensatz für die Laufschrift und die Textfunktion befand sich in früheren Versionen im EEPROM des ATmega?, in der aktuellen Version im internen Flash-Speicher (PROGMEM). Somit bleibt das interne EEPROM für andere Zwecke frei und der Zeichensatz ist leicht änderbar
Zusätzlich zur Laufschrift bietet die Library auch grundlegende Grafikfunktionen:
const byte d = 0; int count=1; void setup() {
matrix.Init(buffer);
matrix.SetScrollText(" Three 8x8 LED dot matrix modules driven by three AS1107 LED controllers using just four I/O pins of the Arduino for serial data. That is surprisingly fast, look:", 1); }
Hier nun die Sourcen für die Library selbst.
Zur Installation muß im Unterverzeichnis libraries der Arduino-Software ein Verzeichnis AS1107 angelegt werden, dort werden die folgenden Dateien erstellt, bzw. hineinkopiert.
Die vorliegende Version ist für drei kaskadierte Module vorgesehen. Wird eine andere Anzahl verwendet muß AS1107.h an gekennzeichneter Stelle angepasst werden. In zukünftigen Versionen wird dies auch über die Initialisierung möglich sein.
/*
AS1107.h - Library for interfacing the AS1107 LED Driver Chip
Created by Stephan Elsner 2011
version 0.82
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AS1107_h #define AS1107_h
#include "WProgram.h" #include <avr/pgmspace.h>
#define ON 1 #define OFF 0
// --------------------------------------------------------------------------------------------------------------------------
class AS1107 { public:
AS1107(byte cspin, byte clkpin, byte datapin); void WriteRegister2(byte chip, byte reg, byte data); void WriteRegister(byte chip, byte reg, byte data); void WriteColumn( byte column, byte data); void Init(byte *buffer); void SetBuffer(byte *buffer); void SetLed(int x, int y, byte value); void Clear(); void Update(); void ShiftLeft(); void ShiftRight(); void ShiftUp(); void ShiftDown(); void ShiftUp(byte from, byte to); void ShiftDown(byte from, byte to); void DrawLine(int x0, int y0, int x1, int y1); void DrawBox(int x0, int y0, int x1, int y1); void DrawEllipse(int xm, int ym, int a, int b); void SetScrollText(char *string, int charspacing); void DrawText (int x, int y, char *str);
byte DrawChar (int x, int y, char thechar);
boolean TextScroll();
// *************************************** // Set your module configuration here // *************************************** staticconst byte Maxx=23; // maximum x - Pixels of the Module staticconst byte Maxy=7; // maximum y - Pixels of the Module staticconst byte HighestCtrlNum=2; // Number of Matrix modules -1 (0 = single module)
private:
byte _cspin;
byte _clkpin;
byte _datapin;
byte *_buffer; // pointer to current screen buffer
staticconst byte _repcharoff; // Offset of the replacement for unknown characers int _charoffset[82]; // Start position in Array char *_outputstring; // pointer to start of output string char *_curchr; // pointer to current char of output String int _fontidx; // current byte in font to display int _colct; // to count the columns of character to display
byte _charspacing; // the coulumns of space between characters
boolean _hastext;
// -------------------------------------------------------------------------------------------------------------------------- // Values to write to the Shutdown Register
class ShutdownModes { public: staticconst byte ShutdownResetFeature = 0x00; // Shutdown Mode, Reset Feature Register to Default Settings staticconst byte Shutdown = 0x80; // Shutdown Mode, leaving Feature Register unchanged staticconst byte NormalResetFeature = 0x01; // Normal Mode, Reset Feature staticconst byte Normal = 0x81; // Normal Mode, Feature unchanged };
// Bits in the feature-Register, desired Settings must be OR'ed together
class Features { public: staticconst byte ExternalClock = 0x01; // ExternalClock active staticconst byte ResetRegisters = 0x02; // Resets all control registers except the Feature Register. staticconst byte HexDecoding = 0x04; // 1 = Enable HEX decoding, 0 = Enable Code-B decoding staticconst byte SPIEnable = 0x08; // Enables the SPI-compatible interface.(AS1106 only). staticconst byte BlinkEnable = 0x10; // Enables blinking. staticconst byte BlinkSlow = 0x20; // Sets blink with low frequency // (with the internal oscillator enabled)
staticconst byte BlinkSync = 0x40; // Synchronizes blinking on the rising edge of pin LOAD/CSN. // The multiplex and blink timing counter is cleared on the // rising edge of pin LOAD/CSN. By setting this bit in // multiple AS1106/AS1107 devices, the blink timing can // be synchronized across all the devices.
staticconst byte BlinkStartWithOn = 0x80; // Start Blinking with display enabled phase. // When bit D4 (blink_en) is set, bit D7 // determines how blinking starts. // 0 = Blinking starts with the display turned off. // 1 = Blinking starts with the display turned on. };
/*
AS1107.cpp - Library for interfacing the AS1107 LED Driver Chip
Created by Stephan Elsner, March 29, 2011
Scrolltext uses a proportional character font
Tested with Arduino Duemilenove
version 0.82
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ #include <avr/pgmspace.h> #include "WProgram.h" #include "AS1107.h"
// ------------------------------------------------------------------------------------ // Set the Screen buffer void AS1107::SetBuffer(byte * buffer) {
_buffer = buffer; }
// ------------------------------------------------------------------------------------ // Writes Data to a Register of the AS1106/AS1107 // chip: Number of the controller chip (starting at 0 for the left) // reg: Register of the controller // data: Data to be written void AS1107::WriteRegister( byte chip, byte reg, byte data) { if(chip>=0 && chip <= HighestCtrlNum){
chip = HighestCtrlNum -chip;
digitalWrite(_cspin,LOW); for(int i=0; i<=HighestCtrlNum; i++){ if(i == chip){
shiftOut(_datapin, _clkpin, MSBFIRST, reg);
shiftOut(_datapin, _clkpin, MSBFIRST, data); } else{
shiftOut(_datapin, _clkpin, MSBFIRST, Registers::NoOp);
shiftOut(_datapin, _clkpin, MSBFIRST, 0); } }
digitalWrite(_cspin,HIGH); } }
// ------------------------------------------------------------------------------------ // Writes a column of data to the LED-Matrix // column: column number, starting at 0 // data : screen data to be written void AS1107::WriteColumn( byte column, byte data) { // if you use unusual matrix row wiring, you can manipulate data here
byte chip = (column) >>3;
byte reg = (column % 8) +1;
WriteRegister(chip, reg, data); }
// ------------------------------------------------------------------------------------ // Sets the status of a LED in the screen buffer void AS1107::SetLed(int x, int y, byte value) { if(x<=Maxx && y<=Maxy && x>=0 && y>=0){ if(value>0) value = 1;
SetLedInternal(x, y, value); } }
// ------------------------------------------------------------------------------------ // Writes Buffer to Screen // needs to be called after a graphics operation to see anything void AS1107::Update() { for(byte i=0; i<=Maxx; i++){
WriteColumn(i, _buffer[i]); } }
// ------------------------------------------------------------------------------------ // Shift the content of the Screen buffer to the left void AS1107::ShiftLeft() { for(byte i=1; i<=Maxx; i++){
_buffer[i-1] = _buffer[i]; }
_buffer[Maxx] = 0; } // ------------------------------------------------------------------------------------ // Shift the content of the Screen buffer to the right void AS1107::ShiftRight() { for(byte i=Maxx; i>=1; i--){
_buffer[i] = _buffer[i-1]; }
_buffer[0] = 0; } // ------------------------------------------------------------------------------------ // Shift the content of the Screen buffer up void AS1107::ShiftUp() { for(byte i=0; i<=Maxx; i++){
_buffer[i] = _buffer[i]<<1 & 0xFE; } } // ------------------------------------------------------------------------------------ // Shift the content of the Screen buffer up void AS1107::ShiftUp(byte from, byte to) { for(byte i=from; i<=to; i++){
_buffer[i] = _buffer[i]<<1 & 0xFE; } } // ------------------------------------------------------------------------------------ // Shift the content of the Screen buffer down void AS1107::ShiftDown() { for(byte i=0; i<=Maxx; i++){
_buffer[i] = _buffer[i]>>1 & 0x7F; } } // ------------------------------------------------------------------------------------ // Shift the content of the Screen buffer down void AS1107::ShiftDown(byte from, byte to) { for(byte i=from; i<=to; i++){
_buffer[i] = _buffer[i]>>1 & 0x7F; } } // ------------------------------------------------------------------------------------ // draws a line from x0 ,y0 to x1,y1 void AS1107::DrawLine(int x0, int y0, int x1, int y1) {
int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1; int err = dx+dy, e2; /* error value e_xy */
for(;;){/* loop */
SetLed(x0,y0,ON); if(x0==x1 && y0==y1)break;
e2 = 2*err; if(e2 >= dy){ err += dy; x0 += sx; }/* e_xy+e_x > 0 */ if(e2 <= dx){ err += dx; y0 += sy; }/* e_xy+e_y < 0 */ } } // ------------------------------------------------------------------------------------ // draws a box from x0,x0 to x1,y1 void AS1107::DrawBox(int x0, int y0, int x1, int y1) {
DrawLine(x0,y0,x1,y0);
DrawLine(x1,y0,x1,y1);
DrawLine(x1,y1,x0,y1);
DrawLine(x0,y1,x0,y0); } // ------------------------------------------------------------------------------------ // draws an ellipse // center xm, ym - radius a,b void AS1107::DrawEllipse(int xm, int ym, int a, int b) { if(a ==0 && b== 0){
SetLed(xm,ym,ON); return; }
int dx = 0, dy = b; /* first quadrant from top left to bottom right */ int a2 = a*a, b2 = b*b; int err = b2-(2*b-1)*a2, e2; /* error value in the first step */
do{
SetLed(xm+dx, ym+dy, ON); /* I. Quadrant */
SetLed(xm-dx, ym+dy, ON); /* II. Quadrant */
SetLed(xm-dx, ym-dy, ON); /* III. Quadrant */
SetLed(xm+dx, ym-dy, ON); /* IV. Quadrant */
// ------------------------------------------------------------------------------------ // Writes Text at a screen position void AS1107::DrawText(int x, int y, char *str) {
byte count; char thechar; while(*str != '\0'){
Serial.println(*str,DEC);
x+=DrawChar(x, y, *str);
str++; } }
// ------------------------------------------------------------------------------------ // Draws a single character at a screen position // returns the x-position for the next character
byte AS1107::DrawChar(int x, int y, char thechar) {
y+=7;
byte charnum, colct, count=0, colbits; int fontidx;
charnum = GetInternalCharCode(thechar);
// get the location of the first column of the font
fontidx = _charoffset[charnum]-1;
// get the width of the font
colct = pgm_read_byte_near(_charwidth + charnum); for(byte i=colct; i>0; i--){
colbits = pgm_read_byte_near(_font + fontidx + i); for(byte j=0; j<=7; j++){ if((colbits >>j) & 1){
SetLed(x, y-j, 1); } }
x++; } return colct+1; } // ------------------------------------------------------------------------------------ // Sets the Text for Scrolline void AS1107::SetScrollText(char *string, int charspacing) {
_charspacing = charspacing;
_outputstring = string;
_curchr = string;
_hastext = true;
_colct =-1; }
// ------------------------------------------------------------------------------------ // Scrolls the text one pixel to the left // returns true if last character has been displayed
boolean AS1107::TextScroll() {
boolean lastchar = false;
byte colbits = 0; if(_colct == (0-_charspacing-1)){
lastchar = NextCharacter(); } if(_colct>=0){
colbits = pgm_read_byte_near(_font + _fontidx + _colct); }
ShiftLeft();
_buffer[Maxx] = colbits;
Update();
_colct--; return lastchar; }
// ------------------------------------------------------------------------------------ // PRIVATE (Internal) functions // ------------------------------------------------------------------------------------ // Set LED without Parameter check void AS1107::SetLedInternal(byte x, byte y, byte value) {
_buffer[x] |= value << (Maxy-y); }
// ------------------------------------------------------------------------------------ // fetches the next character of the Scrollline // returns true if string is at the end
boolean AS1107::NextCharacter() {
boolean lastchar = false; if(_hastext){ char thechar = *_curchr;
boolean found = false;
byte charnum = 0;
byte i; // if the string ends, start from the beginning if(thechar == 0){
lastchar = true;
_curchr = _outputstring;
thechar = *_curchr; }
charnum = GetInternalCharCode(thechar);
// get the offset of the first column of the character
_fontidx = _charoffset[charnum];
// get the width of the font
_colct = pgm_read_byte_near(_charwidth + charnum) -1; } else{
_fontidx= _charoffset[_repcharoff];
_colct = pgm_read_byte_near(_charwidth + _repcharoff); }
*_curchr++; return lastchar; } // ------------------------------------------------------------------------------------ // calculates Character offsets from font width table in EEPROM void AS1107::CalculateCharOffsets() { int off =0; int idx=0; int w=0; int i=0;
do{
_charoffset[i]=off;
w = pgm_read_byte_near(_charwidth+i);
off += w;
i++; }while(w != 0); }
// ------------------------------------------------------------------------------------ // gets the character number of the built-in-font from the ASCII table // returns number of the replacement character for unknown characters
byte AS1107::GetInternalCharCode(byte thechar) { int i=0; int charnum; do{
charnum = pgm_read_byte_near(_charcodes + i); if(charnum == thechar)break;
i++; }while(charnum != 0); if(charnum == 0) i = _repcharoff; return i; }
Die folgende Datei ist für das Syntax-Highlighting des Arduino-Editors verantwortlich, damit werden die in der Lib verwendeten Methoden ond der Klassenname farblich hervorgehoben.