/* MicroView Arduino Library Copyright (C) 2014 GeekAmmo This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include //#include #include // This fixed ugly GCC warning "only initialized variables can be placed into program memory area" #undef PROGMEM #define PROGMEM __attribute__((section(".progmem.data"))) // Add header of the fonts here. Remove as many as possible to conserve FLASH memory. #include #include #include #include <7segment.h> #include #include #include // Change the total fonts included #define TOTALFONTS 7 #define recvLEN 100 char serInStr[recvLEN]; // TODO - need to fix a value so that this will not take up too much memory. uint8_t serCmd[recvLEN]; // Add the font name as declared in the header file. Remove as many as possible to get conserve FLASH memory. const unsigned char *MicroView::fontsPointer[]={ font5x7 ,font8x16 ,sevensegment ,fontlargenumber ,space01 ,space02 ,space03 }; // TODO - Need to be able to let user add custom fonts from outside of the library // TODO - getTotalFonts(), addFont() return font number, removeFont() /** \brief MicroView screen buffer. Page buffer 64 x 48 divided by 8 = 384 bytes Page buffer is required because in SPI mode, the host cannot read the SSD1306's GDRAM of the controller. This page buffer serves as a scratch RAM for graphical functions. All drawing function will first be drawn on this page buffer, only upon calling display() function will transfer the page buffer to the actual LCD controller's memory. */ static uint8_t screenmemory [] = { // LCD Memory organised in 64 horizontal pixel and 6 rows of byte // B B .............B ----- // y y .............y | // t t .............t | // e e .............e | // 0 1 .............63 | // | // D0 D0.............D0 | ROW 0 // D1 D1.............D1 | // D2 D2.............D2 | // D3 D3.............D3 | // D4 D4.............D4 | // D5 D5.............D5 | // D6 D6.............D6 | // D7 D7.............D7 ---- //SparkFun Electronics LOGO // ROW0, BYTE0 to BYTE63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x07, 0x07, 0x06, 0x06, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ROW1, BYTE64 to BYTE127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x07, 0x0F, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ROW2, BYTE128 to BYTE191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ROW3, BYTE192 to BYTE255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ROW4, BYTE256 to BYTE319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ROW5, BYTE320 to BYTE383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /** \brief Initialisation of MicroView Library. Setup IO pins for SPI port then send initialisation commands to the SSD1306 controller inside the OLED. */ void MicroView::begin() { // default 5x7 font setFontType(0); setColor(WHITE); setDrawMode(NORM); setCursor(0,0); pinMode(OLEDPWR, OUTPUT); digitalWrite(OLEDPWR,HIGH); // Setting up SPI pins pinMode(MOSI, OUTPUT); pinMode(SCK, OUTPUT); //pinMode(DC, OUTPUT); pinMode(RESET, OUTPUT); pinMode(SS, INPUT); digitalWrite(SS, HIGH); ssport = portOutputRegister(digitalPinToPort(SS)); sspinmask = digitalPinToBitMask(SS); ssreg = portModeRegister(digitalPinToPort(SS)); dcport = portOutputRegister(digitalPinToPort(DC)); dcpinmask = digitalPinToBitMask(DC); dcreg = portModeRegister(digitalPinToPort(DC)); digitalWrite(RESET, HIGH); // VDD (3.3V) goes high at start, lets just chill for 5 ms delay(5); // bring reset low digitalWrite(RESET, LOW); // Setup SPI frequency MVSPI.setClockDivider(SPI_CLOCK_DIV2); MVSPI.begin(); // wait 10ms delay(10); // bring out of reset pinMode(RESET,INPUT_PULLUP); //digitalWrite(RESET, HIGH); // Init sequence for 64x48 OLED module command(DISPLAYOFF); // 0xAE command(SETDISPLAYCLOCKDIV); // 0xD5 command(0x80); // the suggested ratio 0x80 command(SETMULTIPLEX); // 0xA8 command(0x2F); command(SETDISPLAYOFFSET); // 0xD3 command(0x0); // no offset command(SETSTARTLINE | 0x0); // line #0 command(CHARGEPUMP); // enable charge pump command(0x14); command(NORMALDISPLAY); // 0xA6 command(DISPLAYALLONRESUME); // 0xA4 command(SEGREMAP | 0x1); command(COMSCANDEC); command(SETCOMPINS); // 0xDA command(0x12); command(SETCONTRAST); // 0x81 command(0x8F); command(SETPRECHARGE); // 0xd9 command(0xF1); command(SETVCOMDESELECT); // 0xDB command(0x40); command(DISPLAYON); //--turn on oled panel clear(ALL); // Erase hardware memory inside the OLED controller to avoid random data in memory. Serial.begin(115200); } /** \brief SPI command. Setup DC and SS pins, then send command via SPI to SSD1306 controller. */ void MicroView::command(uint8_t c) { // Hardware SPI *dcreg |= dcpinmask; // Set DC pin to OUTPUT *dcport &= ~dcpinmask; // DC pin LOW *ssreg |= sspinmask; // Set SS pin to OUTPUT *ssport &= ~sspinmask; // SS LOW MVSPI.transfer(c); *ssport |= sspinmask; // SS HIGH *ssreg &= ~sspinmask; // Set SS pin to INPUT *dcreg &= ~dcpinmask; // Set DC to INPUT to avoid high voltage over driving the OLED logic } /** \brief SPI data. Setup DC and SS pins, then send data via SPI to SSD1306 controller. */ void MicroView::data(uint8_t c) { // Hardware SPI *dcport |= dcpinmask; // DC HIGH *ssreg |= sspinmask; // Set SS pin to OUTPUT *ssport &= ~sspinmask; // SS LOW MVSPI.transfer(c); *ssport |= sspinmask; // SS HIGH *ssreg &= ~sspinmask; // Set SS pin to INPUT *dcreg &= ~dcpinmask; // Set DC to INPUT to avoid high voltage over driving the OLED logic } /** \brief Set SSD1306 page address. Send page address command and address to the SSD1306 OLED controller. */ void MicroView::setPageAddress(uint8_t add) { add=0xb0|add; command(add); return; } /** \brief Set SSD1306 column address. Send column address command and address to the SSD1306 OLED controller. */ void MicroView::setColumnAddress(uint8_t add) { command((0x10|(add>>4))+0x02); command((0x0f&add)); return; } /** \brief Clear screen buffer or SSD1306's memory. To clear GDRAM inside the LCD controller, pass in the variable mode = ALL and to clear screen page buffer pass in the variable mode = PAGE. */ void MicroView::clear(uint8_t mode) { // uint8_t page=6, col=0x40; if (mode==ALL) { for (int i=0;i<8; i++) { setPageAddress(i); setColumnAddress(0); for (int j=0; j<0x80; j++) { data(0); } } } else { memset(screenmemory,0,384); // (64 x 48) / 8 = 384 //display(); } } /** \brief Clear or replace screen buffer or SSD1306's memory with a character. To clear GDRAM inside the LCD controller, pass in the variable mode = ALL with c character and to clear screen page buffer, pass in the variable mode = PAGE with c character. */ void MicroView::clear(uint8_t mode, uint8_t c) { //uint8_t page=6, col=0x40; if (mode==ALL) { for (int i=0;i<8; i++) { setPageAddress(i); setColumnAddress(0); for (int j=0; j<0x80; j++) { data(c); } } } else { memset(screenmemory,c,384); // (64 x 48) / 8 = 384 display(); } } /** \brief Invert display. The WHITE color of the display will turn to BLACK and the BLACK will turn to WHITE. */ void MicroView::invert(boolean inv) { if (inv) command(INVERTDISPLAY); else command(NORMALDISPLAY); } /** \brief Set contrast. OLED contract value from 0 to 255. Note: Contrast level is not very obvious. */ void MicroView::contrast(uint8_t contrast) { command(SETCONTRAST); // 0x81 command(contrast); } /** \brief Transfer display memory. Bulk move the screen buffer to the SSD1306 controller's memory so that images/graphics drawn on the screen buffer will be displayed on the OLED. */ void MicroView::display(void) { uint8_t i, j; for (i=0; i<6; i++) { setPageAddress(i); setColumnAddress(0); for (j=0;j<0x40;j++) { data(screenmemory[i*0x40+j]); } } } //#if ARDUINO >= 100 /** \brief Override Arduino's Print. Arduino's print overridden so that we can use uView.print(). */ size_t MicroView::write(uint8_t c) { //#else // void MicroView::write(uint8_t c) { //#endif if (c == '\n') { cursorY += fontHeight; cursorX = 0; } else if (c == '\r') { // skip } else { drawChar(cursorX, cursorY, c, foreColor, drawMode); cursorX += fontWidth+1; if ((cursorX > (LCDWIDTH - fontWidth))) { cursorY += fontHeight; cursorX = 0; } } //#if ARDUINO >= 100 return 1; //#endif } /** \brief Set cursor position. MicroView's cursor position to x,y. */ void MicroView::setCursor(uint8_t x, uint8_t y) { cursorX=x; cursorY=y; } /** \brief Draw pixel. Draw pixel using the current fore color and current draw mode in the screen buffer's x,y position. */ void MicroView::pixel(uint8_t x, uint8_t y) { pixel(x,y,foreColor,drawMode); } /** \brief Draw pixel with color and mode. Draw color pixel in the screen buffer's x,y position with NORM or XOR draw mode. */ void MicroView::pixel(uint8_t x, uint8_t y, uint8_t color, uint8_t mode) { if ((x<0) || (x>=LCDWIDTH) || (y<0) || (y>=LCDHEIGHT)) return; if (mode==XOR) { if (color==WHITE) screenmemory[x+ (y/8)*LCDWIDTH] ^= _BV((y%8)); } else { if (color==WHITE) screenmemory[x+ (y/8)*LCDWIDTH] |= _BV((y%8)); else screenmemory[x+ (y/8)*LCDWIDTH] &= ~_BV((y%8)); } //display(); } /** \brief Draw line. Draw line using current fore color and current draw mode from x0,y0 to x1,y1 of the screen buffer. */ void MicroView::line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) { line(x0,y0,x1,y1,foreColor,drawMode); } /** \brief Draw line with color and mode. Draw line using color and mode from x0,y0 to x1,y1 of the screen buffer. */ void MicroView::line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color, uint8_t mode) { uint8_t steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swap(x0, y0); swap(x1, y1); } if (x0 > x1) { swap(x0, x1); swap(y0, y1); } uint8_t dx, dy; dx = x1 - x0; dy = abs(y1 - y0); int8_t err = dx / 2; int8_t ystep; if (y0 < y1) { ystep = 1; } else { ystep = -1;} for (; x0= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; pixel(x0 + x, y0 + y, color, mode); pixel(x0 - x, y0 + y, color, mode); pixel(x0 + x, y0 - y, color, mode); pixel(x0 - x, y0 - y, color, mode); pixel(x0 + y, y0 + x, color, mode); pixel(x0 - y, y0 + x, color, mode); pixel(x0 + y, y0 - x, color, mode); pixel(x0 - y, y0 - x, color, mode); } } /** \brief Draw filled circle. Draw filled circle with radius using current fore color and current draw mode at x,y of the screen buffer. */ void MicroView::circleFill(uint8_t x0, uint8_t y0, uint8_t radius) { circleFill(x0,y0,radius,foreColor,drawMode); } /** \brief Draw filled circle with color and mode. Draw filled circle with radius using color and mode at x,y of the screen buffer. */ void MicroView::circleFill(uint8_t x0, uint8_t y0, uint8_t radius, uint8_t color, uint8_t mode) { // TODO - - find a way to check for no overlapping of pixels so that XOR draw mode will work perfectly int8_t f = 1 - radius; int8_t ddF_x = 1; int8_t ddF_y = -2 * radius; int8_t x = 0; int8_t y = radius; // Temporary disable fill circle for XOR mode. if (mode==XOR) return; for (uint8_t i=y0-radius; i<=y0+radius; i++) { pixel(x0, i, color, mode); } while (x= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; for (uint8_t i=y0-y; i<=y0+y; i++) { pixel(x0+x, i, color, mode); pixel(x0-x, i, color, mode); } for (uint8_t i=y0-x; i<=y0+x; i++) { pixel(x0+y, i, color, mode); pixel(x0-y, i, color, mode); } } } /** \brief Get LCD height. The height of the LCD return as byte. */ uint8_t MicroView::getLCDHeight(void) { return LCDHEIGHT; } /** \brief Get LCD width. The width of the LCD return as byte. */ uint8_t MicroView::getLCDWidth(void) { return LCDWIDTH; } /** \brief Get font width. The cucrrent font's width return as byte. */ uint8_t MicroView::getFontWidth(void) { return fontWidth; } /** \brief Get font height. The current font's height return as byte. */ uint8_t MicroView::getFontHeight(void) { return fontHeight; } /** \brief Get font starting character. Return the starting ASCII character of the currnet font, not all fonts start with ASCII character 0. Custom fonts can start from any ASCII character. */ uint8_t MicroView::getFontStartChar(void) { return fontStartChar; } /** \brief Get font total characters. Return the total characters of the current font. */ uint8_t MicroView::getFontTotalChar(void) { return fontTotalChar; } /** \brief Get total fonts. Return the total number of fonts loaded into the MicroView's flash memory. */ uint8_t MicroView::getTotalFonts(void) { return TOTALFONTS; } /** \brief Get font type. Return the font type number of the current font. */ uint8_t MicroView::getFontType(void) { return fontType; } /** \brief Set font type. Set the current font type number, ie changing to different fonts base on the type provided. */ uint8_t MicroView::setFontType(uint8_t type) { if ((type>=TOTALFONTS) || (type<0)) return false; fontType=type; fontWidth=pgm_read_byte(fontsPointer[fontType]+0); fontHeight=pgm_read_byte(fontsPointer[fontType]+1); fontStartChar=pgm_read_byte(fontsPointer[fontType]+2); fontTotalChar=pgm_read_byte(fontsPointer[fontType]+3); fontMapWidth=(pgm_read_byte(fontsPointer[fontType]+4)*100)+pgm_read_byte(fontsPointer[fontType]+5); // two bytes values into integer 16 return true; } /** \brief Set color. Set the current draw's color. Only WHITE and BLACK available. */ void MicroView::setColor(uint8_t color) { foreColor=color; } /** \brief Set draw mode. Set current draw mode with NORM or XOR. */ void MicroView::setDrawMode(uint8_t mode) { drawMode=mode; } /** \brief Draw character. Draw character c using current color and current draw mode at x,y. */ void MicroView::drawChar(uint8_t x, uint8_t y, uint8_t c) { drawChar(x,y,c,foreColor,drawMode); } /** \brief Draw character with color and mode. Draw character c using color and draw mode at x,y. */ void MicroView::drawChar(uint8_t x, uint8_t y, uint8_t c, uint8_t color, uint8_t mode) { // TODO - New routine to take font of any height, at the moment limited to font height in multiple of 8 pixels uint8_t rowsToDraw,row, tempC; uint8_t i,j,temp; uint16_t charPerBitmapRow,charColPositionOnBitmap,charRowPositionOnBitmap,charBitmapStartPosition; if ((c(fontStartChar+fontTotalChar-1))) // no bitmap for the required c return; tempC=c-fontStartChar; // each row (in datasheet is call page) is 8 bits high, 16 bit high character will have 2 rows to be drawn rowsToDraw=fontHeight/8; // 8 is LCD's page size, see SSD1306 datasheet if (rowsToDraw<=1) rowsToDraw=1; // the following draw function can draw anywhere on the screen, but SLOW pixel by pixel draw if (rowsToDraw==1) { for (i=0;i>=1; } } return; } // font height over 8 bit // take character "0" ASCII 48 as example charPerBitmapRow=fontMapWidth/fontWidth; // 256/8 =32 char per row charColPositionOnBitmap=tempC % charPerBitmapRow; // =16 charRowPositionOnBitmap=int(tempC/charPerBitmapRow); // =1 charBitmapStartPosition=(charRowPositionOnBitmap * fontMapWidth * (fontHeight/8)) + (charColPositionOnBitmap * fontWidth) ; // each row on LCD is 8 bit height (see datasheet for explanation) for(row=0;row>=1; } } } /* fast direct memory draw but has a limitation to draw in ROWS // only 1 row to draw for font with 8 bit height if (rowsToDraw==1) { for (i=0; i0) { // process Serial data result=strtok(serInStr,","); if (result !=NULL) { temp=atoi(result); serCmd[index]=(uint8_t)temp & 0xff; // we only need 8 bit number index++; for (uint8_t i=0;i0) uView.setCursor(offsetX,offsetY+10); else uView.setCursor(offsetX+34,offsetY+1); uView.print(strBuffer); } // ------------------------------------------------------------------------------------- // Slider Widget - end // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // Gauge Widget - start // ------------------------------------------------------------------------------------- /** \brief MicroViewGauge class initilisation. Initialise the MicroViewGauge widget with default style. */ MicroViewGauge::MicroViewGauge(uint8_t newx, uint8_t newy, int16_t min, int16_t max):MicroViewWidget(newx, newy, min, max) { style=0; radius=15; needFirstDraw=true; prevValue=getMinValue(); drawFace(); draw(); } /** \brief MicroViewGauge class initialisation with style. Initialise the MicroViewGauge widget with style WIDGETSTYLE0 or WIDGETSTYLE1. */ MicroViewGauge::MicroViewGauge(uint8_t newx, uint8_t newy, int16_t min, int16_t max, uint8_t sty):MicroViewWidget(newx, newy, min, max) { if (sty==WIDGETSTYLE0) { style=0; radius=15; } else { style=1; radius=23; } needFirstDraw=true; prevValue=getMinValue(); drawFace(); draw(); } /** \brief Draw widget face. Draw image/diagram representing the widget's face. */ void MicroViewGauge::drawFace() { uint8_t offsetX, offsetY; float degreeSec, fromSecX, fromSecY, toSecX, toSecY; offsetX=getX(); offsetY=getY(); uView.circle(offsetX,offsetY,radius); for (int i=150;i<=390;i+=30) { // Major tick from 150 degree to 390 degree degreeSec=i*(PI/180); fromSecX = cos(degreeSec) * (radius / 1.5); fromSecY = sin(degreeSec) * (radius / 1.5); toSecX = cos(degreeSec) * (radius / 1); toSecY = sin(degreeSec) * (radius / 1); uView.line(1+offsetX+fromSecX,1+offsetY+fromSecY,1+offsetX+toSecX,1+offsetY+toSecY); } if(radius>15) { for (int i=150;i<=390;i+=15) { // Minor tick from 150 degree to 390 degree degreeSec=i*(PI/180); fromSecX = cos(degreeSec) * (radius / 1.3); fromSecY = sin(degreeSec) * (radius / 1.3); toSecX = cos(degreeSec) * (radius / 1); toSecY = sin(degreeSec) * (radius / 1); uView.line(1+offsetX+fromSecX,1+offsetY+fromSecY,1+offsetX+toSecX,1+offsetY+toSecY); } } } /** \brief Draw widget value. Convert the current value of the widget and draw the ticker representing the value. */ void MicroViewGauge::draw() { uint8_t offsetX, offsetY; float degreeSec, toSecX, toSecY; char strBuffer[5]; offsetX=getX(); offsetY=getY(); if (needFirstDraw) { degreeSec = (((float)(prevValue-getMinValue())/(float)(getMaxValue()-getMinValue()))*240); // total 240 degree in the widget degreeSec = (degreeSec+150) * (PI/180); // 150 degree starting point toSecX = cos(degreeSec) * (radius / 1.2); toSecY = sin(degreeSec) * (radius / 1.2); uView.line(offsetX,offsetY,1+offsetX+toSecX,1+offsetY+toSecY, WHITE,XOR); sprintf(strBuffer,"%4d", prevValue); // we need to force 4 digit so that blank space will cover larger value needFirstDraw=false; } else { // Draw previous pointer in XOR mode to erase it degreeSec = (((float)(prevValue-getMinValue())/(float)(getMaxValue()-getMinValue()))*240); // total 240 degree in the widget degreeSec = (degreeSec+150) * (PI/180); toSecX = cos(degreeSec) * (radius / 1.2); toSecY = sin(degreeSec) * (radius / 1.2); uView.line(offsetX,offsetY,1+offsetX+toSecX,1+offsetY+toSecY, WHITE,XOR); degreeSec = (((float)(getValue()-getMinValue())/(float)(getMaxValue()-getMinValue()))*240); // total 240 degree in the widget degreeSec = (degreeSec+150) * (PI/180); // 150 degree starting point toSecX = cos(degreeSec) * (radius / 1.2); toSecY = sin(degreeSec) * (radius / 1.2); uView.line(offsetX,offsetY,1+offsetX+toSecX,1+offsetY+toSecY, WHITE,XOR); sprintf(strBuffer,"%4d", getValue()); // we need to force 4 digit so that blank space will cover larger value prevValue=getValue(); } // Draw value if(style>0) uView.setCursor(offsetX-10,offsetY+10); else uView.setCursor(offsetX-11,offsetY+11); uView.print(strBuffer); } // ------------------------------------------------------------------------------------- // Slider Widget - end // ------------------------------------------------------------------------------------- /** \brief SPI Initialisation. Setup SCK, MOSI pins for SPI transmission. */ void MVSPIClass::begin() { // Set SS to high so a connected chip will be "deselected" by default digitalWrite(SS, HIGH); // When the SS pin is set as OUTPUT, it can be used as // a general purpose output port (it doesn't influence // SPI operations). pinMode(SS, OUTPUT); // Warning: if the SS pin ever becomes a LOW INPUT then SPI // automatically switches to Slave, so the data direction of // the SS pin MUST be kept as OUTPUT. SPCR |= _BV(MSTR); SPCR |= _BV(SPE); // Set direction register for SCK and MOSI pin. // MISO pin automatically overrides to INPUT. // By doing this AFTER enabling SPI, we avoid accidentally // clocking in a single bit since the lines go directly // from "input" to SPI control. // http://code.google.com/p/arduino/issues/detail?id=888 pinMode(SCK, OUTPUT); pinMode(MOSI, OUTPUT); } /** \brief End SPI. */ void MVSPIClass::end() { SPCR &= ~_BV(SPE); } /** \brief Set SPI bit order. Set SPI port bit order with LSBFIRST or MSBFIRST. */ void MVSPIClass::setBitOrder(uint8_t bitOrder) { if(bitOrder == LSBFIRST) { SPCR |= _BV(DORD); } else { SPCR &= ~(_BV(DORD)); } } /** \brief Set SPI data mode. Set the SPI daa mode: clock polarity and phase. mode - SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3. */ void MVSPIClass::setDataMode(uint8_t mode) { SPCR = (SPCR & ~SPI_MODE_MASK) | mode; } /** \brief Set clock divider. Set the clocl divider of the SPI, default is 4Mhz. rate: SPI_CLOCK_DIV2 SPI_CLOCK_DIV4 SPI_CLOCK_DIV8 SPI_CLOCK_DIV16 SPI_CLOCK_DIV32 SPI_CLOCK_DIV64 SPI_CLOCK_DIV128 */ void MVSPIClass::setClockDivider(uint8_t rate) { SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); } MVSPIClass MVSPI; MicroView uView;