Chen Huan
/
Final_DongGanPingTai
Tsinghua Icenter ChenHuan
TFT/TFT_ILI9340.cpp
- Committer:
- heroistired
- Date:
- 2017-03-16
- Revision:
- 0:9b8df4f9b792
File content as of revision 0:9b8df4f9b792:
/*************************************************************** 功能 : mbed的ILI9340液晶显示芯片的驱动程序与图形库,使用硬件SPI 作者 : 陈欢 清华大学电机工程与应用电子技术系 邮箱 : h-che14@mails.tsinghua.edu.cn OR heroistired@gmail.com 声明 : 本程序移植自 https://developer.mbed.org/users/dextorslabs/code/ILI9340_Driver/ 在原有基础上做了改进与丰富,本程序仅供学习与交流使用,如需他用,须联系作者 All rights reserved 2017.1.30 ***************************************************************/ #include "mbed.h" #include "TFT_ILI9340.h" #include "SimpleFont.cpp" //////////////////////////////////////////////////////////////////////////////////////////////// // Constructor, assigns the pins to the SPI object, set orientation, and sets screen dims. //////////////////////////////////////////////////////////////////////////////////////////////// ILI9340_Display::ILI9340_Display(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName dc) : spi(mosi, miso, sclk), cs(cs), rst(rst), dc(dc) { _height = _TFTHEIGHT; _width = _TFTWIDTH; orientation = 0; } //////////////////////////////////////////////////////////////////////////////////////////////// // Command writing code //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::WriteCommand(uint8_t command) { dc = 0; cs = 0; spi.write(command); cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Data writing code //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::WriteData(uint8_t data) { cs = 0; dc = 1; spi.write(data); cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Initilise the display //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DispInit(void) { //CtrlOutput(); rst = 0; // Setup the spi for 8 bit data, high steady state clock, // second edge capture, with a 1MHz clock rate //spi.format(8,3); spi.frequency(24000000); // actually seems to work up to about 20Mhz... way better than the 8mhz as std. // Toggle rst to reset rst = 1; wait(0.005); rst = 0; wait(0.020); rst = 1; wait(0.150); WriteCommand(0xEF); WriteData(0x03); WriteData(0x80); WriteData(0x02); WriteCommand(0xCF); WriteData(0x00); WriteData(0xC1); WriteData(0x30); WriteCommand(0xED); WriteData(0x64); WriteData(0x03); WriteData(0x12); WriteData(0x81); WriteCommand(0xE8); WriteData(0x85); WriteData(0x00); WriteData(0x78); WriteCommand(0xCB); WriteData(0x39); WriteData(0x2C); WriteData(0x00); WriteData(0x34); WriteData(0x02); WriteCommand(0xF7); WriteData(0x20); WriteCommand(0xEA); WriteData(0x00); WriteData(0x00); WriteCommand(ILI9340_PWCTR1); //Power control WriteData(0x23); //VRH[5:0] WriteCommand(ILI9340_PWCTR2); //Power control WriteData(0x10); //SAP[2:0];BT[3:0] WriteCommand(ILI9340_VMCTR1); //VCM control WriteData(0x3e); // WriteData(0x28); WriteCommand(ILI9340_VMCTR2); //VCM control2 WriteData(0x86); //-- WriteCommand(ILI9340_MADCTL); // Memory Access Control WriteData(ILI9340_MADCTL_MX | ILI9340_MADCTL_BGR); WriteCommand(ILI9340_PIXFMT); WriteData(0x55); WriteCommand(ILI9340_FRMCTR1); WriteData(0x00); WriteData(0x18); WriteCommand(ILI9340_DFUNCTR); // Display Function Control WriteData(0x08); WriteData(0x82); WriteData(0x27); WriteCommand(0xF2); // 3Gamma Function Disable WriteData(0x00); WriteCommand(ILI9340_GAMMASET); //Gamma curve selected WriteData(0x01); WriteCommand(ILI9340_GMCTRP1); //Set Gamma WriteData(0x0F); WriteData(0x31); WriteData(0x2B); WriteData(0x0C); WriteData(0x0E); WriteData(0x08); WriteData(0x4E); WriteData(0xF1); WriteData(0x37); WriteData(0x07); WriteData(0x10); WriteData(0x03); WriteData(0x0E); WriteData(0x09); WriteData(0x00); WriteCommand(ILI9340_GMCTRN1); //Set Gamma WriteData(0x00); WriteData(0x0E); WriteData(0x14); WriteData(0x03); WriteData(0x11); WriteData(0x07); WriteData(0x31); WriteData(0xC1); WriteData(0x48); WriteData(0x08); WriteData(0x0F); WriteData(0x0C); WriteData(0x31); WriteData(0x36); WriteData(0x0F); WriteCommand(ILI9340_SLPOUT); //Exit Sleep wait(0.120); WriteCommand(ILI9340_DISPON); //Display on } //////////////////////////////////////////////////////////////////////////////////////////////// // Sets the rotation of the display //////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// //功能 : 设置屏幕的方向 //参数 : m 方向 以接线的方向为向下 0 向上 1 向右 2 向下 3 向左 //返回值 : 无 ////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::SetRotation(uint8_t m) { WriteCommand(ILI9340_MADCTL); orientation = m % 4; // can't be higher than 3 switch (orientation) { case 0: WriteData(ILI9340_MADCTL_MX | ILI9340_MADCTL_BGR); _width = _TFTWIDTH; _height = _TFTHEIGHT; break; case 1: WriteData(ILI9340_MADCTL_MV | ILI9340_MADCTL_BGR); _width = _TFTHEIGHT; _height = _TFTWIDTH; break; case 2: WriteData(ILI9340_MADCTL_MY | ILI9340_MADCTL_BGR); _width = _TFTWIDTH; _height = _TFTHEIGHT; break; case 3: WriteData(ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX | ILI9340_MADCTL_BGR); _width = _TFTHEIGHT; _height = _TFTWIDTH; break; } } //////////////////////////////////////////////////////////////////////////////////////////////// // Invert the colours of the display in hardware //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::InvertDisplay(bool i) { WriteCommand(i ? ILI9340_INVON : ILI9340_INVOFF); } //////////////////////////////////////////////////////////////////////////////////////////////// // Set address window for writing data to. //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { WriteCommand(ILI9340_CASET); // Column addr set WriteData(x0 >> 8); WriteData(x0 & 0xFF); // XSTART WriteData(x1 >> 8); WriteData(x1 & 0xFF); // XEND WriteCommand(ILI9340_PASET); // Row addr set WriteData(y0>>8); WriteData(y0); // YSTART WriteData(y1>>8); WriteData(y1); // YEND WriteCommand(ILI9340_RAMWR); // write to RAM } //////////////////////////////////////////////////////////////////////////////////////////////// // To draw the humble pixel //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawPixel(uint16_t x, uint16_t y, uint16_t colour) { if((x < 1) ||(x >= _width) || (y < 1) || (y >= _height)) return; SetAddrWindow(x,y,x+1,y+1); dc = 1; cs = 0; spi.write(colour >> 8); spi.write(colour); cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Fill the screen with a colour //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::FillScreen(uint16_t colour) { SetAddrWindow(0,0,_width,_height); dc = 1; cs = 0; unsigned int total = _width * _height; unsigned int position = 0; while (position < total) { spi.write(colour >> 8); spi.write(colour); position++; } cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Draws a vertical line fast //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t colour) { // Rudimentary clipping if((x >= _width) || (y >= _height)) return; if((y+h-1) >= _height) h = _height-y; SetAddrWindow(x, y, x, y+h-1); uint8_t hi = colour >> 8, lo = colour; dc = 1; cs = 0; while (h--) { spi.write(hi); spi.write(lo); } cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Draws a horizontal line fast //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t colour) { // Rudimentary clipping if((x >= _width) || (y >= _height)) return; if((x+w-1) >= _height) w = _width-x; SetAddrWindow(x, y, x+w-1, y); uint8_t hi = colour >> 8, lo = colour; dc = 1; cs = 0; while (w--) { spi.write(hi); spi.write(lo); } cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Draws a filled rectangle //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t colour) { // rudimentary clipping (drawChar w/big text requires this) if((x >= _width) || (y >= _height)) return; if((x + w - 1) >= _width) w = _width - x; if((y + h - 1) >= _height) h = _height - y; SetAddrWindow(x, y, x+w-1, y+h-1); uint8_t hi = colour >> 8, lo = colour; dc = 1; cs = 0; for(y=h; y>0; y--) { for(x=w; x>0; x--) { spi.write(hi); spi.write(lo); } } cs = 1; } //////////////////////////////////////////////////////////////////////////////////////////////// // Draw an unfilled rectangle //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){ DrawFastHLine(x, y, w, color); DrawFastHLine(x, y+h-1, w, color); DrawFastVLine(x, y, h, color); DrawFastVLine(x+w-1, y, h, color); } //////////////////////////////////////////////////////////////////////////////////////////////// // draw an unfilled circle //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t colour){ int16_t f = 1 - r; int16_t ddF_x = 1; int16_t ddF_y = -2 * r; int16_t x = 0; int16_t y = r; DrawPixel(x0 , y0+r, colour); DrawPixel(x0 , y0-r, colour); DrawPixel(x0+r, y0 , colour); DrawPixel(x0-r, y0 , colour); while (x<y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; DrawPixel(x0 + x, y0 + y, colour); DrawPixel(x0 - x, y0 + y, colour); DrawPixel(x0 + x, y0 - y, colour); DrawPixel(x0 - x, y0 - y, colour); DrawPixel(x0 + y, y0 + x, colour); DrawPixel(x0 - y, y0 + x, colour); DrawPixel(x0 + y, y0 - x, colour); DrawPixel(x0 - y, y0 - x, colour); } } //////////////////////////////////////////////////////////////////////////////////////////////// // Draw a filled circle //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::FillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t colour) { DrawFastVLine(x0, y0-r, 2*r+1, colour); FillCircleHelper(x0, y0, r, 3, 0, colour); } //////////////////////////////////////////////////////////////////////////////////////////////// // used to draw circles and roundrects! //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::FillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t colour) { int16_t f = 1 - r; int16_t ddF_x = 1; int16_t ddF_y = -2 * r; int16_t x = 0; int16_t y = r; while (x<y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; if (cornername & 0x1) { DrawFastVLine(x0+x, y0-y, 2*y+1+delta, colour); DrawFastVLine(x0+y, y0-x, 2*x+1+delta, colour); } if (cornername & 0x2) { DrawFastVLine(x0-x, y0-y, 2*y+1+delta, colour); DrawFastVLine(x0-y, y0-x, 2*x+1+delta, colour); } } } //////////////////////////////////////////////////////////////////////////////////////////////// // used for drawing rounded corner radii //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawCircleHelper( int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t colour) { int16_t f = 1 - r; int16_t ddF_x = 1; int16_t ddF_y = -2 * r; int16_t x = 0; int16_t y = r; while (x<y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; if (cornername & 0x4) { DrawPixel(x0 + x, y0 + y, colour); DrawPixel(x0 + y, y0 + x, colour); } if (cornername & 0x2) { DrawPixel(x0 + x, y0 - y, colour); DrawPixel(x0 + y, y0 - x, colour); } if (cornername & 0x8) { DrawPixel(x0 - y, y0 + x, colour); DrawPixel(x0 - x, y0 + y, colour); } if (cornername & 0x1) { DrawPixel(x0 - y, y0 - x, colour); DrawPixel(x0 - x, y0 - y, colour); } } } //////////////////////////////////////////////////////////////////////////////////////////////// // draw a rounded rectangle! //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t colour) { // smarter version DrawFastHLine(x+r , y , w-2*r, colour); // Top DrawFastHLine(x+r , y+h-1, w-2*r, colour); // Bottom DrawFastVLine( x , y+r , h-2*r, colour); // Left DrawFastVLine( x+w-1, y+r , h-2*r, colour); // Right // draw four corners DrawCircleHelper(x+r , y+r , r, 1, colour); DrawCircleHelper(x+w-r-1, y+r , r, 2, colour); DrawCircleHelper(x+w-r-1, y+h-r-1, r, 4, colour); DrawCircleHelper(x+r , y+h-r-1, r, 8, colour); } //////////////////////////////////////////////////////////////////////////////////////////////// // fill a rounded rectangle! //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::FillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t colour) { // smarter version FillRect(x+r, y, w-2*r, h, colour); // draw four corners FillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, colour); FillCircleHelper(x+r , y+r, r, 2, h-2*r-1, colour); } //////////////////////////////////////////////////////////////////////////////////////////////// // Pass 8-bit (each) R,G,B, get back 16-bit packed color //////////////////////////////////////////////////////////////////////////////////////////////// uint16_t ILI9340_Display::Colour565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } //////////////////////////////////////////////////////////////////////////////////////////////// // Writes an ascii character to the display //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawAscii(unsigned char ascii, uint16_t x, uint16_t y, uint16_t size, uint16_t colour) { SetAddrWindow(x, y, x+size, y+size); if( (ascii < 0x20) || (ascii > 0x7e) ) //check for valid ASCII char { ascii = '?'; //char not supported } for(unsigned char i=0; i<8; i++) { unsigned char temp = simpleFont[ascii - 0x20][i]; for(unsigned char f=0; f<8; f++) { if( (temp>>f) & 0x01 ) { switch(orientation) { case '0': FillRect(x+f*size, y-i*size, size, size, colour); break; case '1': FillRect(x-i*size, x-f*size, size, size, colour); break; case '2': FillRect(x-f*size, y+i*size, size, size, colour); break; case '3': default: FillRect(x+i*size, y+f*size, size, size, colour); } } } } } ////////////////////////////////////////////////////////////////////////////////// //功能 : 将一个字符串显示屏幕上 //参数 : string 要显示的字符串 // x,y 字符串中第一个字符的左上角像素的坐标值 // size 字号 可选 1 2 3 // colour 像素颜色 //返回值 : 无 ////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawString(char *string, uint16_t x, uint16_t y, uint8_t size, uint16_t colour) { while(*string) { DrawAscii(*string, x, y, size, colour); *string++; switch(orientation) { case '0': if(y > 0) y-=8*size; //Change position to next char break; case '1': if(x > 0) x-=8*size; break; case '2': if(y < _height) y+=8*size; break; case '3': default: if(x < _width) x+=8*size; } } } ////////////////////////////////////////////////////////////////////////////////// //功能 : 将一个整数数据显示屏幕上 //参数 : buffer 显示数据的字符串形式(输出量) // value 要显示的整数 // spaceonbuffer 对整数的位数限制 // countbase 计数进制 // x,y 最高位数字的左上角像素的坐标值 如spaceonbuffer为5,则是万位数字的相应坐标,不论实际上该位有无数字 // size 字号 可选 1 2 3 // colour 像素颜色 //返回值 : 无 ////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::IntToChars (char* buffer, int value, uint8_t spaceonbuffer, uint8_t countbase, uint16_t x, uint16_t y, uint8_t size, uint16_t colour) { int workvalue = value; int i; int valuetowrite; int end_i = 0; if (value < 0) { workvalue = -value; end_i = 1; buffer[0] = '-'; } for (i = spaceonbuffer - 1; i >= end_i; i--) { valuetowrite = (workvalue % countbase); if (workvalue == 0) { if (i == (spaceonbuffer - 1)) { buffer[i] = 48; // ASCII 0 } else { buffer[i] = 32; // ASCII SPACE } } else { if (valuetowrite > 9) { buffer[i] = valuetowrite + 55; // ASCII A-Z } else { buffer[i] = valuetowrite + 48; // ASCII of that character } }; workvalue = (workvalue - valuetowrite) / countbase; } DrawString(buffer, x, y, size, colour); } //////////////////////////////////////////////////////////////////////////////////////////////// // Functional code to swap data contents of 16bit registers //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::Swap(int16_t *a, int16_t *b) { int16_t x = *a; *a = *b; *b = x; } //////////////////////////////////////////////////////////////////////////////////////////////// // Draws a line with any length and orientation //////////////////////////////////////////////////////////////////////////////////////////////// void ILI9340_Display::DrawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t colour){ int16_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); } int16_t dx, dy; dx = x1 - x0; dy = abs(y1 - y0); int16_t err = dx / 2; int16_t ystep; if (y0 < y1) { ystep = 1; } else { ystep = -1; } for (; x0<=x1; x0++) { if (steep) { DrawPixel(y0, x0, colour); } else { DrawPixel(x0, y0, colour); } err -= dy; if (err < 0) { y0 += ystep; err += dx; } } }