/* 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 #include "WProgram.h" #include "AS1107.h" const byte AS1107::_repcharoff = 27; // Font Data PROGMEM prog_uchar _font[] = { // -------- Space 0b00000000, 0b00000000, 0b00000000, 0b00000000, // -------- A 0b01111110, 0b10010000, 0b10010000, 0b01111110, // -------- B 0b01101100, 0b10010010, 0b10010010, 0b11111110, // -------- C 0b10000010, 0b10000010, 0b01111100, // -------- D 0b00111000, 0b01000100, 0b10000010, 0b11111110, // -------- E 0b10000010, 0b10010010, 0b11111110, // -------- F 0b10000000, 0b10010000, 0b11111110, // -------- G 0b01011100, 0b10010010, 0b10000010, 0b01111100, // -------- H 0b11111110, 0b00010000, 0b00010000, 0b11111110, // -------- I 0b10000010, 0b11111110, 0b10000010, // -------- J 0b11111100, 0b00000010, 0b00001100, // -------- K 0b10000110, 0b01001000, 0b00110000, 0b11111110, // -------- L 0b00000010, 0b00000010, 0b11111110, // -------- M 0b11111110, 0b01100000, 0b00111100, 0b01100000, 0b11111110, // -------- N 0b11111110, 0b00011000, 0b01100000, 0b11111110, // -------- O 0b01111100, 0b10000010, 0b10000010, 0b01111100, // -------- P 0b01100000, 0b10010000, 0b10010000, 0b11111110, // -------- Q 0b01111010, 0b10000100, 0b10001010, 0b01111100, // -------- R 0b01100110, 0b10011000, 0b10010000, 0b11111110, // -------- S 0b10001100, 0b10010010, 0b01100010, // -------- T 0b10000000, 0b11111110, 0b10000000, // -------- U 0b11111100, 0b00000010, 0b00000010, 0b11111100, // -------- V 0b11000000, 0b00111000, 0b00000110, 0b00111000, 0b11000000, // -------- W 0b11111110, 0b00001100, 0b00111000, 0b00001100, 0b11111110, // -------- X 0b11000110, 0b00111000, 0b00111000, 0b11000110, // -------- Y 0b11100000, 0b00011110, 0b11100000, // -------- Z 0b11000010, 0b10110010, 0b10001110, // -------- Unknown character 0b00111000, 0b00111000, 0b00111000, // -------- 0 0b01111100, 0b10100010, 0b10010010, 0b01111100, // -------- 1 0b11111110, 0b01000000, // -------- 2 0b01100010, 0b10010010, 0b10001110, // -------- 3 0b01101100, 0b10010010, 0b10000010, // -------- 4 0b11111110, 0b00010000, 0b11110000, // -------- 5 0b10001100, 0b10010010, 0b11110010, // -------- 6 0b01001100, 0b10010010, 0b10010010, 0b01111100, // -------- 7 0b11100000, 0b10011110, 0b10000000, // -------- 8 0b01101100, 0b10010010, 0b10010010, 0b01101100, // -------- 9 0b01111100, 0b10010010, 0b10010010, 0b01100100, // -------- : 0b00100100, // -------- ; 0b00100110, 0b00000001, // -------- ! 0b01100000, 0b11111010, 0b01100000, // -------- Heart 0b01111000, 0b11111100, 0b11111110, 0b01111111, 0b11111110, 0b11111100, 0b01111000, // -------- < 0b01000100, 0b00101000, 0b00010000, // -------- = 0b00101000, 0b00101000, 0b00101000, 0b00101000, // -------- > 0b00010000, 0b00101000, 0b01000100, // -------- ? 0b01100000, 0b10011010, 0b10000000, // -------- @ 0b01111100, 0b10000010, 0b10111010, 0b10100010, 0b01011100, // -------- ( 0b10000010, 0b01111100, // -------- ) 0b01111100, 0b10000010, // -------- * 0b00101000, 0b00010000, 0b00101000, // -------- + 0b00010000, 0b00010000, 0b01111100, 0b00010000, 0b00010000, // -------- , 0b00000110, 0b00000001, // -------- - 0b00010000, 0b00010000, 0b00010000, 0b00010000, // -------- . 0b00000010, // -------- / 0b11000000, 0b00111000, 0b00000110, // -------- a 0b00111110, 0b00100010, 0b00100010, 0b00011100, // -------- b 0b00011100, 0b00100010, 0b00100010, 0b11111110, // -------- c 0b00100010, 0b00100010, 0b00011100, // -------- d 0b11111110, 0b00100010, 0b00100010, 0b00011100, // -------- e 0b00011000, 0b00101010, 0b00101010, 0b00011100, // -------- f 0b10010000, 0b01111110, 0b00010000, // -------- g 0b00111110, 0b00100101, 0b00100101, 0b00011000, // -------- h 0b00011110, 0b00100000, 0b00100000, 0b11111110, // -------- i 0b00000010, 0b01011110, 0b00010010, // -------- j 0b01011110, 0b00000001, 0b00000001, // -------- k 0b00100010, 0b00010100, 0b00001000, 0b11111110, // -------- l 0b00000010, 0b11111100, // -------- m 0b00011110, 0b00100000, 0b00111110, 0b00100000, 0b00111110, // -------- n 0b00011110, 0b00100000, 0b00100000, 0b00111110, // -------- o 0b00011100, 0b00100010, 0b00100010, 0b00011100, // -------- p 0b00011100, 0b00100010, 0b00100010, 0b00111111, // -------- q 0b00111111, 0b00100010, 0b00100010, 0b00011100, // -------- r 0b00010000, 0b00100000, 0b00111110, // -------- s 0b00100100, 0b00101010, 0b00101010, 0b00010010, // -------- t 0b00100010, 0b11111100, 0b00100000, // -------- u 0b00111110, 0b00000010, 0b00000010, 0b00111100, // -------- v 0b00111000, 0b00000110, 0b00111000, // -------- w 0b00111110, 0b00000010, 0b00011110, 0b00000010, 0b00111100, // -------- x 0b00110110, 0b00001000, 0b00110110, // -------- y 0b00111110, 0b00000101, 0b00000101, 0b00111001, // -------- z 0b00110010, 0b00101010, 0b00100110, 0b00100010, 0b11000001 }; // Char width table PROGMEM prog_uchar _charwidth[] = {4,4,4,3,4,3,3,4,4,3,3,4,3,5,4,4,4,4,4,3,3,4,5,5,4,3,3, 3,4,2,3,3,3,3,4,3,4,4,1,2,3,7,3,4,3,3,5,2,2,3,5,2,4,1,3, 4,4,3,4,4,3,4,4,3,3,4,2,5,4,4,4,4,3,4,3,4,3,5,3,4,4,0 }; // ASCII Codes of the implemented characters PROGMEM prog_uchar _charcodes[] = {32,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, 81,82,83,84,85,86,87,88,89,90,255,48,49,50,51,52,53, 54,55,56,57,58,59,33,3,60,61,62,63,64,40,41,42,43,44, 45,46,47,97,98,99,100,101,102,103,104,105,106,107,108, 109,110,111,112,113,114,115,116,117,118,119,120,121, 122,0}; // ------------------------------------------------------------------------------------ // Constructor, initialize arduino AS1107::AS1107(byte cspin, byte clkpin, byte datapin) { _cspin = cspin; _clkpin = clkpin; _datapin = datapin; pinMode(cspin, OUTPUT); pinMode(clkpin, OUTPUT); pinMode(datapin, OUTPUT); digitalWrite(cspin,HIGH); digitalWrite(clkpin,LOW); digitalWrite(datapin,LOW); } // ------------------------------------------------------------------------------------ // Initializes Arduino and AS1107 // buffer is the initial screen buffer void AS1107::Init(byte * buffer, byte _Maxx, byte _Maxy, byte _cNum) { Maxx = _Maxx; Maxy = _Maxy; HighestCtrlNum = _cNum; _buffer = buffer; CalculateCharOffsets(); // Clear Screen buffer Clear(); for (int i=0; i<=HighestCtrlNum; i++) { WriteRegister(i, Registers::Shutdown, ShutdownModes::Normal); WriteRegister(i, Registers::DecodeMode, 0x00); WriteRegister(i, Registers::IntensityControl, 0x00); WriteRegister(i, Registers::ScanLimit, 0x07); } } // ------------------------------------------------------------------------------------ // 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]); } } // ------------------------------------------------------------------------------------ // Clear the Screen Buffer void AS1107::Clear() { for (byte i=0; i<=Maxx; _buffer[i++]=0); } // ------------------------------------------------------------------------------------ // 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= 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 */ e2 = 2*err; if (e2 < (2*dx+1)*b2) { dx++; err += (2*dx+1)*b2; } if (e2 > -(2*dy-1)*a2) { dy--; err -= (2*dy-1)*a2; } } while (dy >= 0); while (dx++ < a) { /* correction for flat ellipses (b=1) */ SetLed(xm+dx, ym, ON); SetLed(xm-dx, ym, ON); } } // ------------------------------------------------------------------------------------ // 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) { if (value != 0) { _buffer[x] |= value << (Maxy-y); } else { _buffer[x] &= ~(1 << (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; }