Arduino Nano 的 TFT 扩展板 - 开始
组件和用品
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
关于这个项目
故事
几乎没有人没见过也不知道彩色显示器是什么。而且,可能很多人已经(或想要)使用彩色显示器在 Arduino 上完成了一些项目。此外,如今的此类显示器非常普遍且价格合理。有许多显示器在分辨率、屏幕尺寸、界面上有所不同。我想谈谈这些展示之一。我们会对带有 SPI 接口、分辨率为 320x240 像素、屏幕对角线尺寸为 2.8 英寸(以及 2.4 英寸和 3.2 英寸)的显示器感兴趣。SPI 接口非常方便连接到微控制器,因为信号线少。而且SPI的速度可以让你快速更新屏幕内容。总的来说,优点很多。但是也有不爽的时候。比如需要进一步协调逻辑电平在使用 5 伏电源将显示器连接到 Arduino 板的情况下。为了将这些显示器之一(带有 SPI 接口)快速轻松地连接到 Arduino Nano,我们将使用少量费用 - TFT 屏蔽。
此扩展板是适用于 Arduino Uno 的 TFT 扩展板的第二个(轻量级,适用于 Arduino Nano)版本,您可以在此处、此处和此处阅读。
TFT屏蔽的简要说明:
- 板的尺寸为 64x49 毫米,
- 用于连接 Arduino Nano 的 30 针连接器,
- 用于将 320x240 TFT 显示器与 SPI 接口(包括触摸屏)连接的 14 针连接器,
- microSD 卡连接器,
- 蓝牙模块 (HC-06) 的连接器,
- 用于摄像机 OV7670(以及其他)的 20 针连接器,
- Mini USB 连接器,以及用于 5V 电源的单独 2 针连接器。
那么,让我们开始吧。
组装
组装电路板非常简单。但在安装前必须注意阅读触点名称。首先,您需要安装 Arduino Nano 板,如图所示。之后,连接一个显示器,可以在板的一侧连接(方法1 ) 而另一方面 (方法 2 )。之后就可以用迷你USB线连接电源了。以下是照片。
方法一:
图> 图> 图> 图> 图>方法二:
图> 图> 图> 图> 图> 图> 图> 图> 图>组装后,您可以继续下载草图,但在下载之前不要忘记安装必要的库以使用 TFT 屏蔽。该库位于链接:https://github.com/YATFT/YATFT。
演示 1. 图形和文字。
本章提供了使用文本、图形和触摸屏的示例。为方便起见,建议您首先单独对 Arduino Nano 板进行编程,然后组装设备(但您也可以将板作为设备的一部分进行编程)。用于处理文本和图形的草图:
/*********************************************** ************************************ 软件和文档“按原样”提供,不提供任何保证*种类,无论是明示的还是暗示的,包括但不限于对适销性、所有权、非侵权和特定用途适用性的任何保证*。在任何情况下,作者或其许可人均不承担责任或* 因合同、疏忽、严格责任、贡献、* 违反保证或其他法律公平理论而对任何直接或间接* 损害赔偿承担责任,* 间接、惩罚性或后果性损害、利润损失或数据丢失、* 替代品、技术、服务的采购成本或任何* 第三方索赔(包括但不限于任何其他辩护)* .**************************************************** ******************************/#include // 硬件专用库#include // 包含 Adafruit-GFX 库#include // 包含 Adafruit 字体#include #include YATFT tft(0);uint32_t total_time;uint16_t颜色[4] ={BRIGHTBLUE、BRIGHTGREEN、BRIGHTRED、BRIGHTYELLOW};uint16_t 灰色[7] ={GRAY0、GRAY1、GRAY2、GRAY3、GRAY4、GR AY5, GREY6};/******************************************** **********************************/void ClearScreen (void){ tft.SetColor(BLACK); // 设置 fone 颜色 tft.ClearDevice(); // 填满整个屏幕}void setup(){ Serial.begin(115200); // 初始化串口Serial.println("Arduino TFT_shield Example 1!"); tft.begin(); // 初始化显示}void loop(){ uint16_t x, y, x2, y2, mask_gray; uint16_t i;清除屏幕(); // 字体 Serial.print("1) 查看字体 ("); total_time =毫秒(); tft.SetColor(BRIGHTBLUE); tft.SetFont(NULL); tft.OutTextXY(5, 5, "TFT 显示器的工作演示。"); tft.SetColor(BRIGHTGREEN); tft.SetFont(&FreeSerif9pt7b); tft.OutTextXY(5, 20, "这个例子使用了 Adafruit 的字体。"); tft.SetFont(&FreeSerifItalic24pt7b); tft.SetColor(BRIGHTCYAN); tft.OutTextXY(5, 45, "3,5''"); tft.SetColor(BRIGHTRED); tft.OutTextXY(90, 45, "QVGA"); tft.SetColor(BRIGHTMAGENTA); tft.OutTextXY(230, 45, "disp."); tft.SetColor(BRIGHTYELLOW); tft.SetFont(&FreeSans24pt7b); tft.OutTextXY(5, 100, "A R D U I N O + T F T"); tft.SetFont(NULL); for (i =0; i <7; i++) { tft.SetColor(Gray[i]); tft.OutTextXY(5, 170+10*i, "TFT 显示器的工作演示。");打印总时间();延迟(3000);清除屏幕(); // Circle Serial.print("2) 画圆("); total_time =毫秒(); tft.SetColor(BRIGHTRED); for (i =10; i >1; i +=10) { tft.DrawCirc(GetMaxX()>>1, GetMaxY()>>1, i);打印总时间();延迟(1000); // DrawFillCircle &DrawFillRect Serial.print("3) 绘制FillCircle和FillRect("); total_time =毫秒(); tft.SetColor(BRIGHTRED); tft.DrawFillCirc(GetMaxX()>>1,GetMaxY()>>1,110); tft.SetColor(BRIGHTCYAN); tft.DrawFillRect(GetMaxX()/2-77,GetMaxY()/2-77,GetMaxX()/2+77,GetMaxY()/2+77); tft.SetColor(BRIGHTGREEN); tft.DrawFillCirc(GetMaxX()>>1,GetMaxY()>>1,77); tft.SetColor(BRIGHTMAGENTA); tft.DrawFillRect(GetMaxX()/2-54,GetMaxY()/2-54,GetMaxX()/2+54,GetMaxY()/2+54); tft.SetColor(BRIGHTBLUE); tft.DrawFillCirc(GetMaxX()>>1,GetMaxY()>>1,54); tft.SetColor(BRIGHTYELLOW); tft.DrawFillRect(GetMaxX()/2-37,GetMaxY()/2-37,GetMaxX()/2+37,GetMaxY()/2+37);打印总时间();延迟(1000);清除屏幕(); // Arc Serial.print("4) 绘制圆弧("); total_time =毫秒();清除屏幕(); tft.SetColor(BRIGHTBLUE); tft.DrawArc((GetMaxX()>>1)-60,(GetMaxY()>>1)-60,(GetMaxX()>>1)+60,(GetMaxY()>>1)+60,20, 30,0xFF); tft.SetColor(BRIGHTGREEN); tft.DrawArc((GetMaxX()>>1)-40,(GetMaxY()>>1)-40,(GetMaxX()>>1)+40,(GetMaxY()>>1)+40,20, 30,0xFF); tft.SetColor(BRIGHTRED); tft.DrawArc((GetMaxX()>>1)-20,(GetMaxY()>>1)-20,(GetMaxX()>>1)+20,(GetMaxY()>>1)+20,20, 30,0xFF);打印总时间();延迟(1000); Serial.print("5) 绘制 FillBevel ("); total_time =毫秒(); tft.SetColor(BRIGHTBLUE); tft.DrawFillBevel((GetMaxX()>>1)-60,(GetMaxY()>>1)-60,(GetMaxX()>>1)+60,(GetMaxY()>>1)+60,30); tft.SetColor(BRIGHTGREEN); tft.DrawFillBevel((GetMaxX()>>1)-40,(GetMaxY()>>1)-40,(GetMaxX()>>1)+40,(GetMaxY()>>1)+40,30); tft.SetColor(BRIGHTRED); tft.DrawFillBevel((GetMaxX()>>1)-20,(GetMaxY()>>1)-20,(GetMaxX()>>1)+20,(GetMaxY()>>1)+20,30);打印总时间();延迟(1000);清除屏幕(); Serial.print("6) 画圆弧("); total_time =毫秒(); for (i =0; i <4; i++) { tft.SetColor(Color[i]); tft.DrawArc((GetMaxX()>>1),(GetMaxY()>>1)-50,(GetMaxX()>>1),(GetMaxY()>>1)+50,50,60,0x11<>1),(GetMaxY()>>1)-30,(GetMaxX()>>1),(GetMaxY()>>1)+30,35,45,0x11<>1),(GetMaxY()>>1),(GetMaxX()>>1),(GetMaxY()>>1),20,30,0x11<
部分截图:
图> 图> 图> 图>
演示 2. 触摸屏。
/*********************************************** ************************************ 软件和文档“按原样”提供,不提供任何保证*种类,无论是明示的还是暗示的,包括但不限于对适销性、所有权、非侵权和特定用途适用性的任何保证*。在任何情况下,作者或其许可人均不承担责任或* 因合同、疏忽、严格责任、贡献、* 违反保证或其他法律公平理论而对任何直接或间接* 损害赔偿承担责任,* 间接、惩罚性或后果性损害、利润损失或数据丢失、* 替代品、技术、服务的采购成本或任何* 第三方索赔(包括但不限于任何其他辩护)* .**************************************************** ******************************/#include // 硬件专用库#include // 包含 SPI 库#include // 包含触摸屏库#include // 包含 Adafruit-GFX 库#include // 包含 Adafruit 字体#include #include // 触摸屏:MOSI=11, MISO=12, SCK=13, CS=2#define CS_PI N A0XPT2046_Touchscreen ts(CS_PIN, 255);YATFT tft(0);#define Y_BAR_TOP (GetMaxY()-50)#define Y_BAR_BOT GetMaxY()/* 如果使用屏蔽,所有控制线和数据线都是固定的,更简单的声明可以选择使用:*/uint16_t pos_x[] ={0,0,0,0};uint16_t pos_y[] ={0,0,0,0};uint8_t pos_x_cnt =0;uint8_t pos_y_cnt =0;uint16_t =pos_x_mid 0;uint16_t pos_y_mid =0;uint16_t color_paint =WHITE;uint8_t 按钮 =0;uint16_t Color[4] ={BRIGHTBLUE, BRIGHTGREEN, BRIGHTRED, BRIGHTYELLOW};uint16_t Gray[7], GRAY,GRAY4, GRAYRA灰色5, 灰色6};/******************************************** ****************************************************** ***/void ClearScreen (void){ tft.SetColor(BLACK); // 设置 fone 颜色 tft.ClearDevice(); // 填满整个屏幕}void setup(){ Serial.begin(115200); // 初始化串口Serial.println("Arduino TFT_shield Example1!"); ts.begin(); // 初始化触摸屏 SPI.end(); // 为正确工作禁用 SPI DB2 (SS) pin tft.begin(); // 初始化显示 RefreshWindow();}void loop(){ uint16_t x, y; // 触摸 // 当 SS 引脚设置为 OUTPUT 时,它可以用作 // 通用输出端口(它不影响 // SPI 操作)。 SPI.begin(); if (ts.touched()) { TS_Point p =ts.getPoint(); Serial.print(F("压力 =")); Serial.print(p.z); Serial.print(F(", x =")); Serial.print(p.x); Serial.print(F(", y =")); Serial.print(p.y); Serial.println();延迟(3); // 延迟过滤 SPI.end(); // 为正确工作禁用 SPI DB2 (SS) 引脚 // 从代码 ADC Serial.print(F("Pressure =")) 计算坐标 x, y; Serial.print(p.z); Serial.print(F(", x =")); Serial.print(p.x); Serial.print(F(", ")); Serial.print(x); Serial.print(F(", y =")); Serial.print(p.y); Serial.print(F(", ")); Serial.print(y); Serial.println();如果 (p.x <350) p.x =350;如果 (p.x> 3850) p.x =3850;如果 (p.y <250) p.y =250;如果 (p.y> 3850) p.y =3850; x =(uint16_t)(320L - ((uint32_t)p.x - 350L)*100L/1094L); y =(uint16_t)(240L - ((uint32_t)p.y - 250L)*100L/1510L); // 过滤 pos_x_mid =(pos_x[0] + pos_x[1] + pos_x[2] + pos_x[3])/4; pos_y_mid =(pos_y[0] + pos_y[1] + pos_y[2] + pos_y[3])/4; pos_x[pos_x_cnt++] =x; pos_y[pos_y_cnt++] =y; pos_x_cnt &=0x03; pos_y_cnt &=0x03; if (x> (pos_x_mid - 10) &&x <(pos_x_mid + 10) &&y> (pos_y_mid - 10) &&y <(pos_y_mid + 10 )) { if (y> Y_BAR_TOP &&y
部分截图:
图> 图>
演示 3. 逻辑游戏“列”。
/*********************************************** ************************************ 软件和文档“按原样”提供,不提供任何保证*种类,无论是明示的还是暗示的,包括但不限于对适销性、所有权、非侵权和特定用途适用性的任何保证*。在任何情况下,作者或其许可人均不承担责任或* 因合同、疏忽、严格责任、贡献、* 违反保证或其他法律公平理论而对任何直接或间接* 损害赔偿承担责任,* 间接、惩罚性或后果性损害、利润损失或数据丢失、* 替代品、技术、服务的采购成本或任何* 第三方索赔(包括但不限于任何其他辩护)* .**************************************************** ******************************/#include #include #include #include // 核心图形库#include #include #define CS_PIN A0// MOSI=11, MISO=12, SCK=13XPT2046_Touchscreen ts (CS_PIN, 255);YATFT tft(0);/* 如果使用屏蔽,所有控制线和数据线都是固定的,可以选择使用更简单的声明:*/long randNumber;#define KEY_EMPTY 0#define KEY_SWAP 1#define KEY_FALL 2#define KEY_LEFT 3#define KEY_RIGHT 4#define DISPLAY_MAX_X 320#define DISPLAY_MAX_Y 240#define MaxCol 8 #define SRowme X3#define S #define razmer 15#define LL 250#define NumCol 6#define MaxLevel 8#define PeriodLevel 80#define DISP_LEFT ((DISPLAY_MAX_X - MaxCol*razmer)/2 - 2)#define DISP_RIGHT ((DISPLAY_MAX_X + MaxCol*razmer)/2 + 2)#define DISP_TOP ((DISPLAY_MAX_Y - (MaxRow-4)*razmer)/2 - 2 - 10)#define DISP_BOT ((DISPLAY_MAX_Y + (MaxRow-4)*razmer)/2 + 2 - 10)uint8_t MasSt[MaxCol ][MaxRow], MasTmp[MaxCol][MaxRow], MasOld[MaxCol][MaxRow], fignext[3];uint8_t Level=1, OldLevel, tr, flfirst=1;uint16_t MasCol[]={WHITE, BLACK, BRIGHTRED , BRIGHTBLUE, BRIGHTGREEN, BRIGHTYELLOW, BRIGHTMAGENTA, BRIGHTCYAN};unsigned long Counter,Score=0, TScore=0, Record=0, OldRecord, OldScore, myrecord;uint16_t tempspeed;bool fl, Demo=true, myfl=false, Arbeiten false, FlNew, FlZ=false;int8_t VAL, Mp, x,y;int8_t mmm [4][2]={ {-1,0},{0,-1},{1,0},{0,1}};uint16_t MasSpeed[MaxLevel]={500,450,400,350,300,250,200,100};/************ ****************************************************** ****/void setup(void){ // 初始化串口Serial.begin(115200); Serial.println("TFT_shield_Game1 示例!"); ts.begin(); // 初始化触摸屏 SPI.end(); tft.begin(); // 初始化显示 randomSeed(analogRead(5)); tft.SetColor(白色); tft.ClearDevice(); tft.SetColor(红色); tft.SetFont(&FreeSerif9pt7b); tft.OutTextXY(20, 20, "LEVEL"); tft.OutTextXY(240, 20, "下一个"); tft.OutTextXY(20, 75, "分数"); tft.OutTextXY(25, 130, "TOP"); FlNew =真; ViewStacan();获取下一个();延迟(100); tft.SetColor(黑色); tft.DrawLine(DISP_LEFT + 1, DISP_TOP + 0, DISP_LEFT + 1, DISP_BOT - 1); tft.DrawLine(DISP_LEFT + razmer*MaxCol+5-MaxCol,DISP_TOP + 0,DISP_LEFT + razmer*MaxCol+5-MaxCol, DISP_BOT - 1); tft.DrawLine(DISP_LEFT + 1, DISP_BOT - 1, DISP_LEFT + 1+razmer*MaxCol+5-MaxCol-1, DISP_BOT - 1);}void loop(void){ if (Demo) ProcDemo(); else { if (Arbeiten) { mydelay(tempspeed); figmove(0,1); } else if (mypush()==KEY_SWAP) NewGame(); }}uint8_t mypush(void){ unsigned long tpr =millis(); uint8_t res =KEY_EMPTY; uint8_t 按钮 =0;静态 uint8_t button_old;静态 uint8_t cnt =0;按钮 =触摸();如果(按钮){ cnt =5; Serial.print("扫描按钮:"); Serial.print(按钮,十六进制); Serial.println(); if (button !=button_old) { if (button &0x01) res =KEY_SWAP; if (button &0x02) res =KEY_FALL;如果(按钮和 0x04){}; if (button &0x08) res =KEY_LEFT; if (button &0x10) res =KEY_RIGHT; button_old =按钮; } } if (!cnt) { button_old =button; } else { cnt--;返回(res); }void ViewQuad(uint8_t i,uint8_t j,uint8_t mycolor){ if (j<3) return; uint16_t wy =DISP_TOP + SmeY + (j-3)*razmer - j; uint16_t wx =DISP_LEFT + SmeX + i*razmer - i; if (mycolor!=0) { tft.SetColor(BLACK); tft.DrawRect(wx, wy, wx+razmer-1, wy+razmer-1); tft.SetColor(MasCol[mycolor]); tft.DrawFillRect(wx+1, wy+1, wx+1+razmer-3, wy+1+razmer-3); } else { tft.SetColor(白色); tft.DrawFillRect(wx+1, wy+0, wx+1+razmer-3, wy+1+razmer-3); }}void ViewStacan(void){ char myStr2[5]; uint8_t h =tft.GetTextHeight(&FreeMonoBoldOblique12pt7b); tft.SetFont(&FreeMonoBoldOblique12pt7b); if (OldScore!=Score || FlNew) { sprintf(myStr2,"%05d",Score); int16_t w =tft.GetTextWidth(myStr2, &FreeMonoBoldOblique12pt7b); tft.SetColor(白色); tft.DrawFillRect(20,100,20+w+5,100+h); tft.SetColor(绿色); tft.OutTextXY(20,100,myStr2); OldScore=分数; } if (OldRecord!=Record || FlNew) { sprintf(myStr2,"%05d",Record ); int16_t w =tft.GetTextWidth(myStr2, &FreeMonoBoldOblique12pt7b); tft.SetColor(白色); tft.DrawFillRect(20,155,20+w+5,155+h); tft.SetColor(绿色); tft.OutTextXY(20,155,myStr2); OldRecord=记录; } if (OldLevel!=Level || FlNew) { sprintf(myStr2,"%01d",Level ); int16_t w =tft.GetTextWidth(myStr2, &FreeMonoBoldOblique12pt7b); tft.SetColor(白色); tft.DrawFillRect(25,45,25+w+5,45+h); tft.SetColor(绿色); tft.OutTextXY(25,45,myStr2);旧等级=等级; } FlNew=false; for (byte j=3;j=0 &&ny>=0 &&nx1 || MasTmp[i][j]>2 )) { MasTmp[nx][ny]=3; MasTmp[i][j]=3; } else if (mode==3 &&MasTmp[nx][ny]==3) { if (MasTmp[i][j]!=3) { MasTmp[i][j]=3;飞行=真; } } }}void Sos(int i,int j, byte mode){ for (byte k=0;k<4;k++) Sosed(i,j,mmm[k][0],mmm[k][1] ],模式); }bool FindFull(void){ 字节 i,j,k;布尔资源;资源=假; for (byte k=2;k<8;k++) { ClearMas(MasTmp); for (j=3;j1) Sos(i,j,2);做 { fl=false; for (j=3;j0) Sos(i,j,3); } while (fl); for (j=3;j0) { ViewStacan(); FlZ=真;我的延迟(500); } for (j=0;jMaxLevel) Level=MaxLevel; } tempspeed=MasSpeed[Level-1]; }}void MyScore(void){ TScore=0; while(FindFull()) { if (TScore>7) Score=Score+TScore+(TScore-8)*2;其他分数=分数+TS分数; ViewStacan(); FlZ=真;我的延迟(1000); } FlZ=false;}void ProcDemo(void){ Score=0;获取下一个(); for (byte j=3;jMaxCol-1) return(false); if (dx!=0) if (MasSt[x+dx][y+dy+2]==0) return(true);否则返回(假); if (dy>0) { if (y+dy+2>MaxRow-1 || MasSt[x+dx][y+dy+2]>0) { if (y<3) gameover();否则 fff=true; } else { for (byte i=0;i<3;i++) MasSt[x][y+2-i+dy]=MasSt[x][y+2-i]; MasSt[x][y]=0; y=y+dy; } if (fff) { MyScore();获取下一个(); ViewStacan(); } return(true);}uint8_t Touch(void){ uint16_t x, y; uint8_t 按钮 =0; // 触摸 // 当 SS 引脚设置为 OUTPUT 时,它可以用作 // 通用输出端口(它不影响 // SPI 操作)。 SPI.begin(); if (ts.touched()) { TS_Point p =ts.getPoint();延迟(3); // 延迟过滤 SPI.end(); // 从代码 ADC 计算坐标 x, y if (p.x <450) p.x =450;如果 (p.y <500) p.y =500; x =(uint16_t)(320L - ((uint32_t)p.x - 450L)*10L/106L); y =(uint16_t)(240L - ((uint32_t)p.y - 500L)*10L/140L); if (x <80) { // 左键 =0x08; } else if (x> 240) { // 右键 =0x10; } else if (y <120) { // 交换按钮 =0x01; }其他按钮=0x02; // 下降 } SPI.end();返回按钮;}
部分截图:
图>
演示视频
待续。
谢谢关注!
以前的文章:
1) Arduino Uno 的独特 TFT 扩展板 - 开始,
2) Arduino Uno 独特的 TFT 扩展板 - OV7670 Cam Live View,
3) Arduino Uno 的独特 TFT 扩展板 - Arduino 蓝牙相机 (ABC)。
下一篇:
4) TFT SPI 显示器上的照片和 RGB 视频。
2021 年 4 月 1 日更新:
再一次问好!有一系列屏幕的更新库,目前由两个屏蔽和两个分线板组成。根据所选版本(从 1 到 4)和微控制器类型(MegaAVR 或 ESP-32)编译草图。添加了照片,示例。更多信息可以在 https://github.com/Ekaburg/EkaTFT 中找到。
代码
图书馆
https://github.com/YATFT/YATFT制造工艺