LED驱动芯片:SSD1306
开发平台: vscode+platformIO
开发板:ESP32 Divkit v1
目前Arduino平台上使用最广泛的OLED库: U8G2
github地址: https://github.com/olikraus/u8g2/
设置和参考手册:https://github.com/olikraus/u8g2/wiki
U8g2:单色显示器库,版本2
U8g2是用于嵌入式设备的单色图形库。U8g2支持单色OLED和LCD,包括以下控制器:SSD1305,SSD1306,SSD1309,SSD1322,SSD1325,SSD1327,SSD1329,SSD1606,SSD1607,SH1106,SH1107,SH1108,SH1122,T6963,RA8835,LC7981,PCD8544,PCF8812,HX12 ,UC1601,UC1604,UC1608,UC1610,UC1611,UC1701,ST7565,ST7567,ST7588,ST75256,NT7534,IST3020,ST7920,LD7032,KS0108,SED1520,SBN1661,IL3820,MAX7219(完整列表请参见此处)。
为什么要运用U8g2库?
U8g2库平台支持性好,基本上支持绝大部分Arduino开发板;
U8g2库显示控制器支持性好,基本上市面上的OLED都完美支持;
U8g2库 API众多,特别支持了中文,支持了不同字体,这是一个对于开发者俩说不小的福利。
使用U8g2库进行OLED的显示十分简单,首先要包含两个库,U8g2lib和Wire,后者是IIC通信需要用。
对于IIC接口的OLED,需要在程序中指定一下引脚的接口定义,如果是SPI接口,可以参考U8g2库自带例程中SPI接口是使用方法。
在Ardunio的setup中进行u8g2的初始化。
#include <U8g2lib.h>
#include <Wire.h>
#define SCL 5
#define SDA 4
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);
void setup()
{
u8g2.begin();
}
初始化显示器, 清屏, 唤醒屏幕
/**
* 初始化U8g2库
* @Note 关联方法 initDisplay clearDisplay setPowerSave
*/
bool U8G2::begin(void)
只是初始化显示器, 并不清屏, 也不唤醒屏幕
/**
* 初始化显示控制器
*/
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 U8G2::clearBuffer(void)
/**
* 禁用Arduino平台下支持输出UTF8字符集,默认是开启
*/
void U8G2::disableUTF8Print(void)
/**
* 开启Arduino平台下支持输出UTF8字符集
*/
void U8G2::enableUTF8Print(void)
开启UTF-8后,我们可以使用其UTF-8字库
#include <Arduino.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/22, /* data=*/21); // ESP32 Thing, HW I2C with pin remapping
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
u8g2.firstPage();
do
{
u8g2.setCursor(0, 20);
u8g2.print("helloworld"); // Chinese "Hello World"
u8g2.setCursor(0, 40);
u8g2.print("你好世界"); // Chinese "Hello World"
} while (u8g2.nextPage());
delay(1000);
}
/**
* 重置显示光标的位置,回到原点(0,0)
* @Note 关联方法 print clear
*/
void U8G2::home(void)
在Ardunio的loop中编写自己想要的代码逻辑,温馨提醒,在U8g2库在loop中的通用写法是使用do{}while()的形式:
u8g2.firstPage();
do
{
//自己的的逻辑
} while (u8g2.nextPage());
delay(1000);
font:u8g2的字体,比较常用的有u8g2_font_unifont_t_symbols(通常使用这个)和u8g2_font_wqy12_t_gb2312b(用于显示汉字)等
num:启用(1)透明模式
num:禁用(0)透明模式
color:0(显示RAM中的清晰像素值)
color:1(设置像素值)
color:2(异或模式)
x、y:像素点的坐标
例如我们可以显示所有的点:
#include <U8g2lib.h>
#include <Wire.h>
#define SCL 5
#define SDA 4
//定义了一个宏定义,用于延时显示每一次的画图,方便观察OLED的显示过程:
#define SEND_BUFFER_DISPLAY_MS(ms)\
do {\
u8g2.sendBuffer(); \
delay(ms);\
}while(0);
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);
void setup()
{
u8g2.begin();
u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
}
//画像素点-填充屏幕
void testDrawPixelToFillScreen()
{
int t = 1000;
u8g2.clearBuffer();
for (int j = 0; j < 64; j++)
{
for (int i = 0; i < 128; i++)
{
u8g2.drawPixel(i, j);
}
}
SEND_BUFFER_DISPLAY_MS(t);
}
void loop()
{
testDrawPixelToFillScreen();
}
x0,y0线的起点
x1,y1线的终点
x,y线的起点
w水平线的长度(宽度)
x,y线的起点
h竖直线的长度(高度)
//画直线
void testDrawLine()
{
int t = 500;
u8g2.clearBuffer();
u8g2.drawStr(33, 14, "drawLine");
u8g2.drawLine(0, 0, 127, 63);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawLine(0, 0, 127, 0);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawLine(32, 15, 127, 15);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawLine(33, 16, 127, 16);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawLine(127, 0, 127, 15);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawLine(127, 16, 127, 63);
SEND_BUFFER_DISPLAY_MS(t);
}
x,y起点坐标
w,h框的宽度和高度
r圆角的半径
//画空心圆角矩形
void testDrawRFrame()
{
int t = 500;
int x = 16;
int y = 32;
int w = 50;
int h = 20;
int r = 3;
u8g2.clearBuffer();
u8g2.drawStr(0, 15, "drawRFrame");
u8g2.drawRFrame(x, y, w, h, r);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawRFrame(x+w+5, y-10, w-20, h+20, r);
SEND_BUFFER_DISPLAY_MS(t);
}
x,y为圆心坐标
rad为圆的半径
opt为选择画的部分,分为:
U8G2_DRAW_UPPER_RIGHT(右上)
U8G2_DRAW_UPPER_LEFT(左上)
U8G2_DRAW_LOWER_LEFT(左下)
U8G2_DRAW_LOWER_RIGHT(右下)
U8G2_DRAW_ALL(全部)
空心圆:
//画空心圆
void testDrawCircle()
{
int t = 500;
int stx = 0; //画图起始x
int sty = 16; //画图起始y
int with = 16;//一个图块的间隔
int r = 15; //圆的半径
u8g2.clearBuffer();
u8g2.drawStr(0, 15, "drawCircle");
u8g2.drawCircle(stx, sty - 1 + with, r, U8G2_DRAW_UPPER_RIGHT); //右上
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawCircle(stx + with, sty, r, U8G2_DRAW_LOWER_RIGHT); //右下
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawCircle(stx - 1 + with * 3, sty - 1 + with, r, U8G2_DRAW_UPPER_LEFT); //左上
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawCircle(stx - 1 + with * 4, sty, r, U8G2_DRAW_LOWER_LEFT); //左下
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawCircle(stx - 1 + with * 2, sty - 1 + with * 2, r, U8G2_DRAW_ALL);//整个圆
SEND_BUFFER_DISPLAY_MS(t);
}
注意,U8g2库画出的圆,因像素点的显示原理,圆的直径占用的宽度不是半径的2倍,而是2倍再加一个像素点。
x,y为圆心坐标
rx,ry为与椭圆x和y方向的半径
opt与画圆时的作用一致
椭圆的显示与圆的显示类似,只是椭圆可以分别指定x和y方向的半径
字符串的显示,可以使用drawStr函数,也可以使用通用风格的print函数。
x,y起点坐标
string字符串
需要先设置字体,调用setFont方法;
这个方法不能绘制encoding超过256的,超过256需要用drawUTF8或者drawGlyph;说白了就是一般用来显示英文字符;
如果想要使用print显示汉子,需要先设置如下两句:
u8g2.enableUTF8Print();//enable UTF8
u8g2.setFont(u8g2_font_wqy12_t_gb2312b);//设置中文字符集
如果想要显示变量,使用print函数即可。
//字符串/文字/变量显示测试
void testDrawStr()
{
int t = 1000;
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy12_t_gb2312b);//设置中文字符集
u8g2.drawStr(0, 14, "drawStr / print");
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawStr(0, 32, "~!@#$%^&*()_+");
SEND_BUFFER_DISPLAY_MS(t);
u8g2.enableUTF8Print();//enable UTF8
u8g2.setFont(u8g2_font_wqy12_t_gb2312b);//设置中文字符集
u8g2.setCursor(0, 48);
u8g2.print("码农爱学习");
SEND_BUFFER_DISPLAY_MS(t);
int a = 234;
u8g2.setCursor(0, 64);
u8g2.print("int a = ");
u8g2.setCursor(40, 64);
u8g2.print(a);//显示变量
SEND_BUFFER_DISPLAY_MS(t);
}
x,y起点坐标
addr内置图标的地址
U8g2库内置了需要预先定义的图形,通过drawGlyp函数以及指定的地址,即可看OLED上显示对应的图标:
各个图形的地址定义如下:
void testGlyph()
{
int t = 1000;
u8g2.clearBuffer();
u8g2.drawStr(0, 14, "drawGlyph");
u8g2.drawGlyph(0, 32, 0x23f0);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawGlyph(16, 32, 0x23f3);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawGlyph(32, 32, 0x2603);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawGlyph(48, 32, 0x2615);
SEND_BUFFER_DISPLAY_MS(t);
u8g2.drawGlyph(64, 32, 0x2618);
SEND_BUFFER_DISPLAY_MS(t);
}
x,y起点坐标
w,h图片的宽度和高度`
addr图片(数组)的地址
// width: 128, height: 48
const unsigned char bilibili[] U8X8_PROGMEM = { 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, ... 省略若干行 };
void testDrawXBM()
{
int t = 1000;
u8g2.clearBuffer();
u8g2.drawStr(0, 14, "drawXBM");
u8g2.drawXBM(0, 16, 128, 48, bilibili);
SEND_BUFFER_DISPLAY_MS(t);
}
/**
* 获取基准线以上的高度
* @return 返回高度值
* @Note 关联方法 setFont getDescent setFontRefHeightAll
*/
int8_t U8G2::getAscent(void)
跟字体有关(setFont)
示例:下面例子,ascent是18
/**
* 获取基准线以下的高度
* @return 返回高度值
* @Note 关联方法 setFont setFontRefHeightAll
*/
int8_t U8G2::getDescent(void)
跟字体有关(setFont);
示例:下面例子,descent是-5
/**
* 获取显示器的宽度
* @return 返回宽度值
*/
u8g2_uint_t getDisplayWidth(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)
建议该方法保持默认就好,如果用户禁止了,那么需要自己维护缓冲区的状态或者手动调用clearBuffer;
/**
* 设置位图模式(定义drawXBM方法是否绘制背景颜色)
* @param is_transparent
* 0 绘制背景颜色,不透明,默认是该值
* 1 不绘制背景颜色,透明
* @Note 关联方法 drawXBM
*/
void U8G2::setBitmapMode(uint8_t is_transparent)
/**
* 设置总线时钟(I2C SPI)
* @param mode clock_speed 总线时钟频率(Hz)
* @Note 关联方法 begin
*/
void U8G2::setBusClock(uint32_t clock_speed);
仅仅Arduino平台支持;
必须在u8g2.begin() 或者 u8g2.initDisplay()之前调用;
/**
* 设置采集窗口,窗口范围从左上角(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 );
可以通过 setMaxClipWindow 去掉该限制
/**
* 设置绘制光标位置(x,y)
* @Note 关联方法 print
*/
void U8G2::setCursor(u8g2_uint_t x, u8g2_uint_t y)
/**
* 设置显示器的旋转角度
* @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)
启用(1)或禁用(0)透明模式
/**
* 定义字符串绘制或者图形绘制的方向
* @param dir 方向
* @param 关联方法 drawStr
*/
void U8G2::setFontDirection(uint8_t dir)
/**
* 获取缓存空间的地址
* @return 返回缓存空间起始地址
* @Note 关联方法 getBufferTileHeight, getBufferTileWidth, clearBuffer
*/
uint8_t *U8G2::getBufferPtr(void)
/**
* 获取缓冲区的Tile高度
* @return 返回高度值
*/
uint8_t U8G2::getBufferTileHeight(void)
一个tile等于8个像素点.
/**
* 获取缓冲区的Tile宽度
* @return 返回宽度值
*/
uint8_t U8G2::getBufferTileWidth(void)
/**
* 获取缓冲区的当前Tile row行数
* @return 返回当前的tilerow
*/
uint8_t U8G2::getBufferCurrTileRow(void)
5. u8g2.setBufferCurrTileRow() —— 设置缓冲区的当前Tile row
/**
* 设置缓冲区的当前Tile row
* @param 当前的tilerow
*/
void U8G2::setBufferCurrTileRow(uint8_t row)
在 firstPage/nextPage 循环时,由于底层调用了setBufferCurrTileRow,所以尽量不要自己手动调用该方法
U8g2支持三种绘制模式:
Full screen buffer mode,全屏缓存模式
Page mode (This is the U8glib picture loop) 分页模式
U8x8, character only mode 仅仅支持普通字符
特点:
绘制速度快
所有的绘制方法都可以使用
需要大量的ram空间
用法:
清除缓冲区 u8g2.clearBuffer()
操作一些绘制方法
发送缓冲区的内容到显示器 u8g2.sendBuffer().
特点:
绘制速度慢
所有的绘制方法都可以使用
需要少量的ram空间
特点:
绘制速度快
并不是对所有的显示器都有效
图形绘制不可用
不需要ram空间
使用U8X8构造器,比如:
U8X8_ST7565_EA_DOGM128_4W_SW_SPI(clock, data, cs, dc [, reset])
1、包含头文件
#include <U8g2lib.h>
2、U8g2对象初始化
看例程里有无数条代表着各种屏幕的写好的U8g2初始化语句,选择适合的一条解除注释即可
我的ESP32 DEVKIT V1+SSD1306(IIC)是选择这个:
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/22, /* data=*/21); // ESP32 Thing, HW I2C with pin remapping
3、初始化屏幕
u8g2.begin();
五、关于字库
<prefix> '_' <name> '_' <purpose> <char set>
prefix基本上都是 u8g2;
name 字体名称
purpose 用法
字符 | 描述 |
t | 透明字体,不要使用背景色 |
h | 所有的图形有通用的高度 |
m | 所有字形都有共同的高度和宽度(等宽) |
8 | 所有图示符都可以放入8x8像素的方框中 |
char set 字符设置
字符 | 描述 |
f | 最多包含256个字体 |
r | 字体中只包含ASCII代码32到127范围内的字形. |
u | 字体中只包含ASCII代码32到95(大写字符)范围内的字形. |
n | 字体中只包含数字和用于写入日期和时间字符串的额外字形 |
… | 其他自定义字符列表. |
https://github.com/olikraus/u8g2/wiki/fntlistall
https://github.com/olikraus/u8g2/wiki/fntgrpiconic
作者:熊爸天下_56c7
链接:https://www.jianshu.com/p/35e185051aa7
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/22, /* data=*/21); // ESP32 Thing, HW I2C with pin remapping
void setup(void)
{
u8g2.begin();
u8g2.setFont(u8g2_font_10x20_tf);
u8g2.setFontRefHeightExtendedText();
u8g2.setDrawColor(1);
u8g2.setFontPosTop();
u8g2.setFontDirection(0);
}
void loop(void)
{
for (int i = -31; i < 128; i++)
{
u8g2.clearBuffer();
u8g2.drawStr(0, 0, "Fashional Car");
u8g2.drawBox(0 + i, 54 - i % 2, 31, 6);
u8g2.drawBox(7 + i, 48 - i % 2, 17, 6);
u8g2.drawDisc(7 + i, 59, 4);
u8g2.drawDisc(22 + i, 59, 4);
switch (i % 6)
{
case 0:
u8g2.drawDisc(-6 + i, 59, 1);
break;
case 1:
u8g2.drawDisc(-12 + i, 58, 2);
break;
case 2:
u8g2.drawDisc(-16 + i, 57, 3);
break;
default:
break;
}
Serial.println(i);
delay(50);
u8g2.sendBuffer();
}
}
显示XBM图片
我使用了在线转换器:
https://convertio.co/zh/image-converter/?utm_source=chrome_extension
整个转换过程很简单, 转换好的XBM文件用记事本打开就能看到数组了, 感觉比传统的 Img2Lcd 或者 PCtoLCD2002 好用
#include <Arduino.h>
#include "U8g2lib.h"
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/22, /* data=*/21); // ESP32 Thing, HW I2C with pin remapping
static const unsigned char al_logo[] U8X8_PROGMEM = {
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, 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x0A, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0xC0, 0x08, 0x80, 0x01, 0x07, 0x00, 0x70, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x80, 0x1D, 0xC0, 0x03, 0x0F, 0x00, 0xF8, 0x00,
0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0xC0, 0x03,
0xEF, 0x00, 0xF8, 0x01, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x30, 0x18, 0xC0, 0x03, 0xE7, 0x01, 0xFC, 0x01, 0x00, 0x1F, 0x00, 0x00,
0x00, 0x07, 0x00, 0x00, 0x88, 0x57, 0xE0, 0x03, 0xEF, 0x03, 0xFE, 0x01,
0x00, 0x1F, 0x0F, 0x00, 0x80, 0x07, 0x00, 0x00, 0xCC, 0x7E, 0xE0, 0x01,
0xC7, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x80, 0x07, 0x00, 0x00,
0x02, 0x00, 0xE0, 0x0F, 0x87, 0x83, 0xFF, 0x07, 0x00, 0xFF, 0x0F, 0x00,
0xC0, 0x07, 0x00, 0x00, 0x00, 0x06, 0xF0, 0x1F, 0x37, 0xC1, 0xFF, 0x0F,
0x80, 0x7F, 0x01, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x04, 0xF0, 0x1F,
0xFF, 0xC0, 0xBF, 0x0F, 0x80, 0xBF, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00,
0x00, 0x16, 0xF8, 0x1C, 0xFF, 0xC0, 0x17, 0x0F, 0x80, 0x0F, 0x00, 0x00,
0xF0, 0x03, 0x00, 0x00, 0x00, 0x1D, 0x78, 0x9C, 0x1F, 0xC0, 0xFD, 0x0F,
0x80, 0x47, 0x07, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x05, 0x30, 0xFF,
0x07, 0xE0, 0xFF, 0x0F, 0x80, 0xFF, 0x3F, 0x00, 0xF8, 0x01, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xFF, 0x07, 0xE0, 0xBF, 0x0F, 0x80, 0xFF, 0x7E, 0x00,
0xFC, 0x00, 0x00, 0x00, 0x80, 0x64, 0xE0, 0x3D, 0x33, 0xE0, 0x9F, 0x07,
0xE0, 0x0F, 0x78, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x80, 0x05, 0x60, 0x9C,
0x33, 0xE0, 0x8B, 0x0F, 0xF0, 0x03, 0xF0, 0x00, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x9F, 0x63, 0xE0, 0x8D, 0x0F, 0x7C, 0x00, 0xF0, 0x00,
0xFF, 0x03, 0x00, 0x00, 0x00, 0x30, 0xE0, 0x9D, 0xE9, 0xE0, 0xBC, 0x07,
0x3F, 0xF0, 0xF8, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x80, 0x01, 0xE0, 0xDE,
0xF1, 0xE0, 0xBE, 0x0F, 0x1E, 0xFC, 0xF9, 0x80, 0xDF, 0x0F, 0x00, 0x00,
0x80, 0x02, 0x80, 0xDF, 0xF0, 0xE1, 0xBF, 0x07, 0x04, 0xFF, 0x79, 0xC0,
0x9F, 0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x7F, 0xE0, 0xE0, 0x9F, 0x07,
0xC0, 0xBF, 0x7D, 0xC0, 0x0F, 0x7E, 0x00, 0x00, 0xC0, 0x0C, 0x08, 0x2E,
0x00, 0xE0, 0x8C, 0x0F, 0xF0, 0x0F, 0x7C, 0xE0, 0x07, 0xFC, 0x01, 0x00,
0xC0, 0x0C, 0x1E, 0x00, 0xC0, 0xE1, 0xCC, 0x07, 0xFE, 0x0B, 0x3E, 0xF0,
0x03, 0xF8, 0x07, 0x00, 0x80, 0x28, 0x3C, 0x00, 0xE2, 0xE3, 0xD2, 0x07,
0xFE, 0x38, 0x3E, 0xF0, 0x03, 0xE0, 0x1F, 0x00, 0xA0, 0x2D, 0x3C, 0xFF,
0xDF, 0xE7, 0xF8, 0x07, 0x00, 0xF0, 0x3F, 0xF8, 0x01, 0xC0, 0xFF, 0x02,
0xA0, 0x01, 0xF8, 0x71, 0x8E, 0xE7, 0xFE, 0x07, 0x00, 0xF0, 0x1F, 0xFC,
0x00, 0x80, 0xFF, 0x1F, 0x00, 0x0C, 0xF0, 0x60, 0x80, 0xE7, 0xFF, 0x07,
0x00, 0xE0, 0x0F, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00,
0xC0, 0xE3, 0xC3, 0x07, 0x00, 0xE0, 0x0F, 0x7F, 0x00, 0x00, 0xFE, 0xFF,
0x00, 0x08, 0x00, 0x00, 0x20, 0xE0, 0xC1, 0x03, 0x00, 0xC0, 0x03, 0x0C,
0x00, 0x00, 0xF0, 0x1F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x80, 0x03,
0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 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, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 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, 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,
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,};
void setup()
{
Serial.begin(115200);
u8g2.begin();
}
void loop()
{
u8g2.firstPage();
do
{
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawXBMP(0, 0, 128, 64, al_logo);
} while (u8g2.nextPage());
}
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
我使用的是最新版本的Chrome(32.0.1700.107)和Chrome驱动程序(V2.8)。但是当我在Ruby中使用以下代码运行示例测试时:require'selenium-webdriver'WAIT=Selenium::WebDriver::Wait.new(timeout:100)$driver=Selenium::WebDriver.for:chrome$driver.manage.window.maximize$driver.navigate.to'https://www.google.co.in'defapps_hoverele_hover=$driver.find_
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易
如果我在功能规范中调用url_for,它会返回一个以http://www.example.com/开头的绝对URL.Capybara会很乐意尝试加载该站点上的页面,但这与我的应用程序无关。以下是重现该问题的最少步骤:从这个Gemfile开始:source'https://rubygems.org'gem"sqlite3"gem"jquery-rails"gem"draper"gem"rails",'4.1.0'gem"therubyracer"gem"uglifier"gem"rspec-rails"gem"capybara"gem"poltergeist"gem"launchy"运行
在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的进程隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。MiProcessLoaderEntry(pDriverObject->DriverSection,1)添加MiProcessLoaderEntry(pDriverObject->DriverSection,
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N