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.
main.cpp
00001 /** 00002 @file N5110.cpp 00003 00004 @brief Member functions implementations 00005 00006 */ 00007 #include "mbed.h" 00008 #include "N5110.h" 00009 #include "MMA8452.h" 00010 #include "Beep.h" 00011 00012 00013 N5110::N5110(PinName pwrPin, PinName scePin, PinName rstPin, PinName dcPin, PinName mosiPin, PinName sclkPin, PinName ledPin) 00014 { 00015 00016 spi = new SPI(mosiPin,NC,sclkPin); // create new SPI instance and initialise 00017 initSPI(); 00018 00019 // set up pins as required 00020 led = new PwmOut(ledPin); 00021 pwr = new DigitalOut(pwrPin); 00022 sce = new DigitalOut(scePin); 00023 rst = new DigitalOut(rstPin); 00024 dc = new DigitalOut(dcPin); 00025 00026 } 00027 00028 // initialise function - powers up and sends the initialisation commands 00029 void N5110::init() 00030 { 00031 turnOn(); // power up 00032 wait_ms(10); // small delay seems to prevent spurious pixels during mbed reset 00033 reset(); // reset LCD - must be done within 100 ms 00034 00035 // function set - extended 00036 sendCommand(0x20 | CMD_FS_ACTIVE_MODE | CMD_FS_HORIZONTAL_MODE | CMD_FS_EXTENDED_MODE); 00037 // Don't completely understand these parameters - they seem to work as they are 00038 // Consult the datasheet if you need to change them 00039 sendCommand(CMD_VOP_7V38); // operating voltage - these values are from Chris Yan's Library 00040 sendCommand(CMD_TC_TEMP_2); // temperature control 00041 sendCommand(CMD_BI_MUX_48); // bias 00042 00043 // function set - basic 00044 sendCommand(0x20 | CMD_FS_ACTIVE_MODE | CMD_FS_HORIZONTAL_MODE | CMD_FS_BASIC_MODE); 00045 normalMode(); // normal video mode by default 00046 sendCommand(CMD_DC_NORMAL_MODE); // black on white 00047 00048 // RAM is undefined at power-up so clear 00049 clearRAM(); 00050 00051 } 00052 00053 // sets normal video mode (black on white) 00054 void N5110::normalMode() 00055 { 00056 sendCommand(CMD_DC_NORMAL_MODE); 00057 00058 } 00059 00060 // sets normal video mode (white on black) 00061 void N5110::inverseMode() 00062 { 00063 sendCommand(CMD_DC_INVERT_VIDEO); 00064 } 00065 00066 // function to power up the LCD and backlight 00067 void N5110::turnOn() 00068 { 00069 // set brightness of LED - 0.0 to 1.0 - default is 50% 00070 setBrightness(0.5); 00071 pwr->write(1); // apply power 00072 } 00073 00074 // function to power down LCD 00075 void N5110::turnOff() 00076 { 00077 setBrightness(0.0); // turn backlight off 00078 clearRAM(); // clear RAM to ensure specified current consumption 00079 // send command to ensure we are in basic mode 00080 sendCommand(0x20 | CMD_FS_ACTIVE_MODE | CMD_FS_HORIZONTAL_MODE | CMD_FS_BASIC_MODE); 00081 // clear the display 00082 sendCommand(CMD_DC_CLEAR_DISPLAY); 00083 // enter the extended mode and power down 00084 sendCommand(0x20 | CMD_FS_POWER_DOWN_MODE | CMD_FS_HORIZONTAL_MODE | CMD_FS_EXTENDED_MODE); 00085 // small delay and then turn off the power pin 00086 wait_ms(10); 00087 pwr->write(0); 00088 00089 } 00090 00091 // function to change LED backlight brightness 00092 void N5110::setBrightness(float brightness) 00093 { 00094 // check whether brightness is within range 00095 if (brightness < 0.0) 00096 brightness = 0.0; 00097 if (brightness > 1.0) 00098 brightness = 1.0; 00099 // set PWM duty cycle 00100 led->write(brightness); 00101 } 00102 00103 00104 // pulse the active low reset line 00105 void N5110::reset() 00106 { 00107 rst->write(0); // reset the LCD 00108 rst->write(1); 00109 } 00110 00111 // function to initialise SPI peripheral 00112 void N5110::initSPI() 00113 { 00114 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 00115 spi->frequency(4000000); // maximum of screen is 4 MHz 00116 } 00117 00118 // send a command to the display 00119 void N5110::sendCommand(unsigned char command) 00120 { 00121 dc->write(0); // set DC low for command 00122 sce->write(0); // set CE low to begin frame 00123 spi->write(command); // send command 00124 dc->write(1); // turn back to data by default 00125 sce->write(1); // set CE high to end frame (expected for transmission of single byte) 00126 00127 } 00128 00129 // send data to the display at the current XY address 00130 // dc is set to 1 (i.e. data) after sending a command and so should 00131 // be the default mode. 00132 void N5110::sendData(unsigned char data) 00133 { 00134 sce->write(0); // set CE low to begin frame 00135 spi->write(data); 00136 sce->write(1); // set CE high to end frame (expected for transmission of single byte) 00137 } 00138 00139 // this function writes 0 to the 504 bytes to clear the RAM 00140 void N5110::clearRAM() 00141 { 00142 int i; 00143 sce->write(0); //set CE low to begin frame 00144 for(i = 0; i < WIDTH * HEIGHT; i++) { // 48 x 84 bits = 504 bytes 00145 spi->write(0x00); // send 0's 00146 } 00147 sce->write(1); // set CE high to end frame 00148 00149 } 00150 00151 // function to set the XY address in RAM for subsequenct data write 00152 void N5110::setXYAddress(int x, int y) 00153 { 00154 if (x>=0 && x<WIDTH && y>=0 && y<HEIGHT) { // check within range 00155 sendCommand(0x80 | x); // send addresses to display with relevant mask 00156 sendCommand(0x40 | y); 00157 } 00158 } 00159 00160 // These functions are used to set, clear and get the value of pixels in the display 00161 // Pixels are addressed in the range of 0 to 47 (y) and 0 to 83 (x). The refresh() 00162 // function must be called after set and clear in order to update the display 00163 void N5110::setPixel(int x, int y) 00164 { 00165 if (x>=0 && x<WIDTH && y>=0 && y<HEIGHT) { // check within range 00166 // calculate bank and shift 1 to required position in the data byte 00167 buffer[x][y/8] |= (1 << y%8); 00168 } 00169 } 00170 00171 void N5110::clearPixel(int x, int y) 00172 { 00173 if (x>=0 && x<WIDTH && y>=0 && y<HEIGHT) { // check within range 00174 // calculate bank and shift 1 to required position (using bit clear) 00175 buffer[x][y/8] &= ~(1 << y%8); 00176 } 00177 } 00178 00179 int N5110::getPixel(int x, int y) 00180 { 00181 if (x>=0 && x<WIDTH && y>=0 && y<HEIGHT) { // check within range 00182 // return relevant bank and mask required bit 00183 return (int) buffer[x][y/8] & (1 << y%8); 00184 // note this does not necessarily return 1 - a non-zero number represents a pixel 00185 } else { 00186 return 0; 00187 } 00188 } 00189 00190 // function to refresh the display 00191 void N5110::refresh() 00192 { 00193 int i,j; 00194 00195 setXYAddress(0,0); // important to set address back to 0,0 before refreshing display 00196 // address auto increments after printing string, so buffer[0][0] will not coincide 00197 // with top-left pixel after priting string 00198 00199 sce->write(0); //set CE low to begin frame 00200 00201 for(j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing 00202 for(i = 0; i < WIDTH; i++) { 00203 spi->write(buffer[i][j]); // send buffer 00204 } 00205 } 00206 sce->write(1); // set CE high to end frame 00207 00208 } 00209 00210 // fills the buffer with random bytes. Can be used to test the display. 00211 // The rand() function isn't seeded so it probably creates the same pattern everytime 00212 void N5110::randomiseBuffer() 00213 { 00214 int i,j; 00215 for(j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing 00216 for(i = 0; i < WIDTH; i++) { 00217 buffer[i][j] = rand()%256; // generate random byte 00218 } 00219 } 00220 00221 } 00222 00223 // function to print 5x7 font 00224 void N5110::printChar(char c,int x,int y) 00225 { 00226 if (y>=0 && y<BANKS) { // check if printing in range of y banks 00227 00228 for (int i = 0; i < 5 ; i++ ) { 00229 int pixel_x = x+i; 00230 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83) 00231 break; 00232 buffer[pixel_x][y] = font5x7[(c - 32)*5 + i]; 00233 // array is offset by 32 relative to ASCII, each character is 5 pixels wide 00234 } 00235 00236 refresh(); // this sends the buffer to the display and sets address (cursor) back to 0,0 00237 } 00238 } 00239 00240 // function to print string at specified position 00241 void N5110::printString(const char * str,int x,int y) 00242 { 00243 if (y>=0 && y<BANKS) { // check if printing in range of y banks 00244 00245 int n = 0 ; // counter for number of characters in string 00246 // loop through string and print character 00247 while(*str) { 00248 00249 // writes the character bitmap data to the buffer, so that 00250 // text and pixels can be displayed at the same time 00251 for (int i = 0; i < 5 ; i++ ) { 00252 int pixel_x = x+i+n*6; 00253 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83) 00254 break; 00255 buffer[pixel_x][y] = font5x7[(*str - 32)*5 + i]; 00256 } 00257 00258 str++; // go to next character in string 00259 00260 n++; // increment index 00261 00262 } 00263 00264 refresh(); // this sends the buffer to the display and sets address (cursor) back to 0,0 00265 } 00266 } 00267 00268 // function to clear the screen 00269 void N5110::clear() 00270 { 00271 clearBuffer(); // clear the buffer then call the refresh function 00272 refresh(); 00273 } 00274 00275 // function to clear the buffer 00276 void N5110::clearBuffer() 00277 { 00278 int i,j; 00279 for (i=0; i<WIDTH; i++) { // loop through the banks and set the buffer to 0 00280 for (j=0; j<BANKS; j++) { 00281 buffer[i][j]=0; 00282 } 00283 } 00284 } 00285 00286 // function to plot array on display 00287 void N5110::plotArray(float array[]) 00288 { 00289 00290 int i; 00291 00292 for (i=0; i<WIDTH; i++) { // loop through array 00293 // elements are normalised from 0.0 to 1.0, so multiply 00294 // by 47 to convert to pixel range, and subtract from 47 00295 // since top-left is 0,0 in the display geometry 00296 setPixel(i,47 - int(array[i]*47.0)); 00297 } 00298 00299 refresh(); 00300 00301 } 00302 00303 // function to draw circle 00304 void N5110:: drawCircle(int x0,int y0,int radius,int fill) 00305 { 00306 // from http://en.wikipedia.org/wiki/Midpoint_circle_algorithm 00307 int x = radius; 00308 int y = 0; 00309 int radiusError = 1-x; 00310 00311 while(x >= y) { 00312 00313 // if transparent, just draw outline 00314 if (fill == 0) { 00315 setPixel( x + x0, y + y0); 00316 setPixel(-x + x0, y + y0); 00317 setPixel( y + x0, x + y0); 00318 setPixel(-y + x0, x + y0); 00319 setPixel(-y + x0, -x + y0); 00320 setPixel( y + x0, -x + y0); 00321 setPixel( x + x0, -y + y0); 00322 setPixel(-x + x0, -y + y0); 00323 } else { // drawing filled circle, so draw lines between points at same y value 00324 00325 int type = (fill==1) ? 1:0; // black or white fill 00326 00327 drawLine(x+x0,y+y0,-x+x0,y+y0,type); 00328 drawLine(y+x0,x+y0,-y+x0,x+y0,type); 00329 drawLine(y+x0,-x+y0,-y+x0,-x+y0,type); 00330 drawLine(x+x0,-y+y0,-x+x0,-y+y0,type); 00331 } 00332 00333 00334 y++; 00335 if (radiusError<0) { 00336 radiusError += 2 * y + 1; 00337 } else { 00338 x--; 00339 radiusError += 2 * (y - x) + 1; 00340 } 00341 } 00342 00343 } 00344 00345 void N5110::drawLine(int x0,int y0,int x1,int y1,int type) 00346 { 00347 int y_range = y1-y0; // calc range of y and x 00348 int x_range = x1-x0; 00349 int start,stop,step; 00350 00351 // if dotted line, set step to 2, else step is 1 00352 step = (type==2) ? 2:1; 00353 00354 // make sure we loop over the largest range to get the most pixels on the display 00355 // for instance, if drawing a vertical line (x_range = 0), we need to loop down the y pixels 00356 // or else we'll only end up with 1 pixel in the x column 00357 if ( abs(x_range) > abs(y_range) ) { 00358 00359 // ensure we loop from smallest to largest or else for-loop won't run as expected 00360 start = x1>x0 ? x0:x1; 00361 stop = x1>x0 ? x1:x0; 00362 00363 // loop between x pixels 00364 for (int x = start; x<= stop ; x+=step) { 00365 // do linear interpolation 00366 int y = y0 + (y1-y0)*(x-x0)/(x1-x0); 00367 00368 if (type == 0) // if 'white' line, turn off pixel 00369 clearPixel(x,y); 00370 else 00371 setPixel(x,y); // else if 'black' or 'dotted' turn on pixel 00372 } 00373 } else { 00374 00375 // ensure we loop from smallest to largest or else for-loop won't run as expected 00376 start = y1>y0 ? y0:y1; 00377 stop = y1>y0 ? y1:y0; 00378 00379 for (int y = start; y<= stop ; y+=step) { 00380 // do linear interpolation 00381 int x = x0 + (x1-x0)*(y-y0)/(y1-y0); 00382 00383 if (type == 0) // if 'white' line, turn off pixel 00384 clearPixel(x,y); 00385 else 00386 setPixel(x,y); // else if 'black' or 'dotted' turn on pixel 00387 00388 } 00389 } 00390 00391 } 00392 00393 void N5110::drawRect(int x0,int y0,int width,int height,int fill) 00394 { 00395 00396 if (fill == 0) { // transparent, just outline 00397 drawLine(x0,y0,x0+width,y0,1); // top 00398 drawLine(x0,y0+height,x0+width,y0+height,1); // bottom 00399 drawLine(x0,y0,x0,y0+height,1); // left 00400 drawLine(x0+width,y0,x0+width,y0+height,1); // right 00401 } else { // filled rectangle 00402 int type = (fill==1) ? 1:0; // black or white fill 00403 for (int y = y0; y<= y0+height; y++) { // loop through rows of rectangle 00404 drawLine(x0,y,x0+width,y,type); // draw line across screen 00405 } 00406 } 00407 00408 } 00409 00410 00411 00412 MMA8452:: MMA8452(PinName sdaPin, PinName sclPin) 00413 { 00414 i2c = new I2C(sdaPin,sclPin); // create new I2C instance and initialise 00415 i2c->frequency(400000); // I2C Fast Mode - 400kHz 00416 leds = new BusOut(LED4,LED3,LED2,LED1); // for debug 00417 } 00418 00419 void MMA8452::init() 00420 { 00421 00422 i2c->frequency(400000); // set Fast Mode I2C frequency (5.10 datasheet) 00423 00424 char data = readByteFromRegister(WHO_AM_I); // p18 datasheet 00425 if (data != 0x2A) { // if correct ID not found, hand and flash error message 00426 error(); 00427 } 00428 00429 // put into STANDBY while configuring 00430 data = readByteFromRegister(CTRL_REG1); // get current value of register 00431 data &= ~(1<<0); // clear bit 0 (p37 datasheet) 00432 sendByteToRegister(data,CTRL_REG1); 00433 00434 // Set output data rate, default is 800 Hz, will set to 100 Hz (clear b5, set b4/b3 - p37 datasheet) 00435 data = readByteFromRegister(CTRL_REG1); 00436 data &= ~(1<<5); 00437 data |= (1<<4); 00438 data |= (1<<3); 00439 sendByteToRegister(data,CTRL_REG1); 00440 00441 //// Can also change default 2g range to 4g or 8g (p22 datasheet) 00442 data = readByteFromRegister(XYZ_DATA_CFG); 00443 data |= (1<<0); // set bit 0 - 4g range 00444 sendByteToRegister(data,XYZ_DATA_CFG); 00445 00446 // set ACTIVE 00447 data = readByteFromRegister(CTRL_REG1); 00448 data |= (1<<0); // set bit 0 in CTRL_REG1 00449 sendByteToRegister(data,CTRL_REG1); 00450 00451 } 00452 00453 // read acceleration data from device 00454 Acceleration MMA8452::readValues() 00455 { 00456 // acceleration data stored in 6 registers (0x01 to 0x06) 00457 // device automatically increments register, so can read 6 bytes starting from OUT_X_MSB 00458 char data[6]; 00459 readBytesFromRegister(OUT_X_MSB,6,data); 00460 00461 char x_MSB = data[0]; // extract MSB and LSBs for x,y,z values 00462 char x_LSB = data[1]; 00463 char y_MSB = data[2]; 00464 char y_LSB = data[3]; 00465 char z_MSB = data[4]; 00466 char z_LSB = data[5]; 00467 00468 // [0:7] of MSB are 8 MSB of 12-bit value , [7:4] of LSB are 4 LSB's of 12-bit value 00469 // need to type-cast as numbers are in signed (2's complement) form (p20 datasheet) 00470 int x = (int16_t) (x_MSB << 8) | x_LSB; // combine bytes 00471 x >>= 4; // are left-aligned, so shift 4 places right to right-align 00472 int y = (int16_t) (y_MSB << 8) | y_LSB; 00473 y >>= 4; 00474 int z = (int16_t) (z_MSB << 8) | z_LSB; 00475 z >>= 4; 00476 00477 // sensitivity is 1024 counts/g in 2g mode (pg 9 datasheet) 00478 // " " 512 " 4g " 00479 // " " 256 " 8g " 00480 Acceleration acc; 00481 00482 acc.x = x/512.0; 00483 acc.y = y/512.0; 00484 acc.z = z/512.0; 00485 00486 return acc; 00487 } 00488 00489 // reads a byte from a specific register 00490 char MMA8452::readByteFromRegister(char reg) 00491 { 00492 int nack = i2c->write(MMA8452_W_ADDRESS,®,1,true); // send the register address to the slave 00493 // true as need to send repeated start condition (5.10.1 datasheet) 00494 // http://www.i2c-bus.org/repeated-start-condition/ 00495 if (nack) 00496 error(); // if we don't receive acknowledgement, flash error message 00497 00498 char rx; 00499 nack = i2c->read(MMA8452_R_ADDRESS,&rx,1); // read a byte from the register and store in buffer 00500 if (nack) 00501 error(); // if we don't receive acknowledgement, flash error message 00502 00503 return rx; 00504 } 00505 00506 // reads a series of bytes, starting from a specific register 00507 void MMA8452::readBytesFromRegister(char reg,int numberOfBytes,char bytes[]) 00508 { 00509 00510 int nack = i2c->write(MMA8452_W_ADDRESS,®,1,true); // send the slave write address and the configuration register address 00511 // true as need to send repeated start condition (5.10.1 datasheet) 00512 // http://www.i2c-bus.org/repeated-start-condition/ 00513 00514 if (nack) 00515 error(); // if we don't receive acknowledgement, flash error message 00516 00517 nack = i2c->read(MMA8452_R_ADDRESS,bytes,numberOfBytes); // read bytes 00518 if (nack) 00519 error(); // if we don't receive acknowledgement, flash error message 00520 00521 } 00522 00523 // sends a byte to a specific register 00524 void MMA8452::sendByteToRegister(char byte,char reg) 00525 { 00526 char data[2]; 00527 data[0] = reg; 00528 data[1] = byte; 00529 // send the register address, followed by the data 00530 int nack = i2c->write(MMA8452_W_ADDRESS,data,2); 00531 if (nack) 00532 error(); // if we don't receive acknowledgement, flash error message 00533 00534 } 00535 00536 void MMA8452::error() 00537 { 00538 while(1) { 00539 leds->write(15); 00540 wait(0.1); 00541 leds->write(0); 00542 wait(0.1); 00543 } 00544 } 00545 00546 00547 00548 00549 00550 00551 00552 00553 00554 00555 00556 N5110 lcd(p7,p8,p9,p10,p11,p13,p26); 00557 MMA8452 mma8452(p28,p27); // SDA, SCL 00558 Serial serial(USBTX,USBRX); 00559 DigitalOut myLED1(p24); 00560 InterruptIn button(p29); 00561 Beep buzzer(p21); 00562 BusOut leds (LED4,LED3,LED2,LED1); 00563 00564 int fsm[5]={1,3,8,12,0};//array for led in mbed 00565 int state=0; 00566 int buttonFlag=0;//button 00567 00568 void buttonPressed(){ 00569 buttonFlag=1; 00570 } 00571 00572 00573 int main() 00574 { 00575 // first need to initialise display and MMA8452 00576 00577 lcd.init(); 00578 mma8452.init();// 100 Hz update rate, ±4g scale 00579 00580 00581 lcd.normalMode(); 00582 00583 //rise up button 00584 button.rise(&buttonPressed); 00585 00586 //show initial interface 00587 lcd.printString("Acceleration",4,1); 00588 lcd.printString("And Angle",4,2); 00589 lcd.printString("Measurer",4,3); 00590 lcd.drawRect(2,2,78,43,0); // transparent, just outline 00591 lcd.refresh(); // need to refresh screen after drawing rects 00592 00593 00594 wait(2.0); 00595 lcd.clear(); 00596 00597 Acceleration acceleration; // Accleration structure declared in MMA8452 class 00598 00599 00600 while(1) { 00601 00602 00603 00604 lcd.printString("Acceleration:",0,0); 00605 lcd.printString("Angle:",0,4); 00606 00607 myLED1 = 0; 00608 00609 acceleration = mma8452.readValues(); // read current values and print over serial port 00610 00611 00612 00613 //show acceleration x,y,z 00614 char x[14]; 00615 int length=sprintf(x,"x = %.2f g",acceleration.x); 00616 if (length <= 14) 00617 lcd.printString(x,0,1); 00618 00619 char y[14]; 00620 int length2=sprintf(y,"y = %.2f g",acceleration.y); 00621 if (length2 <= 14) 00622 lcd.printString(y,0,2); 00623 00624 char z[14]; 00625 int length3=sprintf(z,"z = %.2f g",acceleration.z); 00626 if (length3 <= 14) 00627 lcd.printString(z,0,3); 00628 00629 //convert acceration in z to angle 00630 char angleZ[14]; 00631 float anglez=90-(acceleration.z/1*90); 00632 00633 00634 00635 // set button 00636 if (buttonFlag){ 00637 buttonFlag=0; 00638 int angle3=sprintf(angleZ,"%.2f",anglez); 00639 lcd.printString(angleZ,0,5); 00640 } 00641 00642 00643 00644 if (anglez>=30){ 00645 00646 myLED1 = 1; 00647 00648 } 00649 00650 00651 00652 if(anglez>=30&&acceleration.x>0){ 00653 00654 leds=fsm[0]; 00655 00656 } 00657 00658 00659 if(anglez>=60&&acceleration.x>0){ 00660 leds=fsm[1]; 00661 00662 } 00663 00664 00665 if(anglez>=30&&acceleration.x<0){ 00666 00667 leds=fsm[2]; 00668 } 00669 00670 00671 if(anglez>=60&&acceleration.x<0){ 00672 leds=fsm[3]; 00673 } 00674 00675 00676 if(anglez<30){ 00677 leds=fsm[4]; 00678 } 00679 00680 00681 if(anglez>=60){ 00682 00683 buzzer.beep(2000,0.5); 00684 } 00685 00686 00687 00688 wait(0.1); 00689 lcd.refresh(); 00690 00691 00692 00693 } 00694 00695 00696 }
Generated on Tue Jul 19 2022 21:33:49 by
1.7.2