Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
