Arduino UNO控制3.5inch ILI9486显示屏教程

Arduino UNO控制3.5inch ILI9486显示屏教程

这几天在做一个Arduino + ESP8266 + 甲醛气体传感器 + Andriod APP + 树莓派的物联网实验,大致思想是Arduino + ESP8266 + 甲醛气体传感器作为传感器节点检测数据;Andriod APP实现与该传感器节点的网络连接与同一局域网下的网络通信,包括设置WiFi模式,设置检测频率,读取传感器数据等;树莓派作为一个小型服务器,将传感器节点实时采集的数据存入数据库,并可以实现Andriod APP远程手机访问和检索。期间,由于涉及到传感器节点数据显示的问题,为了实现传感器节点的单独使用,采购了一个ILI9486的3.5inch的显示屏。本文主要总结Arduino UNO对该屏幕的使用方法。

1. 下载支持库

点击下载链接,下载“3.5寸Arduino UNO模块配套资料包”。

2. 添加库文件

这里使用的是Arduino 1.8.9,切换路径至:下载文件目录\1-Demo\Demo_Arduino\Install libraries,将此文件夹下的所有文件夹拷贝至Arduino IDE根目录下的libraries文件夹中。

3. 库文件的修改

LCDWIKI_KBV文件夹下的lcd_mode.h可修改8或16位模式,保持默认即可。LCDWIKI_KBV可以在Arduino中直接创建LCD对象,LCDWIKI_GUI为LCDWIKI_KBV的基类,主要方法如下:

	virtual uint16_t 	Color_To_565(uint8_t r, uint8_t g, uint8_t b)=0;
	virtual void 	 	Draw_Pixe(int16_t x, int16_t y, uint16_t color)=0;
	virtual void 		Fill_Rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)=0;
	virtual void 		Set_Addr_Window(int16_t x1, int16_t y1, int16_t x2, int16_t y2)=0;
	virtual void 		Push_Any_Color(uint16_t * block, int16_t n, bool first, uint8_t flags)=0;
	virtual int16_t 	Read_GRAM(int16_t x, int16_t y, uint16_t *block, int16_t w, int16_t h)=0;
	virtual int16_t 	Get_Height(void) const=0;
	virtual int16_t 	Get_Width(void) const=0;
	
	//These exist only with LCDWIKI_GUI(no subclass overrides)
	void 	 Set_Draw_color(uint16_t color);
	void 	 Set_Draw_color(uint8_t r, uint8_t g, uint8_t b);
	uint16_t Get_Draw_color(void) const;
	void 	 Draw_Pixel(int16_t x, int16_t y);
	uint16_t Read_Pixel(int16_t x, int16_t y);
	void 	 Draw_Fast_VLine(int16_t x, int16_t y, int16_t h);
	void 	 Draw_Fast_HLine(int16_t x, int16_t y, int16_t w);
	void 	 Fill_Screen(uint16_t color);
	void 	 Fill_Screen(uint8_t r, uint8_t g, uint8_t b);
	void 	 Draw_Line(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
	void 	 Draw_Rectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
	void 	 Fill_Rectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
	void 	 Draw_Round_Rectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t radius);
	void 	 Fill_Round_Rectangle(int16_t x1, int16_t y1, int16_t x2,int16_t y2, int16_t radius);
	void 	 Draw_Circle(int16_t x, int16_t y, int16_t radius);
	void 	 Draw_Circle_Helper(int16_t x0, int16_t y0, int16_t radius, uint8_t cornername);
	void 	 Fill_Circle(int16_t x, int16_t y, int16_t radius);
	void 	 Fill_Circle_Helper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,int16_t delta);
	void 	 Draw_Triangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,int16_t x2, int16_t y2);
	void 	 Fill_Triangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,int16_t x2, int16_t y2);
	void 	 Draw_Bit_Map(int16_t x, int16_t y, int16_t sx, int16_t sy, const uint16_t *data, int16_t scale);
	void 	 Set_Text_Cousur(int16_t x, int16_t y);
	int16_t  Get_Text_X_Cousur(void) const;
	int16_t  Get_Text_Y_Cousur(void) const;
	void 	 Set_Text_colour(uint16_t color);
	void 	 Set_Text_colour(uint8_t r, uint8_t g, uint8_t b);
	uint16_t Get_Text_colour(void) const;
	void 	 Set_Text_Back_colour(uint16_t color); 
	void 	 Set_Text_Back_colour(uint8_t r, uint8_t g, uint8_t b); 
	uint16_t Get_Text_Back_colour(void) const;
	void 	 Set_Text_Size(uint8_t s);
	uint8_t  Get_Text_Size(void) const;
	void 	 Set_Text_Mode(boolean mode);
	boolean  Get_Text_Mode(void) const;
	size_t 	 Print(uint8_t *st, int16_t x, int16_t y);
	void 	 Print_String(const uint8_t *st, int16_t x, int16_t y);
	void 	 Print_String(uint8_t *st, int16_t x, int16_t y);
	void 	 Print_String(String st, int16_t x, int16_t y);
	void 	 Print_Number_Int(long num, int16_t x, int16_t y, int16_t length, uint8_t filler, int16_t system);
	void 	 Print_Number_Float(double num, uint8_t dec, int16_t x, int16_t y, uint8_t divider, int16_t length, uint8_t filler);
	void 	 Draw_Char(int16_t x, int16_t y, uint8_t c, uint16_t color,uint16_t bg, uint8_t size, boolean mode);
	size_t 	 write(uint8_t c);
	int16_t  Get_Display_Width(void) const;
	int16_t  Get_Display_Height(void) const; 

LCDWIKI_KBV的方法如下:

	void 	 Init_LCD(void);
	void 	 reset(void);
	void 	 start(uint16_t ID);
	void 	 Draw_Pixe(int16_t x, int16_t y, uint16_t color);
	void 	 Write_Cmd(uint16_t cmd);
	void 	 Write_Data(uint16_t data);
	void 	 Write_Cmd_Data(uint16_t cmd, uint16_t data);
	void 	 init_table8(const void *table, int16_t size);
	void 	 init_table16(const void *table, int16_t size);
	void 	 Push_Command(uint16_t cmd, uint8_t *block, int8_t N);
	uint16_t Color_To_565(uint8_t r, uint8_t g, uint8_t b);
	uint16_t Read_ID(void);
	void 	 Fill_Rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
	void 	 Set_Rotation(uint8_t r); 
	uint8_t  Get_Rotation(void) const;
	void 	 Invert_Display(boolean i);
	uint16_t Read_Reg(uint16_t reg, int8_t index);
	int16_t  Read_GRAM(int16_t x, int16_t y, uint16_t *block, int16_t w, int16_t h);
	void 	 Set_Addr_Window(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
	void 	 Push_Any_Color(uint16_t * block, int16_t n, bool first, uint8_t flags);
	void 	 Push_Any_Color(uint8_t * block, int16_t n, bool first, uint8_t flags);
	void 	 Vert_Scroll(int16_t top, int16_t scrollines, int16_t offset);
	int16_t  Get_Height(void) const;
	int16_t  Get_Width(void) const;
	void 	 Set_LR(void);

大家如果有需要可以根据函数声明自行调用,这里我主要用来显示字符串、数字和汉字,偶尔画个图,所以用到的并不多。

4. Arduino使用ILI9486库

首先需要实例化一个对象:

LCDWIKI_KBV my_lcd(ILI9486,A3,A2,A1,A0,A4); //model,cs,cd,wr,rd,reset#define BLACK   0x0000

定义一些颜色的宏:

#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

以及颜色名数组和相应的按位与运算数组

char *color_name[] = { "BLUE", "GREEN", "RED", "WHITE" ,"CYAN","MAGENTA","YELLOW"};
uint16_t color_mask[] = { 0x001F, 0x07E0, 0xF800, 0xFFFF,0x07FF,0xF81F,0xFFE0 };

接着就是一些可以直接拿来用的函数:

  • 16*16、24*24、32*32 PCtoLCD200 字显示函数:
void show_16font(uint16_t x, uint16_t y,uint16_t fc, uint16_t bc,uint8_t *str,uint8_t mode)
{
    uint16_t i,j,k,c_num,color=0;
    boolean first = true;
    c_num = sizeof(tfont16)/sizeof(typFNT_GB16);
    for(k=0;k<c_num;k++)
    {         //pgm_read_byte
         if((pgm_read_byte(&tfont16[k].Index[0])==*str) && (pgm_read_byte(&tfont16[k].Index[1])==*(str+1)))
         {
            my_lcd.Set_Addr_Window(x, y, x+16-1, y+16-1); 
            for(j=0;j<32;j++)
            {
               for(i = 0;i<8;i++)  
               {
                  if(mode) //叠加模式
                  {
                    if(pgm_read_byte(&tfont16[k].Msk[j])&(0x80>>i))
                    {
                        my_lcd.Set_Draw_color(fc);
                        my_lcd.Draw_Pixel(x+((j*8+i)%16),y+((j*8+i)/16));
                     }
                  }
                  else   //非叠加模式
                  {
                    if(pgm_read_byte(&tfont16[k].Msk[j])&(0x80>>i))
                    {
                         color = fc;
                     }
                     else
                     {
                        color = bc;
                     }
                     my_lcd.Push_Any_Color(&color, 1, first, 0);
                    first = false;
                  }
               }
            } 
      }
    }       
}

void show_24font(uint16_t x, uint16_t y,uint16_t fc, uint16_t bc,uint8_t *str,uint8_t mode)
{
  uint16_t i,j,k,c_num,color;
  boolean first = true;
  c_num = sizeof(tfont24)/sizeof(typFNT_GB24);
  for(k=0;k<c_num;k++)
  {
    if((pgm_read_byte(&tfont24[k].Index[0])==*str) && (pgm_read_byte(&tfont24[k].Index[1])==*(str+1)))
    {
      my_lcd.Set_Addr_Window(x, y, x+24-1, y+24-1); 
      for(j=0;j<72;j++)
      {
        for(i = 0;i<8;i++)  
        {
          if(mode) //叠加模式
          {
            if(pgm_read_byte(&tfont24[k].Msk[j])&(0x80>>i))
            {
              my_lcd.Set_Draw_color(fc);
              my_lcd.Draw_Pixel(x+((j*8+i)%24),y+((j*8+i)/24));
            }
          }
          else   //非叠加模式
          {
            if(pgm_read_byte(&tfont24[k].Msk[j])&(0x80>>i))
            {
              color = fc;
            }
            else
            {
              color = bc;
            }
            my_lcd.Push_Any_Color(&color, 1, first, 0);
            first = false;
          }
        }
      } 
    }
  }
}

void show_32font(uint16_t x, uint16_t y,uint16_t fc, uint16_t bc,uint8_t *str,uint8_t mode)
{
    uint16_t i,j,k,c_num,color;
    boolean first = true;
    c_num = sizeof(tfont32)/sizeof(typFNT_GB32);
    for(k=0;k<c_num;k++)
    {
         if((pgm_read_byte(&tfont32[k].Index[0])==*str) && (pgm_read_byte(&tfont32[k].Index[1])==*(str+1)))
         {
            my_lcd.Set_Addr_Window(x, y, x+32-1, y+32-1); 
            for(j=0;j<128;j++)
            {
               for(i = 0;i<8;i++)  
               {
                  if(mode) //叠加模式
                  {
                    if(pgm_read_byte(&tfont32[k].Msk[j])&(0x80>>i))
                    {
                        my_lcd.Set_Draw_color(fc);
                        my_lcd.Draw_Pixel(x+((j*8+i)%32),y+((j*8+i)/32));
                     }
                  }
                  else   //非叠加模式
                  {
                    if(pgm_read_byte(&tfont32[k].Msk[j])&(0x80>>i))
                    {
                         color = fc;
                     }
                     else
                     {
                        color = bc;
                     }
                    my_lcd.Push_Any_Color(&color, 1, first, 0);
                    first = false;
                  }
               }
            } 
      }
    }
}

字体取模软件PCtoLCD200在第1步下载的文件夹下可以找到,生成的字体数组可以单独放在一个头文件中。

  • 显示移动函数:
void scroll(uint16_t t)
{
    uint16_t i;
     for (i = 1; i <= my_lcd.Get_Display_Width(); i++) 
     {
         my_lcd.Vert_Scroll(0, my_lcd.Get_Display_Width(), i);
         delay(t);
     }
}
void windowscroll(int16_t x, int16_t y, int16_t wid, int16_t ht, int16_t dx, int16_t dy, uint16_t *buf)
{
    if (dx)
    { 
      for (int16_t row = 0; row < ht; row++) 
      {
            my_lcd.Read_GRAM(x, y + row, buf,wid, 1);
            my_lcd.Set_Addr_Window(x, y + row, x + wid - 1, y + row);
            my_lcd.Push_Any_Color(buf + dx, wid - dx, 1,0);
            my_lcd.Push_Any_Color(buf + 0, dx, 0,0);
        }
    }
    if (dy) 
    {
      for (int16_t col = 0; col < wid; col++) 
      {
            my_lcd.Read_GRAM(x + col, y, buf,1, ht);
            my_lcd.Set_Addr_Window(x + col, y, x + col, y + ht - 1);
            my_lcd.Push_Any_Color(buf + dy, ht - dy, 1,0);
            my_lcd.Push_Any_Color(buf + 0, dy, 0,0);
      }
    }
}
  • 显示图片函数:
void showpic(void)
{
    int i;
    my_lcd.Set_Addr_Window(my_lcd.Get_Display_Width()-40-40, 20, my_lcd.Get_Display_Width()-40-1, 59); 
    my_lcd.Push_Any_Color(penguin_pic, 1600, 1, 1);
}
  • 显示汉字函数
void showchinese(uint8_t *str,uint16_t x, uint16_t y, uint16_t csize,uint16_t fc, uint16_t bc, uint8_t mode)
{    
    int i = 0;
    if(x>(my_lcd.Get_Display_Width()-csize)||y>(my_lcd.Get_Display_Height()-csize))
      { 
        return;
      }              
    while(*str!='\0')
    { 
       if(csize==32)
       {
          show_32font(x, y,fc, bc,str,mode);
       }
      else if(csize==24)
      {
          show_24font(x, y,fc, bc,str,mode);
      }
      else
      {
          show_16font(x, y,fc, bc,str,mode);
      } 
      str+=3; 
      x+=csize;              
    }   
}
  • 显示字符串函数:
void showstring(uint8_t *str,int16_t x,int16_t y,uint8_t csize,uint16_t fc, uint16_t bc,boolean mode)
{
    my_lcd.Set_Text_Mode(mode);
    my_lcd.Set_Text_Size(csize);
    my_lcd.Set_Text_colour(fc);
    my_lcd.Set_Text_Back_colour(bc);
    my_lcd.Print_String(str,x,y);
    //my_lcd.Print_Number_Float(01234.56789, 4, x, y, '.', 2, ' ');
}
  • 显示数字函数:
void shownumber(float num,int16_t x,int16_t y,uint8_t csize,uint16_t fc, uint16_t bc,boolean mode,uint16_t dotnum)
{
    my_lcd.Set_Text_Mode(mode);
    my_lcd.Set_Text_Size(csize);
    my_lcd.Set_Text_colour(fc);
    my_lcd.Set_Text_Back_colour(bc);
    my_lcd.Print_Number_Float(num, dotnum, x, y, '.', 2, ' ');
}
  • 设置背景色函数:
void setcolor(int16_t x1,int16_t y1,int16_t x2,int16_t y2,
              uint8_t *str,int16_t grade,int16_t type = 0,int16_t diff = 0)       //type  0:全填充 1:自左向右 2:自上向下 3:自中心向左右 4:自中心向上下
{
  uint16_t i,l,mask;
  for(i = 0; i < 7; i++)
  {
    if(str == color_name[i])
    break;
  }
  mask = color_mask[i];
  switch(type)
  {
  case 0:
    my_lcd.Set_Draw_color(grade*8, grade*8, grade*8); 
    my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
    my_lcd.Fill_Rectangle(x1,y1,x2,y2);
    break;  
  case 1:
    for(i = x1; i < x2; i++)
    {
      my_lcd.Set_Draw_color(grade*8-(x1-i)*diff, grade*8-(x1-i)*diff, grade*8-(x1-i)*diff);
      my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
      my_lcd.Fill_Rectangle(i,y1,i,y2);
    }
    break;  
  case 2:
    for(i = y1; i < y2; i++)
    {
      my_lcd.Set_Draw_color(grade*8-(y1-i)*diff, grade*8-(y1-i)*diff, grade*8-(y1-i)*diff);
      my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
      my_lcd.Fill_Rectangle(x1,i,x2,i);
    }
    break;  
  case 3:
    l = (x1+x2)/2;
    for(i = l; i < x2; i++)
    {
      my_lcd.Set_Draw_color(grade*8-(l-i)*diff, grade*8-(l-i)*diff, grade*8-(l-i)*diff);
      my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
      my_lcd.Fill_Rectangle(i,y1,i,y2);
    }
    for(i = l; i > x1; i--)
    {
      my_lcd.Set_Draw_color(grade*8-(i-l)*diff, grade*8-(i-l)*diff, grade*8-(i-l)*diff);
      my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
      my_lcd.Fill_Rectangle(i,y1,i,y2);
    }
    break;  
  case 4:
    l = (y1+y2)/2;
    for(i = l; i < y2; i++)
    {
      my_lcd.Set_Draw_color(grade*8-(l-i)*diff, grade*8-(l-i)*diff, grade*8-(l-i)*diff);
      my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
      my_lcd.Fill_Rectangle(x1,i,x2,i);
    }
    for(i = l; i > y1; i--)
    {
      my_lcd.Set_Draw_color(grade*8-(i-l)*diff, grade*8-(i-l)*diff, grade*8-(i-l)*diff);
      my_lcd.Set_Draw_color(my_lcd.Get_Draw_color()&mask);
      my_lcd.Fill_Rectangle(x1,i,x2,i);
    }
    break;   
  default:
    break;  
  }
}

type可以用来设置渐变色,diff可影响渐变程度

  • 以下为一些使用示例:
	//char *color_name[] = { "BLUE", "GREEN", "RED", "WHITE" ,"CYAN","MAGENTA","YELLOW"};
	//my_lcd.Fill_Screen(BLACK);                                //填充
	//my_lcd.Set_Rotation(1);                                   //02:竖屏 13:横屏
	//setcolor(0,0,100,100,"BLUE",20);                          //20 颜色深度 
	//scroll(10);
	//showstring("to blossom.Yes OK",0,160,1,GREEN, BLACK,0);   
	//showchinese("甲醛检测设备",0,150,32,YELLOW, BLACK,0);            
	//setcolor(239,0,241,320,"CYAN",30);
	
	//uint16_t scrollbuf[my_lcd.Get_Display_Height()];
	//showstring("SOFTWARE SCROLL",0,216,2,YELLOW, BLACK,0); 
	//for (int16_t i = my_lcd.Get_Display_Width(), dx = 4, dy = 0; i > 0; i -= dx)
	//{
	//  windowScroll(0, 216, my_lcd.Get_Display_Width(), 16, dx, dy, scrollbuf);
	//}

以下为setup()参考函数:

void setup()
{
  Serial.begin(9600);
  my_lcd.Init_LCD();
  Serial.println(my_lcd.Read_ID(), HEX);
  my_lcd.Fill_Screen(BLACK);                           //填充
  my_lcd.Set_Rotation(1);                             //02:竖屏 13:横屏
  //showchinese("欢迎您",0,150,32,YELLOW, BLACK,0); 
  my_lcd.Fill_Screen(BLACK);
  setcolor(240,2,241,320,"WHITE",30);
  setcolor(0,160,480,161,"WHITE",30);
  setcolor(0,0,480,30,"CYAN",15,4,10);
  showchinese("甲醛含量",0,50,32,YELLOW, BLACK,0);
  showchinese("温度",0,180,32,MAGENTA, BLACK,0);
  showchinese("℃",200,180,32,GREEN, BLACK,0);
  showchinese("湿度",0,270,32,MAGENTA, BLACK,0);
  shownumber(23.85,0,240,3,GREEN, BLACK,1,2);  
  delay(1000);
}

你可能感兴趣的:(物联网)