差分
このページの2つのバージョン間の差分を表示します。
次のリビジョン | 前のリビジョン | ||
gimmickkouza:electronic_basic:6:3_oled_i2c [2024/06/01 21:26] – 作成 lutamesta | gimmickkouza:electronic_basic:6:3_oled_i2c [2024/06/20 22:47] (現在) – ★動画追加 lutamesta | ||
---|---|---|---|
行 1: | 行 1: | ||
- | ====== 6-3 OLEDディスプレイを使ってみる(I2C) ====== | + | ====== 6-3 OLEDディスプレイ(I2C) ====== |
===== ディスプレイについての基礎知識 ===== | ===== ディスプレイについての基礎知識 ===== | ||
==== ディスプレイの違い ==== | ==== ディスプレイの違い ==== | ||
- | ディスプレイと一口に言っても、その仕組みや表示できるものの違い等、非常に幅が広いです。 | + | ディスプレイと一口に言っても、その仕組みや表示できるものの違い等、非常に幅が広いです。 |
=== ディスプレイの種類 === | === ディスプレイの種類 === | ||
- | 電子工作用途で使われるディスプレイでは「LCD」と「OLED」が一般的です。 | + | 電子工作用途で使われるディスプレイでは「LCD」と「OLED」が一般的です。 |
あと最近では「電子ペーパー」なんてのもありますが、講師非所持のため説明は割愛します。 | あと最近では「電子ペーパー」なんてのもありますが、講師非所持のため説明は割愛します。 | ||
行 29: | 行 29: | ||
文字や数字をのみを表示できるLCDキャラクタディスプレイ。 | 文字や数字をのみを表示できるLCDキャラクタディスプレイ。 | ||
工作物に組み込み、情報表示用途に使われます。 | 工作物に組み込み、情報表示用途に使われます。 | ||
+ | <panel type=" | ||
+ | characterが文字集合の意味なんですよね。</ | ||
== グラフィック == | == グラフィック == | ||
行 53: | 行 55: | ||
===== 6-3-1_OLED_I2C ===== | ===== 6-3-1_OLED_I2C ===== | ||
+ | {{youtube> | ||
+ | |||
+ | (この動画は6-3-2と6-3-1を繋げています。0: | ||
+ | |||
==== I2Cの仕組み ==== | ==== I2Cの仕組み ==== | ||
UARTに続く二つめのシリアル通信、I2Cの登場です! | UARTに続く二つめのシリアル通信、I2Cの登場です! | ||
行 59: | 行 65: | ||
「I2C」はInter-Integrated Circuitの略で、「アイ・スクエアド・シー」と呼びます。 | 「I2C」はInter-Integrated Circuitの略で、「アイ・スクエアド・シー」と呼びます。 | ||
「アイ・アイ・シー」「アイ・ツー・シー」とも呼ばれます。アイスクエアドシーの方がかっこいいのに… | 「アイ・アイ・シー」「アイ・ツー・シー」とも呼ばれます。アイスクエアドシーの方がかっこいいのに… | ||
- | 信号線が2本だけという点はUARTと同じですが、I2CはUARTにはない特徴がたくさんあります。 | + | |
+ | __**I2Cの最大の特徴は、2本1組の信号線で複数のI2C機器を操れる**__という点です。 | ||
+ | (信号線が2本1組という点ではUARTと同じですが、UARTは1組の信号線で操れる機器は1つだけでしたね!) | ||
I2Cの特徴は以下の4つです。 | I2Cの特徴は以下の4つです。 | ||
行 68: | 行 76: | ||
順番にひとつずつ解説します。 | 順番にひとつずつ解説します。 | ||
+ | /*<alert type=" | ||
+ | もちろん下記でも書いてあるんですが、その特徴があってこそのこの仕組みなので・・ | ||
+ | </ | ||
== 信号線「SCL」と「SDA」 == | == 信号線「SCL」と「SDA」 == | ||
行 88: | 行 99: | ||
例えば本項での「コントローラ」はArduinoです。そこにOLEDディスプレイを「ターゲット」として繋ぎます。 | 例えば本項での「コントローラ」はArduinoです。そこにOLEDディスプレイを「ターゲット」として繋ぎます。 | ||
**「ターゲット」として複数のディスプレイや他のI2C機器を繋ぐことも可能です。** | **「ターゲット」として複数のディスプレイや他のI2C機器を繋ぐことも可能です。** | ||
+ | <panel type=" | ||
+ | そういったマイコンであれば、I2C機器を繋ぎすぎたりする場合などに、複数のI2Cコントローラを用意して分割して繋ぐ手も使えます。</ | ||
+ | |||
== クロック信号で同期を取る == | == クロック信号で同期を取る == | ||
I2Cでの通信の仕組みを超ざっくり説明します。 | I2Cでの通信の仕組みを超ざっくり説明します。 | ||
行 104: | 行 118: | ||
こういった部品を扱う際には、自分でI2Cアドレスを調べる必要があります。 | こういった部品を扱う際には、自分でI2Cアドレスを調べる必要があります。 | ||
いつかそんなシーンに遭遇した時のために、I2Cアドレスの調べ方を掲載しておきます。 | いつかそんなシーンに遭遇した時のために、I2Cアドレスの調べ方を掲載しておきます。 | ||
- | + | ||
- | ---- | + | ===i2c_scannerでI2Cアドレスを調べる=== |
I2Cアドレスを確認するには、i2c_scannerというスケッチを使用します。 | I2Cアドレスを確認するには、i2c_scannerというスケッチを使用します。 | ||
行 136: | 行 150: | ||
下記の検索ワードを打ち込み、2つのライブラリをインストールしてください。 | 下記の検索ワードを打ち込み、2つのライブラリをインストールしてください。 | ||
- | * " | + | * " |
* " | * " | ||
ちなみに~GFXはディスプレイ用のグラフィックスライブラリ、~SSD1306はSSD1306ドライバを搭載した電子部品を使用するためのライブラリです。 | ちなみに~GFXはディスプレイ用のグラフィックスライブラリ、~SSD1306はSSD1306ドライバを搭載した電子部品を使用するためのライブラリです。 | ||
+ | |||
+ | /*<alert type=" | ||
==== 配線図 ==== | ==== 配線図 ==== | ||
行 151: | 行 167: | ||
また他のサイトや店舗で販売している似たようなディスプレイは、個別に確認が必要です。 | また他のサイトや店舗で販売している似たようなディスプレイは、個別に確認が必要です。 | ||
ネット情報ではプルアップ抵抗のない商品も存在するようです) | ネット情報ではプルアップ抵抗のない商品も存在するようです) | ||
+ | |||
+ | ===使う部品リスト=== | ||
+ | ^ 部品 | ||
+ | | OLEDディスプレイ | 1個 | | ||
==== サンプルコード解説 ==== | ==== サンプルコード解説 ==== | ||
サンプルコード6-3-1_OLED_I2C.inoを開いてください。 | サンプルコード6-3-1_OLED_I2C.inoを開いてください。 | ||
+ | /*<alert type=" | ||
+ | 下のコードをコピペすると「}」が足りないです | ||
+ | {{: | ||
+ | </ | ||
< | < | ||
行 183: | 行 207: | ||
display.display();// | display.display();// | ||
delay(1000); | delay(1000); | ||
+ | } | ||
</ | </ | ||
行 294: | 行 319: | ||
全く同じコードを、サンプルコード「6-3-2_OLED_I2C_from_sample.ino」として収録してありますので、興味のある方はぜひ実行してみてください。 | 全く同じコードを、サンプルコード「6-3-2_OLED_I2C_from_sample.ino」として収録してありますので、興味のある方はぜひ実行してみてください。 | ||
+ | |||
==== 配線図 ==== | ==== 配線図 ==== | ||
{{: | {{: | ||
直前の6-3-1で作った回路そのままでOKです! | 直前の6-3-1で作った回路そのままでOKです! | ||
+ | |||
+ | ===使う部品リスト=== | ||
+ | ^ 部品 | ||
+ | | OLEDディスプレイ | 1個 | | ||
==== サンプルコード解説(しないよ!) ==== | ==== サンプルコード解説(しないよ!) ==== | ||
サンプルコード6-3-2_OLED_I2C_from_sample.inoを開いてください。 | サンプルコード6-3-2_OLED_I2C_from_sample.inoを開いてください。 | ||
+ | |||
+ | < | ||
+ | / | ||
+ | This is an example for our Monochrome OLEDs based on SSD1306 drivers | ||
+ | |||
+ | Pick one up today in the adafruit shop! | ||
+ | | ||
+ | |||
+ | This example is for a 128x64 pixel display using I2C to communicate | ||
+ | 3 pins are required to interface (two I2C and one reset). | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | with contributions from the open source community. | ||
+ | BSD license, check license.txt for more information | ||
+ | All text above, and the splash screen below must be | ||
+ | | ||
+ | | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #define SCREEN_WIDTH 128 // OLED display width, in pixels | ||
+ | #define SCREEN_HEIGHT 64 // OLED display height, in pixels | ||
+ | |||
+ | // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) | ||
+ | // The pins for I2C are defined by the Wire-library. | ||
+ | // On an arduino UNO: | ||
+ | // On an arduino MEGA 2560: 20(SDA), 21(SCL) | ||
+ | // On an arduino LEONARDO: | ||
+ | #define OLED_RESET | ||
+ | |||
+ | // | ||
+ | #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 | ||
+ | |||
+ | |||
+ | Adafruit_SSD1306 display(SCREEN_WIDTH, | ||
+ | |||
+ | #define NUMFLAKES | ||
+ | |||
+ | #define LOGO_HEIGHT | ||
+ | #define LOGO_WIDTH | ||
+ | static const unsigned char PROGMEM logo_bmp[] = | ||
+ | { 0b00000000, 0b11000000, | ||
+ | 0b00000001, 0b11000000, | ||
+ | 0b00000001, 0b11000000, | ||
+ | 0b00000011, 0b11100000, | ||
+ | 0b11110011, 0b11100000, | ||
+ | 0b11111110, 0b11111000, | ||
+ | 0b01111110, 0b11111111, | ||
+ | 0b00110011, 0b10011111, | ||
+ | 0b00011111, 0b11111100, | ||
+ | 0b00001101, 0b01110000, | ||
+ | 0b00011011, 0b10100000, | ||
+ | 0b00111111, 0b11100000, | ||
+ | 0b00111111, 0b11110000, | ||
+ | 0b01111100, 0b11110000, | ||
+ | 0b01110000, 0b01110000, | ||
+ | 0b00000000, 0b00110000 }; | ||
+ | |||
+ | void setup() { | ||
+ | Serial.begin(9600); | ||
+ | |||
+ | // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally | ||
+ | if(!display.begin(SSD1306_SWITCHCAPVCC, | ||
+ | Serial.println(F(" | ||
+ | for(;;); // Don't proceed, loop forever | ||
+ | } | ||
+ | |||
+ | // Show initial display buffer contents on the screen -- | ||
+ | // the library initializes this with an Adafruit splash screen. | ||
+ | display.display(); | ||
+ | delay(2000); | ||
+ | |||
+ | // Clear the buffer | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | // Draw a single pixel in white | ||
+ | display.drawPixel(10, | ||
+ | |||
+ | // Show the display buffer on the screen. You MUST call display() after | ||
+ | // drawing commands to make them visible on screen! | ||
+ | display.display(); | ||
+ | delay(2000); | ||
+ | // display.display() is NOT necessary after every single drawing command, | ||
+ | // unless that's what you want...rather, | ||
+ | // drawing operations and then update the screen all at once by calling | ||
+ | // display.display(). These examples demonstrate both approaches... | ||
+ | |||
+ | testdrawline(); | ||
+ | |||
+ | testdrawrect(); | ||
+ | |||
+ | testfillrect(); | ||
+ | |||
+ | testdrawcircle(); | ||
+ | |||
+ | testfillcircle(); | ||
+ | |||
+ | testdrawroundrect(); | ||
+ | |||
+ | testfillroundrect(); | ||
+ | |||
+ | testdrawtriangle(); | ||
+ | |||
+ | testfilltriangle(); | ||
+ | |||
+ | testdrawchar(); | ||
+ | |||
+ | testdrawstyles(); | ||
+ | |||
+ | testscrolltext(); | ||
+ | |||
+ | testdrawbitmap(); | ||
+ | |||
+ | // Invert and restore display, pausing in-between | ||
+ | display.invertDisplay(true); | ||
+ | delay(1000); | ||
+ | display.invertDisplay(false); | ||
+ | delay(1000); | ||
+ | |||
+ | testanimate(logo_bmp, | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | } | ||
+ | |||
+ | void testdrawline() { | ||
+ | int16_t i; | ||
+ | |||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(i=0; i< | ||
+ | display.drawLine(0, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | for(i=0; i< | ||
+ | display.drawLine(0, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | delay(250); | ||
+ | |||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(i=0; i< | ||
+ | display.drawLine(0, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | for(i=display.height()-1; | ||
+ | display.drawLine(0, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | delay(250); | ||
+ | |||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(i=display.width()-1; | ||
+ | display.drawLine(display.width()-1, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | for(i=display.height()-1; | ||
+ | display.drawLine(display.width()-1, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | delay(250); | ||
+ | |||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(i=0; i< | ||
+ | display.drawLine(display.width()-1, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | for(i=0; i< | ||
+ | display.drawLine(display.width()-1, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testdrawrect(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=0; i< | ||
+ | display.drawRect(i, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testfillrect(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=0; i< | ||
+ | // The INVERSE color is used so rectangles alternate white/black | ||
+ | display.fillRect(i, | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testdrawcircle(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=0; i< | ||
+ | display.drawCircle(display.width()/ | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testfillcircle(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=max(display.width(), | ||
+ | // The INVERSE color is used so circles alternate white/black | ||
+ | display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE); | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testdrawroundrect(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=0; i< | ||
+ | display.drawRoundRect(i, | ||
+ | display.height()/ | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testfillroundrect(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=0; i< | ||
+ | // The INVERSE color is used so round-rects alternate white/black | ||
+ | display.fillRoundRect(i, | ||
+ | display.height()/ | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testdrawtriangle(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=0; i< | ||
+ | display.drawTriangle( | ||
+ | display.width()/ | ||
+ | display.width()/ | ||
+ | display.width()/ | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testfilltriangle(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | for(int16_t i=max(display.width(), | ||
+ | // The INVERSE color is used so triangles alternate white/black | ||
+ | display.fillTriangle( | ||
+ | display.width()/ | ||
+ | display.width()/ | ||
+ | display.width()/ | ||
+ | display.display(); | ||
+ | delay(1); | ||
+ | } | ||
+ | |||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testdrawchar(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | display.setTextSize(1); | ||
+ | display.setTextColor(SSD1306_WHITE); | ||
+ | display.setCursor(0, | ||
+ | display.cp437(true); | ||
+ | |||
+ | // Not all the characters will fit on the display. This is normal. | ||
+ | // Library will draw what it can and the rest will be clipped. | ||
+ | for(int16_t i=0; i<256; i++) { | ||
+ | if(i == ' | ||
+ | else display.write(i); | ||
+ | } | ||
+ | |||
+ | display.display(); | ||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testdrawstyles(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | display.setTextSize(1); | ||
+ | display.setTextColor(SSD1306_WHITE); | ||
+ | display.setCursor(0, | ||
+ | display.println(F(" | ||
+ | |||
+ | display.setTextColor(SSD1306_BLACK, | ||
+ | display.println(3.141592); | ||
+ | |||
+ | display.setTextSize(2); | ||
+ | display.setTextColor(SSD1306_WHITE); | ||
+ | display.print(F(" | ||
+ | |||
+ | display.display(); | ||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void testscrolltext(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | display.setTextSize(2); | ||
+ | display.setTextColor(SSD1306_WHITE); | ||
+ | display.setCursor(10, | ||
+ | display.println(F(" | ||
+ | display.display(); | ||
+ | delay(100); | ||
+ | |||
+ | // Scroll in various directions, pausing in-between: | ||
+ | display.startscrollright(0x00, | ||
+ | delay(2000); | ||
+ | display.stopscroll(); | ||
+ | delay(1000); | ||
+ | display.startscrollleft(0x00, | ||
+ | delay(2000); | ||
+ | display.stopscroll(); | ||
+ | delay(1000); | ||
+ | display.startscrolldiagright(0x00, | ||
+ | delay(2000); | ||
+ | display.startscrolldiagleft(0x00, | ||
+ | delay(2000); | ||
+ | display.stopscroll(); | ||
+ | delay(1000); | ||
+ | } | ||
+ | |||
+ | void testdrawbitmap(void) { | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | display.drawBitmap( | ||
+ | (display.width() | ||
+ | (display.height() - LOGO_HEIGHT) / 2, | ||
+ | logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, | ||
+ | display.display(); | ||
+ | delay(1000); | ||
+ | } | ||
+ | |||
+ | #define XPOS 0 // Indexes into the ' | ||
+ | #define YPOS 1 | ||
+ | #define DELTAY 2 | ||
+ | |||
+ | void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) { | ||
+ | int8_t f, icons[NUMFLAKES][3]; | ||
+ | |||
+ | // Initialize ' | ||
+ | for(f=0; f< NUMFLAKES; f++) { | ||
+ | icons[f][XPOS] | ||
+ | icons[f][YPOS] | ||
+ | icons[f][DELTAY] = random(1, 6); | ||
+ | Serial.print(F(" | ||
+ | Serial.print(icons[f][XPOS], | ||
+ | Serial.print(F(" | ||
+ | Serial.print(icons[f][YPOS], | ||
+ | Serial.print(F(" | ||
+ | Serial.println(icons[f][DELTAY], | ||
+ | } | ||
+ | |||
+ | for(;;) { // Loop forever... | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | // Draw each snowflake: | ||
+ | for(f=0; f< NUMFLAKES; f++) { | ||
+ | display.drawBitmap(icons[f][XPOS], | ||
+ | } | ||
+ | |||
+ | display.display(); | ||
+ | delay(200); | ||
+ | |||
+ | // Then update coordinates of each flake... | ||
+ | for(f=0; f< NUMFLAKES; f++) { | ||
+ | icons[f][YPOS] += icons[f][DELTAY]; | ||
+ | // If snowflake is off the bottom of the screen... | ||
+ | if (icons[f][YPOS] >= display.height()) { | ||
+ | // Reinitialize to a random position, just off the top | ||
+ | icons[f][XPOS] | ||
+ | icons[f][YPOS] | ||
+ | icons[f][DELTAY] = random(1, 6); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
37行目のI2CアドレスをみなさんのディスプレイのI2Cアドレスに書き換えてArduinoに書き込んでください。 | 37行目のI2CアドレスをみなさんのディスプレイのI2Cアドレスに書き換えてArduinoに書き込んでください。 | ||
※今回のコードはライブラリ付属のサンプルスケッチそのまんまですので、解説は致しません! | ※今回のコードはライブラリ付属のサンプルスケッチそのまんまですので、解説は致しません! | ||
+ | |||
{{: | {{: | ||
+ | |||
+ | /*<alert type=" | ||
+ |