STM32F401(Black Pill)にSD・ssd1306・LM35と色々詰め込んでみた

　400穴ブレッドボード上のSTM32F401CCU6(Black Pill)にどれだけ詰め込めるか試しました。ArduinoIDEを使いmicroSDカードスロット、SSD1306OLED、温度センサーLM35CZを載せて動かしてみました。
![F401Many.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/91e99a70-00cf-2944-a5d5-ff4922c59bd2.jpeg)

Adafruitのssd1306_128x64_i2cのexampleに、SDライブラリー、温度を読取る簡単なコードを加えてbinの62.88KBのサイズでした。なかなかの大きさになりましたがまだ余裕ですかね。相変わらず、このボードを「STM32 BOOTLOADER」に変化させるのに世話が焼けます。
　内容は、まずSDカードからファイルリストを取得表示させ、次にお決まりのグラフィックスを表示、loopで温度を取得表示という、たいして芸の無いものです。温度の較正のため私の部屋の温度に合うよう適当に
　temp_val = (temp_adc_val * 3.00/10)
としてあります。1度ぐらいは常にずれてきますが。
　今回初めて、display.cp437(true or false)を意識しましたが、「0xB0」に一文字入るかどうかの違いです。温度の「°」を表すために「248」を使いました。
　以下にソースを示しますが、描画の関数群は省略します。ただし、スノーフレークの部分はdelay(50)とし、無限ループを100回ループに変更し、loopに進むようにしました。
```
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SD.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)
#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
  };
/*
  SD card attached to SPI bus as follows:
  ** MOSI - pin 11
  ** MISO - pin 12
  ** CLK  - pin 13
  ** CS   - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
*/
// STM32F401CCU6
#define MOSI PA7
#define MISO PA6
#define CLK  PA5
#define CS   PA4

#define lm35_pin PA1	/* LM35 O/P pin */

File root;

void setup() {
  Serial.begin(115200);
  Wire.setSDA(PB7);
  Wire.setSCL(PB6);
  Wire.begin();

  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }

  // 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...
  
  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
  
  Serial.print("Initializing SD card...");
  display.print("Initializing SD card...");
  if (!SD.begin(CS)) {
    Serial.println("initialization failed!");
    display.println("initialization failed!");
    delay(1000);
  } else {
    Serial.println("initialization done.");
    display.println("initialization done.");
    root = SD.open("/");
    printDirectory(root, 0);
    Serial.println("done!");
    display.println("done!");
  }
  display.display();
  delay(5000);
  display.clearDisplay();

  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() {  
  int temp_adc_val;
  float temp_val;
  temp_adc_val = analogRead(lm35_pin);	/* Read Temperature */
  temp_val = (temp_adc_val * 3.00/10);	/* Convert adc value to equivalent voltage */
  //temp_val = (temp_val/10);	/* LM35 gives output of 10mv/°C */
  Serial.print("Temperature = ");
  Serial.print(temp_val);
  Serial.println(" Degree Celsius");

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);  // Draw white text
  display.setTextSize(2);               // Normal 1:1 pixel scale
  display.setCursor(0, 0);              // Start at top-left corner
  display.println(F("Temperature"));

  display.setTextSize(3);               // Normal 1:1 pixel scale
  //display.setCursor(0, 8);              // Start at top-left corner
  display.print(temp_val);
  
  display.setTextSize(1);               // Normal 1:1 pixel scale
  //display.setCursor(0, 32);              // Start at top-left corner
  display.cp437(true);
  display.write(248);//167
  display.setTextSize(3);
  display.print("C");
  display.display();                    // Important

  delay(2000);  
}

void printDirectory(File dir, int numTabs) {
  while (true) {
    File entry = dir.openNextFile();
    if (!entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
      display.print('\t');
    }
    Serial.print(entry.name());
    display.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      display.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
      display.print("\t\t");
      display.println(entry.size(), DEC);
    }
    entry.close();
  }
}

```