Forked LEDMatrix and added horizontal scrolling
Fork of LEDMatrix by
LEDMatrix.cpp
00001 /** 00002 * LED Matrix library for http://www.seeedstudio.com/depot/ultrathin-16x32-red-led-matrix-panel-p-1582.html 00003 * The LED Matrix panel has 32x16 pixels. Several panel can be combined together as a large screen. 00004 * 00005 * Coordinate & Connection (mbed -> panel 0 -> panel 1 -> ...) 00006 * (0, 0) (0, 0) 00007 * +--------+--------+--------+ +--------+--------+ 00008 * | 5 | 3 | 1 | | 1 | 0 | 00009 * | | | | | | |<----- mbed 00010 * +--------+--------+--------+ +--------+--------+ 00011 * | 4 | 2 | 0 | (64, 16) 00012 * | | | |<----- mbed 00013 * +--------+--------+--------+ 00014 * (96, 32) 00015 * Copyright (c) 2013 Seeed Technology Inc. 00016 * @auther Yihui Xiong 00017 * @date Nov 8, 2013 00018 * @license Apache 00019 * 00020 * Heavily modified by Rob Dobson, 2016 00021 */ 00022 00023 #include "LEDMatrix.h" 00024 #include "mbed.h" 00025 #include "fontBig.h" 00026 #include "font5x7.h" 00027 00028 #if 0 00029 #define ASSERT(e) if (!(e)) { Serial.println(#e); while (1); } 00030 #else 00031 #define ASSERT(e) 00032 #endif 00033 00034 LEDMatrix::LEDMatrix(PinName pinA, PinName pinB, PinName pinC, PinName pinD, PinName pinOE, PinName pinR1, PinName pinSTB, PinName pinCLK) : 00035 a(pinA), b(pinB), c(pinC), d(pinD), oe(pinOE), r1(pinR1), stb(pinSTB), clk(pinCLK) 00036 { 00037 this->clk = clk; 00038 this->r1 = r1; 00039 this->stb = stb; 00040 this->oe = oe; 00041 this->a = a; 00042 this->b = b; 00043 this->c = c; 00044 this->d = d; 00045 00046 mask = 0xff; 00047 _isEnabled = false; 00048 for (int i = 0; i < LED_MATRIX_LEDS_VERTICALLY; i++) 00049 { 00050 _hScrollPos[i] = 0; 00051 _hScrollWidth[i] = LED_MATRIX_LEDS_HORIZONTALLY; 00052 } 00053 for (int i = 0; i < LED_MATRIX_MAX_LINES; i++) 00054 { 00055 _lineScrollInc[i] = 0; 00056 _lineHighlight[i] = false; 00057 _lineInvert[i] = false; 00058 } 00059 _isBusy = false; 00060 _charSeparation = 1; 00061 _flashCounter = 0; 00062 _flashRate = 50; 00063 _flashState = false; 00064 _scrollCounter = 0; 00065 _scrollRate = 7; 00066 } 00067 00068 void LEDMatrix::begin(uint8_t *_pDisplayBuf, uint16_t width, uint16_t height, uint16_t dispBufWidth, 00069 uint16_t numLines, int charSeparation, int flashRate, int scrollRate) 00070 { 00071 ASSERT(0 == (width % LED_MATRIX_LEDS_HORIZONTALLY)); 00072 ASSERT(0 == (scroll_width % LED_MATRIX_LEDS_HORIZONTALLY)); 00073 ASSERT(0 == (height % LED_MATRIX_LEDS_VERTICALLY)); 00074 00075 this->_pDisplayBuf = _pDisplayBuf; 00076 this->width = width; 00077 this->height = height; 00078 this->dispBufWidth = dispBufWidth; 00079 this->numLines = numLines; 00080 this->_charSeparation = charSeparation; 00081 if (flashRate > 0) 00082 this->_flashRate = flashRate; 00083 if (scrollRate > 0) 00084 this->_scrollRate = scrollRate; 00085 if (numLines > LED_MATRIX_MAX_LINES) 00086 this->numLines = LED_MATRIX_MAX_LINES; 00087 for (int i = 0; i < LED_MATRIX_LEDS_VERTICALLY; i++) 00088 { 00089 this->_hScrollWidth[i] = dispBufWidth; 00090 } 00091 00092 _isEnabled = true; 00093 } 00094 00095 void LEDMatrix::drawPoint(uint16_t x, uint16_t y, uint8_t pixel) 00096 { 00097 ASSERT(dispBufWidth > x); 00098 ASSERT(height > y); 00099 00100 uint8_t *byte = _pDisplayBuf + (height - 1 - y) * dispBufWidth / 8 + x / 8; 00101 uint8_t bit = x % 8; 00102 00103 if (pixel) 00104 { 00105 *byte |= 0x80 >> bit; 00106 } 00107 else 00108 { 00109 *byte &= ~(0x80 >> bit); 00110 } 00111 } 00112 00113 void LEDMatrix::drawRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t pixel) 00114 { 00115 for (uint16_t x = x1; x < x2; x++) 00116 { 00117 for (uint16_t y = y1; y < y2; y++) 00118 { 00119 drawPoint(x, y, pixel); 00120 } 00121 } 00122 } 00123 00124 void LEDMatrix::drawImage(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t *image) 00125 { 00126 ASSERT(0 == ((x2 - x1) % 8)); 00127 00128 for (uint16_t x = x1; x < x2; x++) 00129 { 00130 for (uint16_t y = y1; y < y2; y++) 00131 { 00132 uint8_t *byte = image + x * 8 + y / 8; 00133 uint8_t bit = 7 - (y % 8); 00134 uint8_t pixel = (*byte >> bit) & 1; 00135 drawPoint(x, y, pixel); 00136 } 00137 } 00138 } 00139 00140 //void LEDMatrix::clear() 00141 //{ 00142 // uint8_t *ptr = _pDisplayBuf; 00143 // for (uint16_t i = 0; i < (dispBufWidth * height / 8); i++) 00144 // { 00145 // *ptr = 0x00; 00146 // ptr++; 00147 // } 00148 //} 00149 00150 void LEDMatrix::invertColour() 00151 { 00152 mask = ~mask; 00153 } 00154 00155 uint8_t LEDMatrix::isInvertedColour() 00156 { 00157 return mask; 00158 } 00159 00160 void LEDMatrix::scan() 00161 { 00162 // On each call this function handles one row of the display 00163 static uint8_t scanRowIdx = 0; 00164 00165 // Check if being updated 00166 if (_isBusy) 00167 return; 00168 00169 // Check if display enabled 00170 if (!_isEnabled) 00171 return; 00172 00173 // Base of this scan row in buffer to display 00174 uint8_t *pBufBase = _pDisplayBuf + scanRowIdx * (dispBufWidth / 8); 00175 00176 // Handle multiple units vertically 00177 for (int rowIdx = 0; rowIdx < (height / LED_MATRIX_LEDS_VERTICALLY); rowIdx++) 00178 { 00179 // Calculate buffer position within this unit 00180 uint8_t *pBuf = pBufBase + rowIdx * (dispBufWidth / 8) * LED_MATRIX_LEDS_VERTICALLY; 00181 00182 // Work out which display line we're in 00183 uint8_t dispMask = mask; 00184 int rowsInLine = (height/numLines); 00185 int dispLine = scanRowIdx / rowsInLine; 00186 if (dispLine < numLines) 00187 { 00188 if (_lineInvert[dispLine]) 00189 dispMask = ~dispMask; 00190 } 00191 00192 // Work along the display row sending out data as we go 00193 // Noting that the first data we send out will be shunted to the end of the row 00194 int hScrollPos = _hScrollPos[scanRowIdx]; 00195 int hScrollWidth = _hScrollWidth[scanRowIdx]; 00196 if (hScrollWidth > dispBufWidth) 00197 hScrollWidth = dispBufWidth; 00198 int bitOffset = hScrollPos % 8; 00199 for (int byteIdx = (width / 8) - 1; byteIdx >= 0; byteIdx--) 00200 { 00201 // When a row is scrolled a single byte on the display can be a combination of two buffer bytes 00202 uint8_t* pByte1 = pBuf + ((byteIdx*8 + hScrollPos) % hScrollWidth) / 8; 00203 uint8_t* pByte2 = pBuf + (((byteIdx+1)*8 + hScrollPos) % hScrollWidth) / 8; 00204 uint8_t pixels = ((*pByte1) << bitOffset) + (((*pByte2) >> (8 - bitOffset)) % 256); 00205 00206 // Reverse the bits so they come out in the right order 00207 pixels = reverseBits(pixels) ^ dispMask; // reverse: mask = 0xff, normal: mask =0x00 00208 for (uint8_t bit = 0; bit < 8; bit++) 00209 { 00210 clk = 0; 00211 r1 = pixels & (0x80 >> bit); 00212 clk = 1; 00213 } 00214 } 00215 } 00216 00217 // Disable display 00218 oe = 1; 00219 00220 // Select row (rows are muxed) 00221 int rowSel = LED_MATRIX_LEDS_VERTICALLY - 1 - scanRowIdx; 00222 a = (rowSel & 0x01); 00223 b = (rowSel & 0x02); 00224 c = (rowSel & 0x04); 00225 d = (rowSel & 0x08); 00226 00227 // Latch data 00228 stb = 0; 00229 stb = 1; 00230 00231 // Reenable display 00232 oe = 0; 00233 00234 // Move the scan row on for next time 00235 scanRowIdx = (scanRowIdx + 1) & 0x0F; 00236 } 00237 00238 void LEDMatrix::on() 00239 { 00240 _isEnabled = true; 00241 } 00242 00243 void LEDMatrix::off() 00244 { 00245 _isEnabled = false; 00246 oe = 1; 00247 } 00248 00249 bool LEDMatrix::getRowsToWorkOn(int lineIdx, int &startRow, int &numRows) 00250 { 00251 // lineIdx == -1 means all lines 00252 startRow = 0; 00253 numRows = LED_MATRIX_LEDS_VERTICALLY; 00254 if (lineIdx != -1) 00255 { 00256 if ((lineIdx < 0) || (lineIdx >= numLines)) 00257 return false; 00258 numRows = height / numLines; 00259 startRow = lineIdx * numRows; 00260 } 00261 return true; 00262 } 00263 00264 void LEDMatrix::scrollReset(int lineIdx) 00265 { 00266 // Interpret param 00267 int startRow = 0; 00268 int numRows = LED_MATRIX_LEDS_VERTICALLY; 00269 if (!getRowsToWorkOn(lineIdx, startRow, numRows)) 00270 return; 00271 // Reset scroll position all rows 00272 for (int i = startRow; i < startRow+numRows; i++) 00273 _hScrollPos[i] = 0; 00274 } 00275 00276 void LEDMatrix::scroll(int lineIdx, bool scrollLeft) 00277 { 00278 // Interpret param 00279 int startRow = 0; 00280 int numRows = LED_MATRIX_LEDS_VERTICALLY; 00281 if (!getRowsToWorkOn(lineIdx, startRow, numRows)) 00282 return; 00283 // Reset scroll position all rows 00284 for (int i = startRow; i < startRow+numRows; i++) 00285 { 00286 if (scrollLeft) 00287 { 00288 _hScrollPos[i]++; 00289 if (_hScrollPos[i] >= _hScrollWidth[i]) 00290 _hScrollPos[i] = 0; 00291 } 00292 else 00293 { 00294 _hScrollPos[i]--; 00295 if (_hScrollPos[i] < 0) 00296 _hScrollPos[i] = _hScrollWidth[i]-1; 00297 } 00298 } 00299 } 00300 00301 void LEDMatrix::scrollToPos(int lineIdx, int pos) 00302 { 00303 // Interpret param 00304 int startRow = 0; 00305 int numRows = LED_MATRIX_LEDS_VERTICALLY; 00306 if (!getRowsToWorkOn(lineIdx, startRow, numRows)) 00307 return; 00308 // Check pos 00309 if ((pos < 0) || (pos >= dispBufWidth)) 00310 return; 00311 // Reset scroll position all rows 00312 for (int i = startRow; i < startRow+numRows; i++) 00313 _hScrollPos[i] = pos; 00314 } 00315 00316 void LEDMatrix::clear(int lineIdx) 00317 { 00318 // Interpret param 00319 int startRow = 0; 00320 int numRows = LED_MATRIX_LEDS_VERTICALLY; 00321 if (!getRowsToWorkOn(lineIdx, startRow, numRows)) 00322 return; 00323 // Clear section 00324 uint8_t *ptr = _pDisplayBuf + startRow * (dispBufWidth / 8); 00325 int bytesToZero = numRows * (dispBufWidth / 8); 00326 for (int i = 0; i < bytesToZero; i++) 00327 *ptr++ = 0x00; 00328 // Stop invert 00329 for (int i = 0; i < LED_MATRIX_MAX_LINES; i++) 00330 _lineInvert[i] = false; 00331 } 00332 00333 void LEDMatrix::setScrollRate(int rate) 00334 { 00335 _scrollRate = rate; 00336 } 00337 00338 void LEDMatrix::setFlashRate(int rate) 00339 { 00340 _flashRate = rate; 00341 } 00342 00343 void LEDMatrix::setupScroll(int lineIdx, int scrollWidth, int scrollInc) 00344 { 00345 // Interpret param 00346 int startRow = 0; 00347 int numRows = LED_MATRIX_LEDS_VERTICALLY; 00348 if (!getRowsToWorkOn(lineIdx, startRow, numRows)) 00349 return; 00350 scrollWidth = (((scrollWidth / 8) + 1) * 8); 00351 if (scrollWidth <= 0) 00352 return; 00353 for (int i = startRow; i < startRow+numRows; i++) 00354 { 00355 _hScrollPos[i] = 0; 00356 _hScrollWidth[i] = scrollWidth; 00357 } 00358 // Store the scroll increment 00359 int startLine = 0; 00360 int linesToProcess = numLines; 00361 if (lineIdx != -1) 00362 { 00363 if ((lineIdx < 0) || (lineIdx >= numLines)) 00364 return; 00365 startLine = lineIdx; 00366 linesToProcess = 1; 00367 } 00368 for (int i = 0; i < linesToProcess; i++) 00369 _lineScrollInc[i+startLine] = scrollInc; 00370 } 00371 00372 void LEDMatrix::setHighlight(int lineIdx, bool highlightOn) 00373 { 00374 // Store the highlight status 00375 int startLine = 0; 00376 int linesToProcess = numLines; 00377 if (lineIdx != -1) 00378 { 00379 if ((lineIdx < 0) || (lineIdx >= numLines)) 00380 return; 00381 startLine = lineIdx; 00382 linesToProcess = 1; 00383 } 00384 for (int i = 0; i < linesToProcess; i++) 00385 _lineHighlight[i+startLine] = highlightOn; 00386 } 00387 00388 void LEDMatrix::serviceEffects() 00389 { 00390 // Scroll logic 00391 _scrollCounter++; 00392 if (_scrollCounter >= _scrollRate) 00393 { 00394 _scrollCounter = 0; 00395 int rowsInLine = (height / numLines); 00396 for (int i = 0; i < numLines; i++) 00397 { 00398 for (int j = 0; j < rowsInLine; j++) 00399 _hScrollPos[i*rowsInLine+j] += _lineScrollInc[i]; 00400 } 00401 } 00402 00403 // Update flash state 00404 _flashCounter++; 00405 if (_flashCounter >= _flashRate) 00406 { 00407 _flashCounter = 0; 00408 _flashState = !_flashState; 00409 for (int i = 0; i < numLines; i++) 00410 _lineInvert[i] = _lineHighlight[i] ? _flashState : false; 00411 } 00412 } 00413 00414 // Reverse bits in byte 00415 uint8_t LEDMatrix::reverseBits(uint8_t b) 00416 { 00417 b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; 00418 b = (b & 0xCC) >> 2 | (b & 0x33) << 2; 00419 b = (b & 0xAA) >> 1 | (b & 0x55) << 1; 00420 return b; 00421 } 00422 00423 // Display ASCII char 00424 int LEDMatrix::displayChar(int xPos, int yPos, char ch) 00425 { 00426 const int FONT_HEIGHT = 7; 00427 const int FONT_WIDTH = 5; 00428 00429 // Find the width of the character 00430 uint8_t chTotalBits = 0; 00431 int chIdxInFont = (ch % 128) - 0x20; 00432 // Special case for £, euro and yen signs 00433 if ((ch >= 0xa3) && (ch <= 0xa5)) 00434 chIdxInFont = ch - 0xa3 + 128 - ' '; 00435 for (int i = 0; i < FONT_HEIGHT; i++) 00436 { 00437 uint8_t chBits = font5x7[chIdxInFont][i]; 00438 chTotalBits |= chBits; 00439 } 00440 uint8_t rightShift = 0; 00441 for (int j = 0; j < FONT_WIDTH; j++) 00442 { 00443 if (chTotalBits & 0x01) 00444 break; 00445 chTotalBits = chTotalBits >> 1; 00446 rightShift++; 00447 } 00448 uint8_t charWidth = 8; 00449 for (int j = 0; j < FONT_WIDTH+1; j++) 00450 { 00451 if (chTotalBits & 0x80) 00452 break; 00453 chTotalBits = chTotalBits << 1; 00454 charWidth--; 00455 } 00456 00457 // display character 00458 int xOffset = xPos / 8; 00459 int bitOffset = xPos % 8; 00460 // printf("%c %d %d %d %d\n", ch, charPos, charWidth, xOffset, bitOffset); 00461 if (xOffset >= (dispBufWidth/8)) 00462 return 0; 00463 00464 // Copy the bits of the character into the buffer 00465 for (int i = 0; i < FONT_HEIGHT; i++) 00466 { 00467 // Check we don't go off the display buffer 00468 int rowIdx = i + yPos; 00469 if (rowIdx > height) 00470 break; 00471 00472 // 00473 uint8_t chBits = font5x7[chIdxInFont][i] >> rightShift; 00474 int dispBufPos = (rowIdx * (dispBufWidth/8) + xOffset); 00475 _pDisplayBuf[dispBufPos] |= ((chBits << (8 - charWidth)) >> bitOffset); 00476 if (xOffset + 1 < (dispBufWidth/8)) 00477 _pDisplayBuf[dispBufPos + 1] |= ((chBits << (8-bitOffset)) << (8 - charWidth)); 00478 } 00479 00480 return charWidth; 00481 } 00482 00483 // Display a large digit 00484 int LEDMatrix::displayLargeDigit(int curX, int curY, char ch) 00485 { 00486 // Bounds check 00487 if ((ch < '0') || (ch > '9')) 00488 return 0; 00489 00490 // Get character data 00491 const uint8_t* charData = bigFont[ch-'0']; 00492 int numLines = sizeof(bigFont[0])/sizeof(bigFont[0][0]); 00493 00494 // Find the position and width of the character 00495 uint16_t chTotalBits = 0; 00496 for (int i = 0; i < numLines; i++) 00497 chTotalBits |= charData[i]; 00498 uint16_t rightShift = 0; 00499 for (; rightShift < 16; rightShift++) 00500 { 00501 if (chTotalBits & 0x01) 00502 break; 00503 chTotalBits = chTotalBits >> 1; 00504 } 00505 uint16_t charWidth = 16; 00506 for (; charWidth > 0; charWidth--) 00507 { 00508 if (chTotalBits & 0x8000) 00509 break; 00510 chTotalBits = chTotalBits << 1; 00511 } 00512 00513 // display character 00514 int xOffset = curX / 8; 00515 int bitOffset = curX % 8; 00516 // printf("%c %d %d %d %d %d\n", ch, curX, charWidth, rightShift, xOffset, bitOffset); 00517 if (xOffset >= (dispBufWidth/8)) 00518 return 0; 00519 for (int i = 0; i < numLines; i++) 00520 { 00521 uint32_t chBits = charData[i] >> rightShift; 00522 chBits = (chBits << (24-charWidth)) >> bitOffset; 00523 for (int j = 0; j < 3; j++) 00524 { 00525 if (xOffset + j >= (dispBufWidth/8)) 00526 break; 00527 _pDisplayBuf[(i + curY) * (dispBufWidth/8) + xOffset + j] |= ((chBits >> (16-j*8)) & 0xff); 00528 } 00529 } 00530 00531 return charWidth; 00532 } 00533 00534 // Display line of characters 00535 int LEDMatrix::displayLine(int lineIdx, const char* line) 00536 { 00537 if (lineIdx >= numLines) 00538 lineIdx = 0; 00539 _isBusy = true; 00540 int curX = 0; 00541 int curY = lineIdx * height/numLines; 00542 for (int chIdx = 0; chIdx < strlen(line); chIdx++) 00543 { 00544 curX += displayChar(curX, curY, line[chIdx]) + _charSeparation; 00545 } 00546 _isBusy = false; 00547 return curX; 00548 } 00549
Generated on Thu Jul 14 2022 22:43:16 by 1.7.2