授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。但愿你们分享给你周边须要的朋友或者同窗,说不定大神成长之路有博哥的奠定石。。。html
QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷git
1、基础篇github
2、网络篇web
- ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
- ESP8266开发之旅 网络篇② ESP8266 工做模式与ESP8266WiFi库
- ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
- ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
- ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
- ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
- ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
- ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
- ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
- ESP8266开发之旅 网络篇⑩ UDP服务
- ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用
- ESP8266开发之旅 网络篇⑫ 域名服务——ESP8266mDNS库
- ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 Flash文件系统
- ESP8266开发之旅 网络篇⑭ web配网
- ESP8266开发之旅 网络篇⑮ 真正的域名服务——DNSServer
- ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新
3、应用篇设计模式
4、高级篇缓存
最近博主听到QQ群里面问得比较多的问题:
“博哥,有玩过OLED吗?”
“博哥,有试过在ESP8266上调成功过SSD1306吗?”
“博哥,OLED上显示天气信息怎么弄?”
........
诸如此类的问题,在博主看来,无非都是对OLED库用法的不熟悉甚至不了解。Arduino OLED库众多,博主也曾经介绍过一款 《博哥OLED系列》- 玩转SSD1306-12864 OLED Adafruit_GFX 和 Adafruit_SSD1306库。可是,博主今天要介绍的是目前Arduino平台上使用最普遍的OLED库 —— U8G2库,也是不少初学者容易懵逼的一个第三方库。目前在github上超过1K star,1800次commit,能够说维护热度很高,读者大可放心使用。
至于这个库为何这么火爆,请读者认真看完本博文自行评价,博主只能说功能真的很好很强大!!!!
那么,博主首先立个flag,阅读完本篇博文的最终效果——读者之后在Arduino平台上开发OLED项目的时候,能够考虑U8G2库,而且知道U8G2库的具体用法,甚至能够可以当作工具书来翻阅。
进入正文以前,博主要给读者灌输两个个很是重要的知识点:网络
OLED其实就是一个M x n 的像素点阵,想显示什么就得把具体位置的像素点亮起来。对于每个像素点,有多是1点亮,也有多是0点亮;
在坐标系中,左上角是原点,向右是X轴,向下是Y轴。app
但愿读者能仔细理解这两个知识点。函数
U8g2是嵌入式设备的单色图形库,一句话简单明了。主要应用于嵌入式设备,包括咱们常见的单片机;工具
U8g2支持单色OLED和LCD,包括如下控制器:SSD1305,SSD1306,SSD1309,SSD1322,SSD1325,SSD1327,SSD1329,SSD1606,SSD1607,SH1106,SH1107,SH1108,SH1122,T6963,RA8835,LC7981,PCD8544,PCF8812,HX1230 ,UC1601,UC1604,UC1608,UC1610,UC1611,UC1701,ST7565,ST7567,ST7588,ST75256,NT7534,IST3020,ST7920,LD7032,KS0108,SED1520,SBN1661,IL3820,MAX7219(有关完整列表,请参见 此处)。
能够说,基本上主流的显示控制器都支持,好比咱们常见的SSD1306 12864,读者在使用该库以前请查阅本身的OLED显示控制器是否处于支持列表中。
能够说基本上全部Arduino API的主板都获得U8g2的支持。包括:
因此说,读者彻底不用担忧兼容性问题,放心使用。
Arduino库U8g2能够从Arduino IDE的库管理器安装,读者在库管理器搜索“U8g2”关键字就能够下载安装:
下载完毕,测试一下库是否安装成功:
#include <U8g2lib.h> void setup() { // put your setup code here, to run once: } void loop() { // put your main code here, to run repeatedly: }
编译成功,证实你本地已经加载了U8G2库。
为何要运用U8g2库?也就是说U8g2库能带给咱们什么样的开发便利。在博主看来,主要考虑几个方面:
如下是官方提供的一些U8G2库测试图,博主挑选了几张常见的以及附上U8G2库的配置(读者能够先不用理会配置,等看完博文再次阅读就会了解含义):
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R2, /* clock=*/ 16, /* data=*/ 17, /* reset=*/ U8X8_PIN_NONE); // ESP32 Thing, pure SW emulated I2C U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17); // ESP32 Thing, HW I2C with pin remapping
U8G2_MAX7219_32X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1305_128X32_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
U8X8_SSD1306_128X32_UNIVISION_SW_I2C u8x8(/* clock=A5*/ 19, /* data=A4*/ 18);
U8G2_PCD8544_84X48_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Nokia 5110 Display
U8G2_ST7920_128X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18 /* A4 */, /*cs=*/ U8X8_PIN_NONE, /*dc/rs=*/ 17 /* A3 */, /*reset=*/ 15 /* A1 */); // Remember to set R/W to 0
这只是一些常见的显示器,能够说,已经足够覆盖到咱们常见的范围了。
老规则,先上一个图:
方法能够分为四大类:
函数说明:
/** * 初始化U8g2库 * @Note 关联方法 initDisplay clearDisplay setPowerSave */ bool U8G2::begin(void)
源码说明:
bool begin(void) { /* note: call to u8x8_utf8_init is not required here, this is done in the setup procedures before */ initDisplay(); //初始化显示器 clearDisplay(); // 重置清屏 setPowerSave(0); //唤醒屏幕 return 1; }
函数说明:
/** * 简单初始化U8g2库 * @Note 关联方法 beginSimple */ void U8G2::beginSimple(void);
源码说明:
void beginSimple(void) { /* does not clear the display and does not wake up the display */ /* user is responsible for calling clearDisplay() and setPowerSave(0) */ initDisplay();//初始化显示器 }
注意点:
函数说明:
/** * 初始化显示控制器 */ void U8G2::initDisplay(void)
注意点:
函数说明:
/** * 清除屏幕 */ void U8G2::clearDisplay(void)
注意点:
函数说明:
/** * 清除显示缓冲区 * @param is_enable * 1 表示启用显示器的省电模式,屏幕上看不到任何东西 * 0 表示禁用省电模式 */ void U8G2::setPowerSave(uint8_t is_enable)
注意点:
函数说明:
/** * 清除屏幕显示,清除缓冲区,光标回到左上角原点位置(0,0) * @Note 关联方法 home clearDisplay clearBuffer */ void U8G2::clear(void)
源码说明:
void clear(void) { home(); //回到原点 clearDisplay(); //清除屏幕上的显示 clearBuffer(); //清除缓冲区 }
函数说明:
/** * 清除内存中数据缓冲区 */ void U8G2::clearBuffer(void)
注意点:
void loop(void) { u8g2.clearBuffer(); // ... write something to the buffer u8g2.sendBuffer(); delay(1000); }
函数说明:
/** * 禁用Arduino平台下支持输出UTF8字符集,默认是开启 */ void U8G2::disableUTF8Print(void)
函数说明:
/** * 开启Arduino平台下支持输出UTF8字符集 */ void U8G2::enableUTF8Print(void)
注意点:
void setup(void) { u8g2.begin(); u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function } void loop(void) { u8g2.setFont(u8g2_font_unifont_t_chinese2); // use chinese2 for all the glyphs of "你好世界" u8g2.firstPage(); do { u8g2.setCursor(0, 40); u8g2.print("你好世界"); // Chinese "Hello World" } while ( u8g2.nextPage() ); delay(1000); }
函数说明:
/** * 重置显示光标的位置,回到原点(0,0) * @Note 关联方法 print clear */ void U8G2::home(void)
函数说明:
/** * 画实心方形,左上角坐标为(x,y),宽度为w,高度为h * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param w 方形的宽度 * @param h 方形的高度 * @Note 关联方法 drawFrame setDrawColor */ void U8G2::drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h)
注意点:
示例:
u8g2.drawBox(3,7,25,15);
函数说明:
/** * 画空心圆,圆心坐标为(x0,y0),半径为rad * @param x0 圆点的x坐标 * @param y0 圆点的y坐标 * @param rad 圆形的半径 * @param opt 圆形选项 * U8G_DRAW_ALL 整个圆 * U8G2_DRAW_UPPER_RIGHT 右上部分的圆弧 * U8G2_DRAW_UPPER_LEFT 左上部分的圆弧 * U8G2_DRAW_LOWER_LEFT 左下部分的圆弧 * U8G2_DRAW_LOWER_RIGHT 右下部分的圆弧 * 选项能够经过 | 操做符来组合 * @Note 关联方法 drawDisc setDrawColor */ void U8G2::drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL)
注意点:
示例:
u8g2.drawCircle(20, 25, 10, U8G2_DRAW_ALL);
函数说明:
/** * 画实心圆,圆心坐标为(x0,y0),半径为rad * @param x0 圆点的x坐标 * @param y0 圆点的y坐标 * @param rad 圆形的半径 * @param opt 圆形选项 * U8G_DRAW_ALL 整个圆 * U8G2_DRAW_UPPER_RIGHT 右上部分的圆弧 * U8G2_DRAW_UPPER_LEFT 左上部分的圆弧 * U8G2_DRAW_LOWER_LEFT 左下部分的圆弧 * U8G2_DRAW_LOWER_RIGHT 右下部分的圆弧 * 选项能够经过 | 操做符来组合 * @Note 关联方法 drawCircle setDrawColor */ void U8G2::drawDisc(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G_DRAW_ALL)
注意点:
函数说明:
/** * 画空心椭圆,圆心坐标为(x0,y0),半径为rad * @param x0 圆点的x坐标 * @param y0 圆点的y坐标 * @param rx 椭圆形水平x方向的半径 * @param ry 椭圆形竖直y方向的半径 * @param opt 圆形选项 * U8G_DRAW_ALL 整个椭圆 * U8G2_DRAW_UPPER_RIGHT 右上部分的圆弧 * U8G2_DRAW_UPPER_LEFT 左上部分的圆弧 * U8G2_DRAW_LOWER_LEFT 左下部分的圆弧 * U8G2_DRAW_LOWER_RIGHT 右下部分的圆弧 * 选项能够经过 | 操做符来组合 * @Note 关联方法 drawCircle */ void U8G2::drawEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt)
注意点:
示例:
u8g2.drawEllipse(20, 25, 15, 10, U8G2_DRAW_ALL);
函数说明:
/** * 画实心椭圆,圆心坐标为(x0,y0),半径为rad * @param x0 圆点的x坐标 * @param y0 圆点的y坐标 * @param rx 椭圆形水平x方向的半径 * @param ry 椭圆形竖直y方向的半径 * @param opt 圆形选项 * U8G_DRAW_ALL 整个椭圆 * U8G2_DRAW_UPPER_RIGHT 右上部分的圆弧 * U8G2_DRAW_UPPER_LEFT 左上部分的圆弧 * U8G2_DRAW_LOWER_LEFT 左下部分的圆弧 * U8G2_DRAW_LOWER_RIGHT 右下部分的圆弧 * 选项能够经过 | 操做符来组合 * @Note 关联方法 drawCircle */ void U8G2::drawFilledEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt)
注意点:
函数说明:
/** * 画空心方形,左上角坐标为(x,y),宽度为w,高度为h * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param w 方形的宽度 * @param h 方形的高度 * @Note 关联方法 setDrawColor */ void U8G2::drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h)
注意点:
示例:
u8g2.drawFrame(3,7,25,15);
函数说明:
/** * 绘制字体字集里面定义的符号 * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param encoding 字符的unicode值 * @Note 关联方法 setFont */ void U8G2::drawGlyph(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)
注意点:
函数说明:
/** * 绘制水平线 * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param w 水平线的长度 * @Note 关联方法 setDrawColor */ void U8G2::drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w)
注意点:
函数说明:
/** * 绘制线,从坐标(x0,y0) 到(x1,y1) * @param x0 端点0的x坐标 * @param y0 端点0的y坐标 * @param x1 端点1的x坐标 * @param y1 端点1的y坐标 * @Note 关联方法 setDrawColor */ void U8G2::drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1)
注意点:
示例:
u8g2.drawLine(20, 5, 5, 32);
函数说明:
/** * 绘制像素点,坐标(x,y) * @param x 像素点的x坐标 * @param y 像素点的y坐标 * @Note 关联方法 setDrawColor */ void U8G2::drawPixel(u8g2_uint_t x, u8g2_uint_t y)
注意点:
函数说明:
/** * 绘制圆角实心方形,左上角坐标为(x,y),宽度为w,高度为h,圆角半径为r * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param w 方形的宽度 * @param h 方形的高度 * @param r 圆角半径 */ void U8G2::drawRBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r)
注意点:
函数说明:
/** * 绘制圆角空心方形,左上角坐标为(x,y),宽度为w,高度为h,圆角半径为r * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param w 方形的宽度 * @param h 方形的高度 * @param r 圆角半径 */ void U8G2::drawRFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r)
注意点:
示例:
u8g2.drawRFrame(20,15,30,22,7);
函数说明:
/** * 绘制字符串 * @param x 左上角的x坐标 * @param y 左上角的y坐标 * @param s 绘制字符串内容 * @return 字符串的长度 */ u8g2_uint_t U8g2::drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s)
注意点:
示例:
u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.drawStr(0,15,"Hello World!");
函数说明:
/** * 绘制实心三角形,定点坐标分别为(x0,y0),(x1,y1),(x2,y2) */ void U8G2::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)
示例:
u8g2.drawTriangle(20,5, 27,50, 5,32);
函数说明:
/** * 绘制UTF8编码的字符串 * @param x 字符串在屏幕上的左下角x坐标 * @param y 字符串在屏幕上的左下角y坐标 * @param s 须要绘制的UTF-8编码字符串 * @return 返回字符串的长度 */ u8g2_uint_t U8g2::drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s)
注意点:
示例:
u8g2.setFont(u8g2_font_unifont_t_symbols); u8g2.drawUTF8(5, 20, "Snowman: ☃");
函数说明:
/** * 绘制竖直线 * @param x 左上角坐标x * @param y 左上角坐标y * @param h 高度 */ void U8G2::drawVLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t h)
函数说明:
/** * 绘制图像 * @param x 左上角坐标x * @param y 左上角坐标y * @param w 图形宽度 * @param h 图形高度 * @param bitmap 图形内容 * @Note 关联方法 setBitmapMode */ void U8G2::drawXBM(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap) void U8G2::drawXBMP(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap)
注意点:
函数说明:
/** * 绘制图像 */ void U8G2::firstPage(void) uint8_t U8G2::nextPage(void)
注意点:
优点点:
示例:
u8g2.firstPage(); do { /* all graphics commands have to appear within the loop body. */ u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.drawStr(0,20,"Hello World!"); } while ( u8g2.nextPage() );
库源码解析:
void u8g2_FirstPage(u8g2_t *u8g2) { if ( u8g2->is_auto_page_clear ) { //清除缓冲区 u8g2_ClearBuffer(u8g2); } //设置当前缓冲区的Tile Row 一个Tile等于8个像素点的高度 u8g2_SetBufferCurrTileRow(u8g2, 0); } uint8_t u8g2_NextPage(u8g2_t *u8g2) { uint8_t row; u8g2_send_buffer(u8g2); row = u8g2->tile_curr_row; row += u8g2->tile_buf_height; if ( row >= u8g2_GetU8x8(u8g2)->display_info->tile_height ) { //若是row已经到达最后一行,触发refreshDisplay调用,表示整个页面已经刷完了 u8x8_RefreshDisplay( u8g2_GetU8x8(u8g2) ); return 0; } if ( u8g2->is_auto_page_clear ) { //清除缓冲区 u8g2_ClearBuffer(u8g2); } //不断更新TileRow 这是很是关键的一步 u8g2_SetBufferCurrTileRow(u8g2, row); return 1; }
函数说明:
/** * 绘制内容 * @Note 关联方法 setFont setCursor enableUTF8Print */ void U8G2::print(...)
示例:
u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 15); u8g2.print("Hello World!");
函数说明:
/** * 绘制缓冲区的内容 * @Note 关联方法 clearBuffer */ void U8G2::sendBuffer(void)
注意点:
库源码解析:
void u8g2_SendBuffer(u8g2_t *u8g2) { u8g2_send_buffer(u8g2); u8x8_RefreshDisplay( u8g2_GetU8x8(u8g2) ); } static void u8g2_send_tile_row(u8g2_t *u8g2, uint8_t src_tile_row, uint8_t dest_tile_row) { uint8_t *ptr; uint16_t offset; uint8_t w; w = u8g2_GetU8x8(u8g2)->display_info->tile_width; offset = src_tile_row; ptr = u8g2->tile_buf_ptr; offset *= w; offset *= 8; ptr += offset; u8x8_DrawTile(u8g2_GetU8x8(u8g2), 0, dest_tile_row, w, ptr); } /* write the buffer to the display RAM. For most displays, this will make the content visible to the user. Some displays (like the SSD1606) require a u8x8_RefreshDisplay() */ static void u8g2_send_buffer(u8g2_t *u8g2) U8X8_NOINLINE; static void u8g2_send_buffer(u8g2_t *u8g2) { uint8_t src_row; uint8_t src_max; uint8_t dest_row; uint8_t dest_max; src_row = 0; src_max = u8g2->tile_buf_height; dest_row = u8g2->tile_curr_row; dest_max = u8g2_GetU8x8(u8g2)->display_info->tile_height; do { u8g2_send_tile_row(u8g2, src_row, dest_row); src_row++; dest_row++; } while( src_row < src_max && dest_row < dest_max ); }
示例:
void loop(void) { u8g2.clearBuffer(); // ... write something to the buffer u8g2.sendBuffer(); delay(1000);
函数说明:
/** * 获取基准线以上的高度 * @return 返回高度值 * @Note 关联方法 setFont getDescent setFontRefHeightAll */ int8_t U8G2::getAscent(void)
注意点:
示例:
下面例子,ascent是18
函数说明:
/** * 获取基准线如下的高度 * @return 返回高度值 * @Note 关联方法 setFont setFontRefHeightAll */ int8_t U8G2::getDescent(void)
注意点:
示例:
下面例子,descent是-5
函数说明:
/** * 获取显示器的高度 * @return 返回高度值 */ u8g2_uint_t getDisplayHeight(void)
函数说明:
/** * 获取显示器的宽度 * @return 返回宽度值 */ u8g2_uint_t getDisplayWidth(void)
函数说明:
/** * 获取当前字体里的最大字符的高度 * @return 返回高度值 * @Note 关联方法 setFont */ u8g2_uint_t getMaxCharHeight(void)
注意点:
函数说明:
/** * 获取当前字体里的最大字符的宽度 * @return 返回宽度值 * @Note 关联方法 setFont */ u8g2_uint_t getMaxCharWidth(void)
注意点:
函数说明:
/** * 获取字符串的像素宽度 * @param s 绘制字符串 * @return 返回字符串的像素宽度值 * @Note 关联方法 setFont drawStr */ u8g2_uint_t U8G2::getStrWidth(const char *s)
注意点:
函数说明:
/** * 获取UTF-8字符串的像素宽度 * @param s 绘制字符串 * @return 返回字符串的像素宽度值 * @Note 关联方法 setFont drawStr */ u8g2_uint_t U8G2::getUTF8Width(const char *s)
注意点:
函数说明:
/** * 是否自动清除缓冲区 * @param mode 0 表示关闭 * 1 表示开启,默认是开启 */ void U8G2::setAutoPageClear(uint8_t mode)
注意点:
函数说明:
/** * 设置位图模式(定义drawXBM方法是否绘制背景颜色) * @param is_transparent * 0 绘制背景颜色,不透明,默认是该值 * 1 不绘制背景颜色,透明 * @Note 关联方法 drawXBM */ void U8G2::setBitmapMode(uint8_t is_transparent)
示例:
u8g2.setDrawColor(1); u8g2.setBitmapMode(0); u8g2.drawXBM(4,3, u8g2_logo_97x51_width, u8g2_logo_97x51_height, u8g2_logo_97x51_bits); u8g2.drawXBM(12,11, u8g2_logo_97x51_width, u8g2_logo_97x51_height, u8g2_logo_97x51_bits);
u8g2.setDrawColor(1); u8g2.setBitmapMode(1); u8g2.drawXBM(4,3, u8g2_logo_97x51_width, u8g2_logo_97x51_height, u8g2_logo_97x51_bits); u8g2.drawXBM(12,11, u8g2_logo_97x51_width, u8g2_logo_97x51_height, u8g2_logo_97x51_bits);
函数说明:
/** * 设置总线时钟(I2C SPI) * @param mode clock_speed 总线时钟频率(Hz) * @Note 关联方法 begin */ void U8G2::setBusClock(uint32_t clock_speed);
注意点:
函数说明:
/** * 设置采集窗口,窗口范围从左上角(x0,y0)到右下角(x1,y1) * 也就是咱们绘制的内容只能在规范范围内显示 * @param x0 左上角x坐标 * @param y0 左上角y坐标 * @param x1 右上角x坐标 * @param y1 右上角y坐标 * @Note 关联方法 begin */ void U8G2::setClipWindow(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1 );
注意点:
void U8G2::setMaxClipWindow(void)
示例:
u8g2.setClipWindow(10, 10, 85, 30); u8g2.setDrawColor(1); u8g2.drawStr(3, 32, "U8g2");
函数说明:
/** * 设置绘制光标位置(x,y) * @Note 关联方法 print */ void U8G2::setCursor(u8g2_uint_t x, u8g2_uint_t y)
示例:
u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.setCursor(0, 15); u8g2.print("Hello World!");
函数说明:
/** * 设置显示器的旋转角度 * @param u8g2_cb 旋转选项 * U8G2_R0 不作旋转 水平 * U8G2_R1 旋转90度 * U8G2_R2 旋转180度 * U8G2_R3 旋转270度 * U8G2_MIRROR 不作旋转 水平,显示内容是镜像的,暂时不理解 */ void setDisplayRotation(const u8g2_cb_t *u8g2_cb)
函数说明:
/** * 设置绘制颜色(暂时尚未具体去了解用法) */ void U8G2::setDrawColor(uint8_t color)
这是一个很是重要的方法,很是重要!!!
函数说明:
/** * 设置字体集(字体集用于字符串绘制方法或者glyph绘制方法) * @param font 具体的字体集 * @Note 关联方法 drawUTF8 drawStr drawGlyph print */ void U8G2::setFont(const uint8_t *font)
Font会根据像素点高度作了不少区分,具体font请参考 wiki。
若是咱们须要用到中文字符,能够在wiki里面搜索一下chinese,你就会发现不少中文font,好比:
//支持UTF-8或者GB2312编码 u8g2_font_wqy15_t_chinese1 u8g2_font_wqy15_t_chinese2 u8g2_font_wqy15_t_chinese3 u8g2_font_wqy12_t_gb2312 u8g2_font_wqy12_t_gb2312a ......
注意点:
至于用哪个,看本身的需求了。
咱们看看Font的命名规则:
<prefix> '_' <name> '_' <purpose> <char set>
其中:
|
描述 |
---|---|
t | Transparent font, Do not use a background color. |
h | All glyphs have common height(全部的图形有通用的高度). |
m | All glyphs have common height and width (monospace). |
8 | All glyphs fit into a 8x8 pixel box. |
|
描述 |
---|---|
f | The font includes up to 256 glyphs. |
r | Only glyphs on the range of the ASCII codes 32 to 127 are included in the font. |
u | Only glyphs on the range of the ASCII codes 32 to 95 (uppercase chars) are included in the font. |
n | Only numbers and extra glyphs for writing date and time strings are included in the font. |
... | Other custom character list. |
注意点:
示例:Fonts u8g2_font_5x7_tr and u8g2_font_pressstart2p_8u
函数说明:
/** * 定义字符串绘制或者图形绘制的方向 * @param dir 方向 * @param 关联方法 drawStr */ void U8G2::setFontDirection(uint8_t dir)
注意点:
Argument | String Rotation | Description |
---|---|---|
0 | 0 degree | Left to right |
1 | 90 degree | Top to down |
2 | 180 degree | Right to left |
3 | 270 degree | Down to top |
示例:
u8g2.setFont(u8g2_font_ncenB14_tf); u8g2.setFontDirection(0); u8g2.drawStr(15, 20, "Abc"); u8g2.setFontDirection(1); u8g2.drawStr(15, 20, "Abc");
缓存相关函数,通常不会去操做,了解便可;
函数说明
/** * 获取缓存空间的地址 * @return 返回缓存空间起始地址 * @Note 关联方法 getBufferTileHeight, getBufferTileWidth, clearBuffer */ uint8_t *U8G2::getBufferPtr(void)
注意点:
函数说明
/** * 获取缓冲区的Tile高度 * @return 返回高度值 */ uint8_t U8G2::getBufferTileHeight(void)
注意点:
函数说明
/** * 获取缓冲区的Tile宽度 * @return 返回宽度值 */ uint8_t U8G2::getBufferTileWidth(void)
注意点:
函数说明
/** * 获取缓冲区的当前Tile row行数 * @return 返回当前的tilerow */ uint8_t U8G2::getBufferCurrTileRow(void)
注意点:
函数说明
/** * 设置缓冲区的当前Tile row * @param 当前的tilerow */ void U8G2::setBufferCurrTileRow(uint8_t row)
注意点:
示例:
u8g2.setBufferCurrTileRow(0); // let y=0 be the topmost row of the buffer u8g2.clearBuffer(); u8g2.setFont(u8g2_font_helvB08_tr); u8g2.drawStr(2, 8, "abcdefg"); u8g2.setBufferCurrTileRow(2); // write the buffer to tile row 2 (y=16) on the display u8g2.sendBuffer(); u8g2.setBufferCurrTileRow(4); // write the same buffer to tile row 4 (y=32) on the display u8g2.sendBuffer();
利用好该方法,咱们能够实现部分更新;
前面博主介绍到U8G2适配了绝大部分的OLED,那么咱们如何构建具体的OLED驱动呢?可分为如下几个顺序步骤:
首先,你须要知道OLED显示器的控制器型号以及屏幕大小。举个例子,博主手上有一块SSD1306 128X64的OLED,那么它的控制器就是SSD1306,屏幕大小是128X64。
其次,你所选择的OLED必须在U8g2库所支持的OLED列表中,具体可参考 连接地址。
图像信息是经过物理总线方式发给OLED显示器。一般,咱们的总线包括:
具体的OLED使用什么物理总线,咱们须要查阅各自的数据手册。好比,博主的SSD1306就是IIC。
知道了物理连线模式以后,咱们通常都是把OLED链接到Arduino Board的输出引脚,也就是软件模拟具体总线协议。固然,若是有现成的物理总线端口那就更好了。
经历以上三步以后,咱们就能够开始初始化出具体的OLED驱动了。好比,博主的IIC SSD1306 128X64 的OLED,就能够用如下初始化构造器(Builder设计模式,有空能够去了解一下):
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display
固然SSD1306还有其余构造器(具体能够参考 wiki):
Controller "ssd1306", Display "128x64_noname" | Descirption |
---|---|
U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) | page buffer, size = 128 bytes |
U8G2_SSD1306_128X64_NONAME_2_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) | page buffer, size = 256 bytes |
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) | full framebuffer, size = 1024 bytes |
U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI(rotation, cs, dc [, reset]) | page buffer, size = 128 bytes |
那么,咱们这里就须要重点讲述一下构造器的规则。
构造器的名字包括如下几方面:
No | Description | Example |
---|---|---|
1 | Prefix | U8G2 |
2 | Display Controller | SSD1306 |
3 | Display Name | 128X64_NONAME |
4 | Buffer Size | 1, 2 or F (full frame buffer) |
5 | Communication | 4W_SW_SPI |
它们之间使用"_"链接起来。其中:
BufferSize | Description |
---|---|
1 | 保持一页的缓冲区,用于firstPage/nextPage的PageMode. |
2 | 保持两页的缓冲区,用于firstPage/nextPage的PageMode.. |
F | 获取整个屏幕的缓冲区,ram消耗大,通常用在ram空间比较大的arduino板子. |
Communication | Description |
---|---|
4W_SW_SPI | 4-wire (clock, data, cs and dc) software emulated SPI |
4W_HW_SPI | 4-wire (clock, data, cs and dc) hardware SPI (based on Arduino SPI library) |
2ND_4W_HW_SPI | If supported, second 4-wire hardware SPI (based on Arduino SPI library) |
3W_SW_SPI | 3-wire (clock, data and cs) software emulated SPI |
SW_I2C | Software emulated I2C/TWI |
HW_I2C | Hardware I2C based on the Arduino Wire library |
2ND_HW_I2C | If supported, use second hardware I2C (Arduino Wire lib) |
6800 | 8-bit parallel interface, 6800 protocol |
8080 | 8-bit parallel interface, 8080 protocol |
Rotation/Mirror | Description |
---|---|
U8G2_R0 | No rotation, landscape |
U8G2_R1 | 90 degree clockwise rotation |
U8G2_R2 | 180 degree clockwise rotation |
U8G2_R3 | 270 degree clockwise rotation |
U8G2_MIRROR | No rotation, landscape, display content is mirrored (v2.6.x) |
因此,一个完整的例子为:
#include <Arduino.h> #include <U8g2lib.h> #include <SPI.h> #include <Wire.h> U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8); void setup(void) { u8g2.begin(); } void loop(void) { u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.drawStr(0,24,"Hello World!"); } while ( u8g2.nextPage() ); }
那么,咱们来看看到底构造器里面作了什么操做?仍是以博主使用的SSD1306 128X64为例子:
/** * SSD1306 4线软件模拟SPI */ U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(.....)
类定义:
/** * SSD1306构造器,继承U8G2 */ class U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI : public U8G2 { public: U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(const u8g2_cb_t *rotation, uint8_t clock, uint8_t data, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE) : U8G2() { //配置SSD1306 u8g2_Setup_ssd1306_128x64_noname_1(&u8g2, rotation, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino); //设置通讯协议 u8x8_SetPin_4Wire_SW_SPI(getU8x8(), clock, data, cs, dc, reset); } };
从上面代码看出,默认调用了父类U8G2的构造函数,咱们看看它里面作了什么:
class U8G2 : public Print { protected: u8g2_t u8g2; u8x8_char_cb cpp_next_cb; /* the cpp interface has its own decoding function for the Arduino print command */ public: u8g2_uint_t tx, ty; U8G2(void) { //设置Arduino print函数的解码方法,这里是ASCII,固然也有UTF-8 cpp_next_cb = u8x8_ascii_next; //屏幕初始化 home(); } .......
而后咱们看看,u8g2_Setup_ssd1306_128x64_noname_1作了什么:
void u8g2_Setup_ssd1306_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb) { uint8_t tile_buf_height; //定义好缓存空间 记住 这里是 1 page mode uint8_t *buf; //配置屏幕 u8g2_SetupDisplay(u8g2, u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, byte_cb, gpio_and_delay_cb); //生成buf 这里是128 bytes buf = u8g2_m_16_8_1(&tile_buf_height); //初始化buf u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation); } /*============================================*/ /* This procedure is called after setting up the display (u8x8 structure). --> This is the central init procedure for u8g2 object */ void u8g2_SetupBuffer(u8g2_t *u8g2, uint8_t *buf, uint8_t tile_buf_height, u8g2_draw_ll_hvline_cb ll_hvline_cb, const u8g2_cb_t *u8g2_cb) { u8g2->font = NULL; //u8g2->kerning = NULL; //u8g2->get_kerning_cb = u8g2_GetNullKerning; //u8g2->ll_hvline = u8g2_ll_hvline_vertical_top_lsb; u8g2->ll_hvline = ll_hvline_cb; u8g2->tile_buf_ptr = buf; u8g2->tile_buf_height = tile_buf_height; u8g2->tile_curr_row = 0;//页码 这是一个很重要的参数 u8g2->font_decode.is_transparent = 0; /* issue 443 */ u8g2->bitmap_transparency = 0; u8g2->draw_color = 1; u8g2->is_auto_page_clear = 1;//自动清除 u8g2->cb = u8g2_cb; u8g2->cb->update_dimension(u8g2); #ifdef U8G2_WITH_CLIP_WINDOW_SUPPORT u8g2_SetMaxClipWindow(u8g2); /* assign a clip window and call the update() procedure */ #else u8g2->cb->update_page_win(u8g2); #endif u8g2_SetFontPosBaseline(u8g2); /* issue 195 */ #ifdef U8G2_WITH_FONT_ROTATION u8g2->font_decode.dir = 0; #endif }
能够总结几点:
注意点:
U8g2支持三种绘制模式:
特色:
构造器:
U8G2_ST7920_128X64_F_SW_SPI(rotation, clock, data, cs [, reset])
用法:
示例代码:
void setup(void) { u8g2.begin(); } void loop(void) { u8g2.clearBuffer(); u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.drawStr(0,20,"Hello World!"); u8g2.sendBuffer(); }
特色:
构造器:
U8G2_ST7920_128X64_ 1 _SW_SPI(rotation, clock, data, cs [, reset])
用法:
示例代码:
void setup(void) { u8g2.begin(); } void loop(void) { u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB14_tr); u8g2.drawStr(0,24,"Hello World!"); } while ( u8g2.nextPage() ); }
特色:
构造器:
U8X8_ST7565_EA_DOGM128_4W_SW_SPI(clock, data, cs, dc [, reset])
用法:
示例代码:
void setup(void) { u8x8.begin(); } void loop(void) { u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.drawString(0,1,"Hello World!"); }