差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン 前のリビジョン
次のリビジョン
前のリビジョン
gimmickkouza:electronic_basic:6:3_oled_i2c [2024/06/16 19:54] – [ディスプレイの違い] matsuhachigimmickkouza:electronic_basic:6:3_oled_i2c [2024/06/20 22:47] (現在) – ★動画追加 lutamesta
行 2: 行 2:
 ===== ディスプレイについての基礎知識 ===== ===== ディスプレイについての基礎知識 =====
 ==== ディスプレイの違い ==== ==== ディスプレイの違い ====
-ディスプレイと一口に言っても、その仕組みや表示できるものの違い等、非常に幅が広いです。+ディスプレイと一口に言っても、その仕組みや表示できるものの違い等、非常に幅が広いです。 
  
 === ディスプレイの種類 === === ディスプレイの種類 ===
-電子工作用途で使われるディスプレイでは「LCD」と「OLED」が一般的です。+電子工作用途で使われるディスプレイでは「LCD」と「OLED」が一般的です。 
 あと最近では「電子ペーパー」なんてのもありますが、講師非所持のため説明は割愛します。 あと最近では「電子ペーパー」なんてのもありますが、講師非所持のため説明は割愛します。
  
行 29: 行 29:
 文字や数字をのみを表示できるLCDキャラクタディスプレイ。 文字や数字をのみを表示できるLCDキャラクタディスプレイ。
 工作物に組み込み、情報表示用途に使われます。 工作物に組み込み、情報表示用途に使われます。
-<alert type="danger">余談char型のキャラ。characterが文字集合の意味なんですよね</alert>+<panel type="info" title="まつはちさんからのアドバイス">余談ですが、キャラクタディスプレイの「キャラクタ」は変数char型のキャラと同義です 
 +characterが文字集合の意味なんですよね</panel>
  
 == グラフィック == == グラフィック ==
行 54: 行 55:
      
 ===== 6-3-1_OLED_I2C ===== ===== 6-3-1_OLED_I2C =====
 +{{youtube>6KLnDlhiGCE?large}}
 +  
 +(この動画は6-3-2と6-3-1を繋げています。0:58くらいから文字表示の様子が見られるよ)
 +  
 ==== I2Cの仕組み ==== ==== I2Cの仕組み ====
 UARTに続く二つめのシリアル通信、I2Cの登場です! UARTに続く二つめのシリアル通信、I2Cの登場です!
行 60: 行 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つです。
行 69: 行 76:
  
 順番にひとつずつ解説します。 順番にひとつずつ解説します。
 +/*<alert type="danger">コントローラの一組の信号線で複数のスレーブを操れるのが一番の特徴だと思うので、そこを書いたほうがわかりやすいです。
 +もちろん下記でも書いてあるんですが、その特徴があってこそのこの仕組みなので・・
 +</alert>*/
  
 == 信号線「SCL」と「SDA」 == == 信号線「SCL」と「SDA」 ==
行 89: 行 99:
 例えば本項での「コントローラ」はArduinoです。そこにOLEDディスプレイを「ターゲット」として繋ぎます。 例えば本項での「コントローラ」はArduinoです。そこにOLEDディスプレイを「ターゲット」として繋ぎます。
 **「ターゲット」として複数のディスプレイや他のI2C機器を繋ぐことも可能です。** **「ターゲット」として複数のディスプレイや他のI2C機器を繋ぐことも可能です。**
 +<panel type="info" title="まつはちさんからのアドバイス">ESP32のように、複数のI2Cポートを持っているマイコンもあります。
 +そういったマイコンであれば、I2C機器を繋ぎすぎたりする場合などに、複数のI2Cコントローラを用意して分割して繋ぐ手も使えます。</panel>
 +
 == クロック信号で同期を取る == == クロック信号で同期を取る ==
 I2Cでの通信の仕組みを超ざっくり説明します。 I2Cでの通信の仕組みを超ざっくり説明します。
行 105: 行 118:
 こういった部品を扱う際には、自分でI2Cアドレスを調べる必要があります。 こういった部品を扱う際には、自分でI2Cアドレスを調べる必要があります。
 いつかそんなシーンに遭遇した時のために、I2Cアドレスの調べ方を掲載しておきます。 いつかそんなシーンに遭遇した時のために、I2Cアドレスの調べ方を掲載しておきます。
- +   
-----+===i2c_scannerでI2Cアドレスを調べる===
 I2Cアドレスを確認するには、i2c_scannerというスケッチを使用します。 I2Cアドレスを確認するには、i2c_scannerというスケッチを使用します。
  
行 137: 行 150:
 下記の検索ワードを打ち込み、2つのライブラリをインストールしてください。 下記の検索ワードを打ち込み、2つのライブラリをインストールしてください。
  
-  * "Adafruit GFX"で検索をすると出てくる、作者名が「by Adafruit」の「AdafruitGFX Libraly+  * "Adafruit GFX"で検索をすると出てくる、作者名が「by Adafruit」の「AdafruitGFX Library
   * "Adafruit SSD1306"で検索すると出てくる作者名が「by Adafruit」の「AdafruitSSD1306」   * "Adafruit SSD1306"で検索すると出てくる作者名が「by Adafruit」の「AdafruitSSD1306」
  
 ちなみに~GFXはディスプレイ用のグラフィックスライブラリ、~SSD1306はSSD1306ドライバを搭載した電子部品を使用するためのライブラリです。 ちなみに~GFXはディスプレイ用のグラフィックスライブラリ、~SSD1306はSSD1306ドライバを搭載した電子部品を使用するためのライブラリです。
 +
 +/*<alert type="danger">AdafruitGFX Libraly 「Libraly」の綴り</alert>*/
      
 ==== 配線図 ==== ==== 配線図 ====
行 152: 行 167:
 また他のサイトや店舗で販売している似たようなディスプレイは、個別に確認が必要です。 また他のサイトや店舗で販売している似たようなディスプレイは、個別に確認が必要です。
 ネット情報ではプルアップ抵抗のない商品も存在するようです) ネット情報ではプルアップ抵抗のない商品も存在するようです)
 +
 +===使う部品リスト===
 +^ 部品                                                                  ^ 個数  ^
 +| OLEDディスプレイ | 1個   |
      
 ==== サンプルコード解説 ==== ==== サンプルコード解説 ====
 サンプルコード6-3-1_OLED_I2C.inoを開いてください。 サンプルコード6-3-1_OLED_I2C.inoを開いてください。
 +/*<alert type="danger">
 +下のコードをコピペすると「}」が足りないです
 +{{:gimmickkouza:electronic_basic:6:pasted:20240616-202611.png}}
 +</alert>*/
  
 <code> <code>
行 184: 行 207:
   display.display();//ディスプレイにテキストを表示   display.display();//ディスプレイにテキストを表示
   delay(1000);   delay(1000);
 +}
 </code> </code>
  
行 295: 行 319:
  
 全く同じコードを、サンプルコード「6-3-2_OLED_I2C_from_sample.ino」として収録してありますので、興味のある方はぜひ実行してみてください。 全く同じコードを、サンプルコード「6-3-2_OLED_I2C_from_sample.ino」として収録してありますので、興味のある方はぜひ実行してみてください。
 +  
 ==== 配線図 ==== ==== 配線図 ====
 {{:gimmickkouza:electronic_basic:6:6-3-1.png?600|}} {{:gimmickkouza:electronic_basic:6:6-3-1.png?600|}}
      
 直前の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を開いてください。
 +
 +<code>
 +/**************************************************************************
 + This is an example for our Monochrome OLEDs based on SSD1306 drivers
 +
 + Pick one up today in the adafruit shop!
 + ------> http://www.adafruit.com/category/63_98
 +
 + This example is for a 128x64 pixel display using I2C to communicate
 + 3 pins are required to interface (two I2C and one reset).
 +
 + Adafruit invests time and resources providing this open
 + source code, please support Adafruit and open-source
 + hardware by purchasing products from Adafruit!
 +
 + Written by Limor Fried/Ladyada for Adafruit Industries,
 + 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
 + included in any redistribution.
 + **************************************************************************/
 +
 +#include <SPI.h>
 +#include <Wire.h>
 +#include <Adafruit_GFX.h>
 +#include <Adafruit_SSD1306.h>
 +
 +#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:       A4(SDA), A5(SCL)
 +// On an arduino MEGA 2560: 20(SDA), 21(SCL)
 +// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
 +#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
 +
 +//ここのI2Cアドレスを、みなさんのディスプレイのI2Cアドレスに書き換えてください!
 +#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
 +
 +
 +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 +
 +#define NUMFLAKES     10 // Number of snowflakes in the animation example
 +
 +#define LOGO_HEIGHT   16
 +#define LOGO_WIDTH    16
 +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, SCREEN_ADDRESS)) {
 +    Serial.println(F("SSD1306 allocation failed"));
 +    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); // Pause for 2 seconds
 +
 +  // Clear the buffer
 +  display.clearDisplay();
 +
 +  // Draw a single pixel in white
 +  display.drawPixel(10, 10, SSD1306_WHITE);
 +
 +  // 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, you can batch up a bunch of
 +  // drawing operations and then update the screen all at once by calling
 +  // display.display(). These examples demonstrate both approaches...
 +
 +  testdrawline();      // Draw many lines
 +
 +  testdrawrect();      // Draw rectangles (outlines)
 +
 +  testfillrect();      // Draw rectangles (filled)
 +
 +  testdrawcircle();    // Draw circles (outlines)
 +
 +  testfillcircle();    // Draw circles (filled)
 +
 +  testdrawroundrect(); // Draw rounded rectangles (outlines)
 +
 +  testfillroundrect(); // Draw rounded rectangles (filled)
 +
 +  testdrawtriangle();  // Draw triangles (outlines)
 +
 +  testfilltriangle();  // Draw triangles (filled)
 +
 +  testdrawchar();      // Draw characters of the default font
 +
 +  testdrawstyles();    // Draw 'stylized' characters
 +
 +  testscrolltext();    // Draw scrolling text
 +
 +  testdrawbitmap();    // Draw a small bitmap image
 +
 +  // Invert and restore display, pausing in-between
 +  display.invertDisplay(true);
 +  delay(1000);
 +  display.invertDisplay(false);
 +  delay(1000);
 +
 +  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
 +}
 +
 +void loop() {
 +}
 +
 +void testdrawline() {
 +  int16_t i;
 +
 +  display.clearDisplay(); // Clear display buffer
 +
 +  for(i=0; i<display.width(); i+=4) {
 +    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
 +    display.display(); // Update screen with each newly-drawn line
 +    delay(1);
 +  }
 +  for(i=0; i<display.height(); i+=4) {
 +    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +  delay(250);
 +
 +  display.clearDisplay();
 +
 +  for(i=0; i<display.width(); i+=4) {
 +    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +  for(i=display.height()-1; i>=0; i-=4) {
 +    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +  delay(250);
 +
 +  display.clearDisplay();
 +
 +  for(i=display.width()-1; i>=0; i-=4) {
 +    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +  for(i=display.height()-1; i>=0; i-=4) {
 +    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +  delay(250);
 +
 +  display.clearDisplay();
 +
 +  for(i=0; i<display.height(); i+=4) {
 +    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +  for(i=0; i<display.width(); i+=4) {
 +    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +
 +  delay(2000); // Pause for 2 seconds
 +}
 +
 +void testdrawrect(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=0; i<display.height()/2; i+=2) {
 +    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
 +    display.display(); // Update screen with each newly-drawn rectangle
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testfillrect(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=0; i<display.height()/2; i+=3) {
 +    // The INVERSE color is used so rectangles alternate white/black
 +    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
 +    display.display(); // Update screen with each newly-drawn rectangle
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testdrawcircle(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
 +    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testfillcircle(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
 +    // The INVERSE color is used so circles alternate white/black
 +    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
 +    display.display(); // Update screen with each newly-drawn circle
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testdrawroundrect(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=0; i<display.height()/2-2; i+=2) {
 +    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
 +      display.height()/4, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testfillroundrect(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=0; i<display.height()/2-2; i+=2) {
 +    // The INVERSE color is used so round-rects alternate white/black
 +    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
 +      display.height()/4, SSD1306_INVERSE);
 +    display.display();
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testdrawtriangle(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
 +    display.drawTriangle(
 +      display.width()/ , display.height()/2-i,
 +      display.width()/2-i, display.height()/2+i,
 +      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
 +    display.display();
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testfilltriangle(void) {
 +  display.clearDisplay();
 +
 +  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
 +    // The INVERSE color is used so triangles alternate white/black
 +    display.fillTriangle(
 +      display.width()/ , display.height()/2-i,
 +      display.width()/2-i, display.height()/2+i,
 +      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
 +    display.display();
 +    delay(1);
 +  }
 +
 +  delay(2000);
 +}
 +
 +void testdrawchar(void) {
 +  display.clearDisplay();
 +
 +  display.setTextSize(1);      // Normal 1:1 pixel scale
 +  display.setTextColor(SSD1306_WHITE); // Draw white text
 +  display.setCursor(0, 0);     // Start at top-left corner
 +  display.cp437(true);         // Use full 256 char 'Code Page 437' font
 +
 +  // 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 == '\n') display.write(' ');
 +    else          display.write(i);
 +  }
 +
 +  display.display();
 +  delay(2000);
 +}
 +
 +void testdrawstyles(void) {
 +  display.clearDisplay();
 +
 +  display.setTextSize(1);             // Normal 1:1 pixel scale
 +  display.setTextColor(SSD1306_WHITE);        // Draw white text
 +  display.setCursor(0,0);             // Start at top-left corner
 +  display.println(F("Hello, world!"));
 +
 +  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
 +  display.println(3.141592);
 +
 +  display.setTextSize(2);             // Draw 2X-scale text
 +  display.setTextColor(SSD1306_WHITE);
 +  display.print(F("0x")); display.println(0xDEADBEEF, HEX);
 +
 +  display.display();
 +  delay(2000);
 +}
 +
 +void testscrolltext(void) {
 +  display.clearDisplay();
 +
 +  display.setTextSize(2); // Draw 2X-scale text
 +  display.setTextColor(SSD1306_WHITE);
 +  display.setCursor(10, 0);
 +  display.println(F("scroll"));
 +  display.display();      // Show initial text
 +  delay(100);
 +
 +  // Scroll in various directions, pausing in-between:
 +  display.startscrollright(0x00, 0x0F);
 +  delay(2000);
 +  display.stopscroll();
 +  delay(1000);
 +  display.startscrollleft(0x00, 0x0F);
 +  delay(2000);
 +  display.stopscroll();
 +  delay(1000);
 +  display.startscrolldiagright(0x00, 0x07);
 +  delay(2000);
 +  display.startscrolldiagleft(0x00, 0x07);
 +  delay(2000);
 +  display.stopscroll();
 +  delay(1000);
 +}
 +
 +void testdrawbitmap(void) {
 +  display.clearDisplay();
 +
 +  display.drawBitmap(
 +    (display.width()  - LOGO_WIDTH ) / 2,
 +    (display.height() - LOGO_HEIGHT) / 2,
 +    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
 +  display.display();
 +  delay(1000);
 +}
 +
 +#define XPOS   0 // Indexes into the 'icons' array in function below
 +#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 'snowflake' positions
 +  for(f=0; f< NUMFLAKES; f++) {
 +    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
 +    icons[f][YPOS]   = -LOGO_HEIGHT;
 +    icons[f][DELTAY] = random(1, 6);
 +    Serial.print(F("x: "));
 +    Serial.print(icons[f][XPOS], DEC);
 +    Serial.print(F(" y: "));
 +    Serial.print(icons[f][YPOS], DEC);
 +    Serial.print(F(" dy: "));
 +    Serial.println(icons[f][DELTAY], DEC);
 +  }
 +
 +  for(;;) { // Loop forever...
 +    display.clearDisplay(); // Clear the display buffer
 +
 +    // Draw each snowflake:
 +    for(f=0; f< NUMFLAKES; f++) {
 +      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
 +    }
 +
 +    display.display(); // Show the display buffer on the screen
 +    delay(200);        // Pause for 1/10 second
 +
 +    // 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]   = random(1 - LOGO_WIDTH, display.width());
 +        icons[f][YPOS]   = -LOGO_HEIGHT;
 +        icons[f][DELTAY] = random(1, 6);
 +      }
 +    }
 +  }
 +}
 +</code>
 +
 37行目のI2CアドレスをみなさんのディスプレイのI2Cアドレスに書き換えてArduinoに書き込んでください。 37行目のI2CアドレスをみなさんのディスプレイのI2Cアドレスに書き換えてArduinoに書き込んでください。
  
 ※今回のコードはライブラリ付属のサンプルスケッチそのまんまですので、解説は致しません! ※今回のコードはライブラリ付属のサンプルスケッチそのまんまですので、解説は致しません!
 +  
      
      
 {{:gimmickkouza:electronic_basic:6:6-30.png?400|}} {{:gimmickkouza:electronic_basic:6:6-30.png?400|}}
 +
 +/*<alert type="danger">せめてコードは載せておいてもらえると…</alert>*/
 +