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.
Dependencies: ELEC2645_JoystickLCD_LPC1768_2021
N5110.cpp
00001 #include "mbed.h" 00002 #include "N5110.h" 00003 00004 00005 // overloaded constructor includes power pin - LCD Vcc connected to GPIO pin 00006 // this constructor works fine with LPC1768 - enough current sourced from GPIO 00007 // to power LCD. Doesn't work well with K64F. 00008 N5110::N5110(PinName const pwrPin, 00009 PinName const scePin, 00010 PinName const rstPin, 00011 PinName const dcPin, 00012 PinName const mosiPin, 00013 PinName const sclkPin, 00014 PinName const ledPin) 00015 : 00016 _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise 00017 _led(new DigitalOut(ledPin)), 00018 _pwr(new DigitalOut(pwrPin)), 00019 _sce(new DigitalOut(scePin)), 00020 _rst(new DigitalOut(rstPin)), 00021 _dc(new DigitalOut(dcPin)) 00022 {} 00023 00024 // overloaded constructor does not include power pin - LCD Vcc must be tied to +3V3 00025 // Best to use this with K64F as the GPIO hasn't sufficient output current to reliably 00026 // drive the LCD. 00027 N5110::N5110(PinName const scePin, 00028 PinName const rstPin, 00029 PinName const dcPin, 00030 PinName const mosiPin, 00031 PinName const sclkPin, 00032 PinName const ledPin) 00033 : 00034 _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise 00035 _led(new DigitalOut(ledPin)), 00036 _pwr(NULL), // pwr not needed so null it to be safe 00037 _sce(new DigitalOut(scePin)), 00038 _rst(new DigitalOut(rstPin)), 00039 _dc(new DigitalOut(dcPin)) 00040 {} 00041 00042 00043 N5110::~N5110() 00044 { 00045 delete _spi; 00046 00047 if(_pwr) { 00048 delete _pwr; 00049 } 00050 00051 delete _led; 00052 delete _sce; 00053 delete _rst; 00054 delete _dc; 00055 } 00056 00057 // initialise function - powers up and sends the initialisation commands 00058 void N5110::init() 00059 { 00060 turnOn(); // power up 00061 reset(); // reset LCD - must be done within 100 ms 00062 initSPI(); 00063 00064 backLightOn(); 00065 setContrast(0.55); // this may need tuning (say 0.4 to 0.6) 00066 setBias(3); // datasheet - 48:1 mux - don't mess with if you don't know what you're doing! (0 to 7) 00067 setTempCoefficient(0); // datasheet - may need increasing (range 0 to 3) at very low temperatures 00068 normalMode(); // normal video mode by default 00069 00070 clearRAM(); // RAM is undefined at power-up so clear to be sure 00071 clear(); // clear buffer 00072 } 00073 00074 // sets normal video mode (black on white) 00075 void N5110::normalMode() 00076 { 00077 sendCommand(0b00100000); // basic instruction 00078 sendCommand(0b00001100); // normal video mode- datasheet 00079 } 00080 00081 // sets normal video mode (white on black) 00082 void N5110::inverseMode() 00083 { 00084 sendCommand(0b00100000); // basic instruction 00085 sendCommand(0b00001101); // inverse video mode - datasheet 00086 } 00087 00088 // function to power up the LCD and backlight - only works when using GPIO to power 00089 void N5110::turnOn() 00090 { 00091 if (_pwr != NULL) { 00092 _pwr->write(1); // apply power 00093 } 00094 } 00095 00096 // function to power down LCD 00097 void N5110::turnOff() 00098 { 00099 clear(); // clear buffer 00100 refresh(); 00101 backLightOff(); // turn backlight off 00102 clearRAM(); // clear RAM to ensure specified current consumption 00103 // send command to ensure we are in basic mode 00104 00105 sendCommand(0b00100000); // basic mode 00106 sendCommand(0b00001000); // clear display 00107 sendCommand(0b00100001); // extended mode 00108 sendCommand(0b00100100); // power down 00109 00110 // if we are powering the LCD using the GPIO then make it low to turn off 00111 if (_pwr != NULL) { 00112 wait_ms(10); // small delay and then turn off the power pin 00113 _pwr->write(0); // turn off power 00114 } 00115 00116 } 00117 00118 // function to change LED backlight brightness 00119 void N5110::backLightOn() 00120 { 00121 _led->write(1); 00122 } 00123 00124 // function to change LED backlight brightness 00125 void N5110::backLightOff() 00126 { 00127 _led->write(0); 00128 } 00129 00130 void N5110::setContrast(float contrast) { 00131 00132 // enforce limits 00133 if (contrast > 1.0f) 00134 contrast = 1.0f; 00135 else if (contrast < 0.0f) 00136 contrast = 0.0; 00137 00138 // convert to char in range 0 to 127 (i.e. 6 bits) 00139 char ic = char(contrast*127.0f); 00140 00141 sendCommand(0b00100001); // extended instruction set 00142 sendCommand(0b10000000 | ic); // set Vop (which controls contrast) 00143 sendCommand(0b00100000); // back to basic instruction set 00144 } 00145 00146 void N5110::setTempCoefficient(char tc) { 00147 00148 // enforce limits 00149 if (tc>3) { 00150 tc=3; 00151 } 00152 00153 // temperature coefficient may need increasing at low temperatures 00154 00155 sendCommand(0b00100001); // extended instruction set 00156 sendCommand(0b00000100 | tc); 00157 sendCommand(0b00100000); // back to basic instruction set 00158 } 00159 00160 void N5110::setBias(char bias) { 00161 00162 // from data sheet 00163 // bias mux rate 00164 // 0 1:100 00165 // 1 1:80 00166 // 2 1:65 00167 // 3 1:48 (default) 00168 // 4 1:40/1:34 00169 // 5 1:24 00170 // 6 1:18/1:16 00171 // 7 1:10/1:9/1:8 00172 00173 // enforce limits 00174 if (bias>7) { 00175 bias=7; 00176 } 00177 00178 sendCommand(0b00100001); // extended mode instruction 00179 sendCommand(0b00010000 | bias); 00180 sendCommand(0b00100000); // end of extended mode instruction 00181 } 00182 00183 // pulse the active low reset line 00184 void N5110::reset() 00185 { 00186 _rst->write(0); // reset the LCD 00187 _rst->write(1); 00188 } 00189 00190 // function to initialise SPI peripheral 00191 void N5110::initSPI() 00192 { 00193 _spi->format(8,1); // 8 bits, Mode 1 - polarity 0, phase 1 - base value of clock is 0, data captured on falling edge/propagated on rising edge 00194 _spi->frequency(4000000); // maximum of screen is 4 MHz 00195 } 00196 00197 // send a command to the display 00198 void N5110::sendCommand(unsigned char command) 00199 { 00200 _dc->write(0); // set DC low for command 00201 _sce->write(0); // set CE low to begin frame 00202 _spi->write(command); // send command 00203 _dc->write(1); // turn back to data by default 00204 _sce->write(1); // set CE high to end frame (expected for transmission of single byte) 00205 } 00206 00207 // send data to the display at the current XY address 00208 // dc is set to 1 (i.e. data) after sending a command and so should 00209 // be the default mode. 00210 void N5110::sendData(unsigned char data) 00211 { 00212 _sce->write(0); // set CE low to begin frame 00213 _spi->write(data); 00214 _sce->write(1); // set CE high to end frame (expected for transmission of single byte) 00215 } 00216 00217 // this function writes 0 to the 504 bytes to clear the RAM 00218 void N5110::clearRAM() 00219 { 00220 _sce->write(0); //set CE low to begin frame 00221 for(int i = 0; i < WIDTH * HEIGHT; i++) { // 48 x 84 bits = 504 bytes 00222 _spi->write(0x00); // send 0's 00223 } 00224 _sce->write(1); // set CE high to end frame 00225 } 00226 00227 // function to set the XY address in RAM for subsequenct data write 00228 void N5110::setXYAddress(unsigned int const x, 00229 unsigned int const y) 00230 { 00231 if (x<WIDTH && y<HEIGHT) { // check within range 00232 sendCommand(0b00100000); // basic instruction 00233 sendCommand(0b10000000 | x); // send addresses to display with relevant mask 00234 sendCommand(0b01000000 | y); 00235 } 00236 } 00237 00238 // These functions are used to set, clear and get the value of pixels in the display 00239 // Pixels are addressed in the range of 0 to 47 (y) and 0 to 83 (x). The refresh() 00240 // function must be called after set and clear in order to update the display 00241 void N5110::setPixel(unsigned int const x, 00242 unsigned int const y, 00243 bool const state) 00244 { 00245 if (x<WIDTH && y<HEIGHT) { // check within range 00246 // calculate bank and shift 1 to required position in the data byte 00247 if(state) buffer[x][y/8] |= (1 << y%8); 00248 else buffer[x][y/8] &= ~(1 << y%8); 00249 } 00250 } 00251 00252 void N5110::clearPixel(unsigned int const x, 00253 unsigned int const y) 00254 { 00255 if (x<WIDTH && y<HEIGHT) { // check within range 00256 // calculate bank and shift 1 to required position (using bit clear) 00257 buffer[x][y/8] &= ~(1 << y%8); 00258 } 00259 } 00260 00261 int N5110::getPixel(unsigned int const x, 00262 unsigned int const y) const 00263 { 00264 if (x<WIDTH && y<HEIGHT) { // check within range 00265 // return relevant bank and mask required bit 00266 00267 int pixel = (int) buffer[x][y/8] & (1 << y%8); 00268 00269 if (pixel) 00270 return 1; 00271 else 00272 return 0; 00273 } 00274 00275 return 0; 00276 00277 } 00278 00279 // function to refresh the display 00280 void N5110::refresh() 00281 { 00282 setXYAddress(0,0); // important to set address back to 0,0 before refreshing display 00283 // address auto increments after printing string, so buffer[0][0] will not coincide 00284 // with top-left pixel after priting string 00285 00286 _sce->write(0); //set CE low to begin frame 00287 00288 for(int j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing 00289 for(int i = 0; i < WIDTH; i++) { 00290 _spi->write(buffer[i][j]); // send buffer 00291 } 00292 } 00293 _sce->write(1); // set CE high to end frame 00294 00295 } 00296 00297 // fills the buffer with random bytes. Can be used to test the display. 00298 // The rand() function isn't seeded so it probably creates the same pattern everytime 00299 void N5110::randomiseBuffer() 00300 { 00301 int i,j; 00302 for(j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing 00303 for(i = 0; i < WIDTH; i++) { 00304 buffer[i][j] = rand()%256; // generate random byte 00305 } 00306 } 00307 00308 } 00309 00310 // function to print 5x7 font 00311 void N5110::printChar(char const c, 00312 unsigned int const x, 00313 unsigned int const y) 00314 { 00315 if (y<BANKS) { // check if printing in range of y banks 00316 00317 for (int i = 0; i < 5 ; i++ ) { 00318 int pixel_x = x+i; 00319 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83) 00320 break; 00321 buffer[pixel_x][y] = font5x7[(c - 32)*5 + i]; 00322 // array is offset by 32 relative to ASCII, each character is 5 pixels wide 00323 } 00324 00325 } 00326 } 00327 00328 // function to print string at specified position 00329 void N5110::printString(const char *str, 00330 unsigned int const x, 00331 unsigned int const y) 00332 { 00333 if (y<BANKS) { // check if printing in range of y banks 00334 00335 int n = 0 ; // counter for number of characters in string 00336 // loop through string and print character 00337 while(*str) { 00338 00339 // writes the character bitmap data to the buffer, so that 00340 // text and pixels can be displayed at the same time 00341 for (int i = 0; i < 5 ; i++ ) { 00342 int pixel_x = x+i+n*6; 00343 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83) 00344 break; 00345 buffer[pixel_x][y] = font5x7[(*str - 32)*5 + i]; 00346 } 00347 str++; // go to next character in string 00348 n++; // increment index 00349 } 00350 } 00351 } 00352 00353 // function to clear the screen buffer 00354 void N5110::clear() 00355 { 00356 memset(buffer,0,sizeof(buffer)); 00357 } 00358 00359 // function to plot array on display 00360 void N5110::plotArray(float const array[]) 00361 { 00362 for (int i=0; i<WIDTH; i++) { // loop through array 00363 // elements are normalised from 0.0 to 1.0, so multiply 00364 // by 47 to convert to pixel range, and subtract from 47 00365 // since top-left is 0,0 in the display geometry 00366 setPixel(i,47 - int(array[i]*47.0f),true); 00367 } 00368 00369 } 00370 00371 // function to draw circle 00372 void N5110:: drawCircle(unsigned int const x0, 00373 unsigned int const y0, 00374 unsigned int const radius, 00375 FillType const fill) 00376 { 00377 // from http://en.wikipedia.org/wiki/Midpoint_circle_algorithm 00378 int x = radius; 00379 int y = 0; 00380 int radiusError = 1-x; 00381 00382 while(x >= y) { 00383 00384 // if transparent, just draw outline 00385 if (fill == FILL_TRANSPARENT) { 00386 setPixel( x + x0, y + y0,true); 00387 setPixel(-x + x0, y + y0,true); 00388 setPixel( y + x0, x + y0,true); 00389 setPixel(-y + x0, x + y0,true); 00390 setPixel(-y + x0, -x + y0,true); 00391 setPixel( y + x0, -x + y0,true); 00392 setPixel( x + x0, -y + y0,true); 00393 setPixel(-x + x0, -y + y0,true); 00394 } else { // drawing filled circle, so draw lines between points at same y value 00395 00396 int type = (fill==FILL_BLACK) ? 1:0; // black or white fill 00397 00398 drawLine(x+x0,y+y0,-x+x0,y+y0,0,type); 00399 drawLine(y+x0,x+y0,-y+x0,x+y0,0,type); 00400 drawLine(y+x0,-x+y0,-y+x0,-x+y0,0,type); 00401 drawLine(x+x0,-y+y0,-x+x0,-y+y0,0,type); 00402 } 00403 00404 y++; 00405 if (radiusError < 0) { 00406 radiusError += 2 * y + 1; 00407 } else { 00408 x--; 00409 radiusError += 2 * (y - x) + 1; 00410 } 00411 } 00412 00413 } 00414 00415 // function to draw ellipse 00416 void N5110:: drawEllipse(unsigned int const xc, 00417 unsigned int const yc, 00418 unsigned int const rx, 00419 unsigned int const ry) 00420 { 00421 int rx2 = rx*rx, ry2 = ry*ry; 00422 int x = 0, y = ry; //Starting point 00423 00424 int incSW = ry2*2 + rx2*2; 00425 00426 // Slopes deduced from incremental algorithm with the second-order logic 00427 int W = ry2*(-2*x + 3); 00428 int S = rx2*(-2*y + 3); 00429 int SW = W + S; 00430 00431 // Decision parameter of Region 1 and Region 2 00432 int p1 = ry2 - rx2*ry + rx2/4; 00433 int p2 = ry2*(x - 0.5)*(x - 0.5) + rx2*(y - 1)*(y - 1) - rx2*ry2; 00434 00435 // Region 1 00436 while(rx2*(y-0.5) >= ry2*(-x-1)) { 00437 00438 // Set points based on 4-way symmetry 00439 setPixel(-x+xc,-y+yc, true); 00440 setPixel(-x+xc, y+yc, true); 00441 setPixel( x+xc, y+yc, true); 00442 setPixel( x+xc,-y+yc, true); 00443 00444 if(p1 > 0) { 00445 p1 += SW; 00446 W += ry2*2; 00447 SW += incSW; 00448 y--; 00449 } 00450 else { 00451 p1 += W; 00452 W += 2*ry2; 00453 SW += 2*ry2; 00454 } 00455 x--; 00456 } 00457 00458 SW = ry2*(2 - 2*x) + rx2*(-2*y + 3); 00459 00460 // Region 2 00461 while(y >= 0) { 00462 00463 // Set points based on 4-way symmetry 00464 setPixel(-x+xc,-y+yc, true); 00465 setPixel(-x+xc, y+yc, true); 00466 setPixel( x+xc, y+yc, true); 00467 setPixel( x+xc,-y+yc, true); 00468 00469 if(p2 > 0) { 00470 p2 += S; 00471 S += rx2*2; 00472 SW += rx2*2; 00473 } 00474 else { 00475 p2 += SW; 00476 SW += incSW; 00477 S += rx2*2; 00478 x--; 00479 } 00480 y--; 00481 } 00482 } 00483 00484 // take points on a curve, decide whether to draw them or not 00485 void N5110::drawCurve(std::vector<Vector2Df> curve_points, float offset, int dash_len, int type) 00486 { 00487 if(type == TYPE_SOLID){ 00488 for(int i = 0; i < curve_points.size()-1; i++){ 00489 // take the current and the following coordinates and draw a line between them 00490 drawLine(static_cast<int>(curve_points[i].x),static_cast<int>(curve_points[i].y), 00491 static_cast<int>(curve_points[i+1].x),static_cast<int>(curve_points[i+1].y),0,1); 00492 } 00493 } 00494 if(type == TYPE_DOTTED){ 00495 int counter = 0; 00496 for(int i = curve_points.size()-1; i > 0 ; i--){ 00497 int x0 = static_cast<int>(curve_points[i].x); 00498 int x1 = static_cast<int>(curve_points[i-1].x); 00499 int y0 = static_cast<int>(curve_points[i].y); 00500 int y1 = static_cast<int>(curve_points[i-1].y); 00501 00502 int const y_range = y0 - y1; 00503 int const x_range = x1 - x0; 00504 00505 // ensure we loop from smallest to largest or else for-loop won't run as expected 00506 //unsigned int const start = y_range > 0 ? y0:y1; 00507 //unsigned int const stop = y_range > 0 ? y1:y0; 00508 00509 for (unsigned int y = y0; y <= y1 ; y++) { 00510 // do linear interpolation 00511 int const dy = y0 - y; 00512 unsigned int const x = x0 + (x_range * (dy / (float)y_range)); 00513 00514 // If the line type is '0', this will clear the pixel 00515 // If it is '1' or '2', the pixel will be set 00516 setPixel(x,y, fmod(pow(counter, 0.6) - fmod(offset, (2 * dash_len)), (2 * dash_len)) < dash_len); 00517 counter++; 00518 } 00519 } 00520 } 00521 } 00522 00523 void N5110::drawLine(unsigned int const x0, 00524 unsigned int const y0, 00525 unsigned int const x1, 00526 unsigned int const y1, 00527 unsigned int const offset, 00528 unsigned int const step) 00529 { 00530 // Note that the ranges can be negative so we have to turn the input values 00531 // into signed integers first 00532 int const y_range = static_cast<int>(y1) - static_cast<int>(y0); 00533 int const x_range = static_cast<int>(x1) - static_cast<int>(x0); 00534 00535 // make sure we loop over the largest range to get the most pixels on the display 00536 // for instance, if drawing a vertical line (x_range = 0), we need to loop down the y pixels 00537 // or else we'll only end up with 1 pixel in the x column 00538 if ( abs(x_range) > abs(y_range) ) { 00539 00540 // ensure we loop from smallest to largest or else for-loop won't run as expected 00541 unsigned int const start = x_range > 0 ? x0:x1; 00542 unsigned int const stop = x_range > 0 ? x1:x0; 00543 00544 // loop between x pixels 00545 for (unsigned int x = start; x<= stop ; x+=step) { 00546 // do linear interpolation 00547 int const dx = static_cast<int>(x) - static_cast<int>(x0); 00548 unsigned int const y = y0 + y_range * dx / x_range; 00549 00550 // If the line type is '0', this will clear the pixel 00551 // If it is '1' or '2', the pixel will be set 00552 setPixel(x,y, FILL_BLACK); 00553 } 00554 } else { 00555 00556 // ensure we loop from smallest to largest or else for-loop won't run as expected 00557 unsigned int const start = y_range > 0 ? y0:y1; 00558 unsigned int const stop = y_range > 0 ? y1:y0; 00559 00560 for (unsigned int y = start; y<= stop ; y+=step) { 00561 // do linear interpolation 00562 int const dy = static_cast<int>(y)-static_cast<int>(y0); 00563 unsigned int const x = x0 + x_range * dy / y_range; 00564 00565 // If the line type is '0', this will clear the pixel 00566 // If it is '1' or '2', the pixel will be set 00567 setPixel(x,y, FILL_BLACK); 00568 } 00569 } 00570 00571 } 00572 00573 void N5110::drawRect(unsigned int const x0, 00574 unsigned int const y0, 00575 unsigned int const width, 00576 unsigned int const height, 00577 FillType const fill) 00578 { 00579 if (fill == FILL_TRANSPARENT) { // transparent, just outline 00580 drawLine(x0,y0,x0+(width-1),y0,0,1); // top 00581 drawLine(x0,y0+(height-1),x0+(width-1),y0+(height-1),0,1); // bottom 00582 drawLine(x0,y0,x0,y0+(height-1),0,1); // left 00583 drawLine(x0+(width-1),y0,x0+(width-1),y0+(height-1),0,1); // right 00584 } else { // filled rectangle 00585 int step = (fill==FILL_BLACK) ? 1:0; // black or white fill 00586 for (int y = y0; y<y0+height; y++) { // loop through rows of rectangle 00587 drawLine(x0,y,x0+(width-1),y,0,step); // draw line across screen 00588 } 00589 } 00590 } 00591 00592 void N5110::drawSprite(int x0, 00593 int y0, 00594 int nrows, 00595 int ncols, 00596 int *sprite) 00597 { 00598 for (int i = 0; i < nrows; i++) { 00599 for (int j = 0 ; j < ncols ; j++) { 00600 00601 int pixel = *((sprite+i*ncols)+j); 00602 setPixel(x0+j,y0+i, pixel); 00603 } 00604 } 00605 }
Generated on Thu Jul 28 2022 01:52:48 by
1.7.2