秋月電子で販売されている ATtiny1604 は、1個100円程度で手に入る小型・高性能なAVRマイコンです。
Arduino互換の環境も整っており、低消費電力でI/Oも豊富です。
今回は VS Code + PlatformIO を使って、
- SerialUPDIによる書き込み
- Lチカ動作確認
- I2C接続LCD(AQM1602、SSD1306)表示
を順に試してみます。初心者でも簡単に再現できる内容です。
開発環境の準備
- VS Code と PlatformIO(拡張機能) のインストール
- 新規プロジェクト作成
- attiny1604 (自分の好きなプロジェクト名を設定する)
- Board:
ATtiny1604(選択) - Framework:Arduino
- Location(保存先)を確認して「Finish」
これでプロジェクトフォルダが自動で作成されます。
フォルダーの構成
PlatformIO は、プロジェクトフォルダごとに独立して環境を持っています。
Documents/
├─ ATtiny1604/
│ ├─ platformio.ini // 構成ファイル
│ └─ src/main.cpp // ここにプログラムを書いて実行します
├─ LCD_Test/
│ ├─ platformio.ini
│ └─ src/main.cpp高度な構成
ATtiny1604/
├─ platformio.ini ← 設定ファイル
├─ src/
│ └─ main.cpp ← ← ← 実際に書くプログラム
├─ lib/
│ └─ MyLibrary/
│ ├─ MyLibrary.h // 自作ライブラリーのヘッダーファイルを置く場所
│ └─ MyLibrary.cpp // 自宅ライブラリーのCPPファイルを置く場所です
└─ include/ ← (必要ならヘッダを置く場所)platformio.ini の設定例
PlatformIO では、設定ファイル platformio.ini に書き込み方法やライブラリをまとめて指定します。
[env:attiny1604]
platform = atmelmegaavr
board = ATtiny1604
framework = arduino
upload_protocol = serialupdi
upload_port = COM3 // 自分の環境に合わせる
lib_deps =
asukiaaa/ST7032_asukiaaa設定のポイント
- upload_protocol = serialupdi
→ ATtiny1604は1本線のUPDI通信で書き込みます。
書き込みにはUSBシリアル変換モジュールと1kΩ抵抗で作る簡易UPDIアダプタが使えます。 - lib_deps
→ ライブラリを自動インストール。ここではI2C液晶(AQM1602)用の「ST7032_asukiaaa」を指定。
SerialUPDI書き込みについて
SerialUPDI(シリアル・ユーピーディーアイ) はATtiny0/1系で採用されている新しい書き込み方式です。
詳しい説明はこちらの私のブログで確認してください
🔌配線例
| USBシリアル変換モジュール | ATtiny1604ピン |
|---|---|
| TX → 1kΩ抵抗 → UPDI | PA0 (UPDIピン) |
| GND | GND |
| 5Vまたは3.3V電源 | VCC |
これで書き込み準備完了です。
Lチカで動作確認
src/main.cpp に以下を保存。
// ATtiny1604 PA3ピン Lチカ
// megaTinyCoreではピン番号ではなく "PIN_PA3" を使用します
#include <Arduino.h> // これを必ず最初に入れる!
#include <Wire.h>
void setup() {
pinMode(PIN_PA3, OUTPUT); // PA3を出力に設定
}
void loop() {
digitalWrite(PIN_PA3, HIGH); // LED点灯
delay(500); // 500ms待機
digitalWrite(PIN_PA3, LOW); // LED消灯
delay(500); // 500ms待機
}ビルド アップロード
VSCODEの下部画面にビルドとuploadボタンがありますので実行してください。

PA3に接続したLEDが点滅すれば書き込み成功です。
I2C液晶接続(AQM1602 / SSD1306)
💡配線(I2C共通)
| 信号 | ATtiny1604ピン | 備考 |
|---|---|---|
| SDA | PB1 | I2Cデータ線 |
| SCL | PB0 | I2Cクロック線 |
| VCC | 3.3Vまたは5V | モジュールに合わせる |
| GND | GND | 共通グラウンド |
配線図

サンプルコード(AQM1602)
#include <Arduino.h>
#include <Wire.h>
#include <ST7032_asukiaaa.h>
ST7032_asukiaaa lcd;
void setup() {
lcd.begin(16, 2);
lcd.setContrast(12);
lcd.print("Hello!");
}
void loop() {}OLED(SSD1306)で文字表示
adafruit/Adafruit SSD1306
adafruit/Adafruit GFX Library
上記のライブラリーを使って動かしましたが表示されませんでした、しかし以前私がブログで紹介した、自作フォントを使ったプログラムで表示ができました。
フォントヘッダーファイル(SimpleFont.h)
PlatformIO では、プロジェクト内に lib フォルダを作り、その中にライブラリ、ヘッダーファイルを置くのが標準です。
今回のフォルダー構成は下記のようになります。
ATtiny1604/
├─ src/
│ └─ main.cpp
├─ lib/
│ └─ SimpleFont/
│ └─ SimpleFont.h // ここにヘッダーファイル
└─ platformio.ini#ifndef SIMPLEFONT_H
#define SIMPLEFONT_H
// 5x7 縦向きフォント A-Z, 0-9
const uint8_t font5x7[][7] = {
// A-Z (26文字)
{ 0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001 }, // A
{ 0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110 }, // B
{ 0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110 }, // C
{ 0b11100, 0b10010, 0b10001, 0b10001, 0b10001, 0b10010, 0b11100 }, // D
{ 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111 }, // E
{ 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000 }, // F
{ 0b01110, 0b10001, 0b10000, 0b10111, 0b10001, 0b10001, 0b01110 }, // G
{ 0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001 }, // H
{ 0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110 }, // I
{ 0b00001, 0b00001, 0b00001, 0b00001, 0b10001, 0b10001, 0b01110 }, // J
{ 0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001 }, // K
{ 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111 }, // L
{ 0b10001, 0b11011, 0b10101, 0b10001, 0b10001, 0b10001, 0b10001 }, // M
{ 0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001 }, // N
{ 0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110 }, // O
{ 0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000 }, // P
{ 0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101 }, // Q
{ 0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001 }, // R
{ 0b01111, 0b10000, 0b10000, 0b01110, 0b00001, 0b00001, 0b11110 }, // S
{ 0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100 }, // T
{ 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110 }, // U
{ 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100 }, // V
{ 0b10001, 0b10001, 0b10001, 0b10001, 0b10101, 0b11011, 0b10001 }, // W
{ 0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001 }, // X
{ 0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100 }, // Y
{ 0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111 }, // Z
// 0-9 (10文字)
{ 0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110 }, // 0
{ 0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110 }, // 1
{ 0b01110, 0b10001, 0b00001, 0b00110, 0b01000, 0b10000, 0b11111 }, // 2
{ 0b11110, 0b00001, 0b00001, 0b01110, 0b00001, 0b00001, 0b11110 }, // 3
{ 0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010 }, // 4
{ 0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110 }, // 5
{ 0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110 }, // 6
{ 0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b10000 }, // 7
{ 0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110 }, // 8
{ 0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100 }, // 9
// a-z (26文字)
{ 0b00000, 0b00000, 0b01110, 0b00001, 0b01111, 0b10001, 0b01111 }, // a
{ 0b10000, 0b10000, 0b10110, 0b11001, 0b10001, 0b10001, 0b11110 }, // b
{ 0b00000, 0b00000, 0b01110, 0b10001, 0b10000, 0b10001, 0b01110 }, // c
{ 0b00001, 0b00001, 0b01101, 0b10011, 0b10001, 0b10001, 0b01111 }, // d
{ 0b00000, 0b00000, 0b01110, 0b10001, 0b11110, 0b10000, 0b01110 }, // e
{ 0b00110, 0b01001, 0b01000, 0b11100, 0b01000, 0b01000, 0b01000 }, // f
{ 0b00000, 0b01111, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110 }, // g
{ 0b10000, 0b10000, 0b10110, 0b11001, 0b10001, 0b10001, 0b10001 }, // h
{ 0b00100, 0b00000, 0b01100, 0b00100, 0b00100, 0b00100, 0b01110 }, // i
{ 0b00010, 0b00000, 0b00110, 0b00010, 0b00010, 0b10010, 0b01100 }, // j
{ 0b10000, 0b10000, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010 }, // k
{ 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110 }, // l
{ 0b00000, 0b00000, 0b11010, 0b10101, 0b10101, 0b10101, 0b10101 }, // m
{ 0b00000, 0b00000, 0b10110, 0b11001, 0b10001, 0b10001, 0b10001 }, // n
{ 0b00000, 0b00000, 0b01110, 0b10001, 0b10001, 0b10001, 0b01110 }, // o
{ 0b00000, 0b00000, 0b11110, 0b10001, 0b11110, 0b10000, 0b10000 }, // p
{ 0b00000, 0b00000, 0b01111, 0b10001, 0b01111, 0b00001, 0b00001 }, // q
{ 0b00000, 0b00000, 0b10110, 0b11001, 0b10000, 0b10000, 0b10000 }, // r
{ 0b00000, 0b00000, 0b01110, 0b10000, 0b01110, 0b00001, 0b11110 }, // s
{ 0b01000, 0b01000, 0b11100, 0b01000, 0b01000, 0b01001, 0b00110 }, // t
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b10001, 0b10011, 0b01101 }, // u
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b01010, 0b01010, 0b00100 }, // v
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b10101, 0b10101, 0b01010 }, // w
{ 0b00000, 0b00000, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001 }, // x
{ 0b00000, 0b00000, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110 }, // y
{ 0b00000, 0b00000, 0b11111, 0b00010, 0b00100, 0b01000, 0b11111 }, // z
{ 0b00000, 0b00100, 0b00100, 0b11111, 0b00100, 0b00100, 0b00000 }, // +
{ 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000 }, // -
{ 0b00000, 0b00000, 0b11111, 0b00000, 0b11111, 0b00000, 0b00000 }, // =
{ 0b11000, 0b11001, 0b00010, 0b00100, 0b01000, 0b10011, 0b00011 }, // %
{ 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00110, 0b00110 }, // .
{ 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 } // スペース
};
#endifmain.cpp
#include <Wire.h>
#include "SimpleFont.h"
const char* mySt = "Hello World!";
#define OLED_ADDR 0x3C
const uint8_t init_cmds[] = {
0xAE, 0x20, 0x00, 0xB0, 0xC8, 0x00, 0x10,
0x40, 0x81, 0x7F, 0xA1, 0xA6, 0xA8, 0x3F,
0xA4, 0xD3, 0x00, 0xD5, 0xF0, 0xD9, 0x22,
0xDA, 0x12, 0xDB, 0x20, 0x8D, 0x14, 0xAF
};
void sendCommand(uint8_t cmd) {
Wire.beginTransmission(OLED_ADDR);
Wire.write(0x00);
Wire.write(cmd);
Wire.endTransmission();
}
void sendData(uint8_t data) {
Wire.beginTransmission(OLED_ADDR);
Wire.write(0x40);
Wire.write(data);
Wire.endTransmission();
}
void initOLED() {
Wire.begin();
delay(100);
for (uint8_t i = 0; i < sizeof(init_cmds); i++) {
sendCommand(init_cmds[i]);
}
}
void setCursor(uint8_t x, uint8_t page) {
sendCommand(0xB0 + page);
sendCommand(0x00 + (x & 0x0F));
sendCommand(0x10 + (x >> 4));
}
void clearDisplay() {
for (uint8_t page = 0; page < 8; page++) {
setCursor(0, page);
for (uint8_t i = 0; i < 128; i++) {
sendData(0x00);
}
}
}
void drawCharVertical(char c, uint8_t x, uint8_t page) {
uint8_t index;
if (c >= 'A' && c <= 'Z') {
index = c - 'A'; // 0〜25
} else if (c >= '0' && c <= '9') {
index = 26 + (c - '0'); // 26〜35
} else if (c >= 'a' && c <= 'z') {
index = 36 + (c - 'a'); // 36〜61
} else {
// 特殊記号追加する
switch (c) {
case '+': index = 62; break;
case '-': index = 63; break;
case '=': index = 64; break;
case '%': index = 65; break;
case '.': index = 66; break;
case ' ': index = 67; break;
default: return; // 未定義文字は無視
}
}
for (int col = 0; col < 5; col++) {
uint8_t colBits = 0;
for (int row = 0; row < 7; row++) {
if (font5x7[index][row] & (1 << (4 - col))) {
colBits |= (1 << row);
}
}
setCursor(x + col, page);
sendData(colBits);
}
setCursor(x + 5, page);
sendData(0x00); // スペース
}
void drawStringVertical(const char* str, uint8_t x, uint8_t page) {
while (*str) {
drawCharVertical(*str, x, page);
x += 6; // 5ドット+スペース
str++;
}
}
void setup() {
initOLED();
clearDisplay();
drawStringVertical("HELLO123456789--", 0, 2);
drawStringVertical("Hlloa+-=%.", 0, 4); // テスト用
drawStringVertical(mySt, 0, 6);
}
void loop() {
}🧾まとめ
VS Code + PlatformIO を使えば、
ATtiny1604のような小型マイコンにも簡単にプログラムを書き込めます。
upload_protocol = serialupdi の設定で、
USBシリアル変換器と1本線UPDIケーブルだけで書き込み可能。
Lチカで動作を確認し、I2C接続の液晶やOLEDを表示すれば、
ATtiny1604の入門から実用までを1台で体験できます。



