「あー!!!PWMポートもっとあるのを書き忘れてたの思い出した!!!!(✽ ゚д゚ ✽)!!!!」
「3つだけじゃなくて他のポートも前回のコアアップデートで動くようになったの忘れてたw」
![]() |
| ピン配置図(2025年9月版) |
ゲーム専門学校の講師をしつつ、同人活動を楽しんでいます。
![]() |
| ピン配置図(2025年9月版) |
//------------------------------------------------
// LED + ボタン + ブザー実験用スケッチ
//
// 目的:
// ・74HC595を2個使って、LEDを最大11個制御する
// ・74HC165を2個使って、ボタンを最大11個読み取る
// ・ボタン0〜9は、対応するLEDを点灯し、音階を鳴らす
// ・ボタン10は、LED10を点灯し、自励式ブザーを鳴らす
//
// 接続概要:
// ・LED出力側:74HC595 x2
// ・ボタン入力側:74HC165 x2
// ・音出力:他励式ブザー / スピーカー
// ・警告音:自励式ブザー
//------------------------------------------------
//------------------------------------------------
// 74HC595 側の接続
//
// 74HC595は「少ないマイコンピンでたくさんのLEDを制御する」IC。
// 今回は2個カスケード接続して、LEDを11個まで扱う。
//
// PIN_SER : 74HC595のSER / DS
// PIN_LATCH : 74HC595のRCLK / ST_CP
// PIN_CLK : 74HC595のSRCLK / SH_CP
//------------------------------------------------
const int PIN_SER = 11;
const int PIN_LATCH = 8;
const int PIN_CLK = 12;
//------------------------------------------------
// 74HC165 側の接続
//
// 74HC165は「たくさんのボタン入力を少ないマイコンピンで読む」IC。
// 今回は2個カスケード接続して、16bit分の入力を読む。
// 実際に使っているのは、そのうち11個。
//
// PIN_165_DATA : 74HC165のQH
// PIN_165_LOAD : 74HC165のSH/LD
// PIN_165_CLK : 74HC165のCLK
//
// ボタン入力はプルアップ前提。
// つまり、押していない時はHIGH、押すとLOWになる。
//------------------------------------------------
const int PIN_165_DATA = 7;
const int PIN_165_LOAD = 5;
const int PIN_165_CLK = 10;
//------------------------------------------------
// LED表示用の仮想画面
//
// vram[0]〜vram[10] が LED0〜LED10 に対応。
// 直接74HC595へ書き込まず、いったんvramに状態を作ってから
// drawVRAM()でまとめてLEDへ反映する。
//------------------------------------------------
const int SCREEN_WIDTH = 11;
bool vram[SCREEN_WIDTH];
//------------------------------------------------
// ブザー接続
//
// PIN_SPEAKER : 他励式ブザー、または小型スピーカー
// tone()で周波数を指定して鳴らす。
// PIN_ALARM : 自励式ブザー
// HIGHにするだけで鳴るタイプ。
//------------------------------------------------
const int PIN_SPEAKER = 6; // 他励式ブザー / スピーカー
const int PIN_ALARM = 0; // 自励式ブザー
//------------------------------------------------
// ボタン0〜9に対応する音階
//------------------------------------------------
const int noteTable[10] =
{
262, // Button0 : ド(C4)
294, // Button1 : レ
330, // Button2 : ミ
349, // Button3 : ファ
392, // Button4 : ソ
440, // Button5 : ラ
494, // Button6 : シ
523, // Button7 : ド(C5)
587, // Button8 : レ
659 // Button9 : ミ
};
//------------------------------------------------
// VRAM操作
//------------------------------------------------
void clearVRAM()
{
for (int i = 0; i < SCREEN_WIDTH; i++)
{
vram[i] = false;
}
}
void setPixel(int x, bool on)
{
if (x < 0 || x >= SCREEN_WIDTH) return;
vram[x] = on;
}
//------------------------------------------------
// 74HC595へLED状態を出力
//
// vram[0]〜vram[7] → 1個目の74HC595
// vram[8]〜vram[10] → 2個目の74HC595
//
// shiftOutは、先に2個目ぶんのデータを送り、
// 次に1個目ぶんのデータを送る。
// その後、LATCHをHIGHにしてLEDへ反映する。
//------------------------------------------------
void drawVRAM()
{
byte b1 = 0;
byte b2 = 0;
for (int i = 0; i < SCREEN_WIDTH; i++)
{
if (vram[i])
{
if (i < 8)
{
b1 |= (1 << i);
}
else
{
b2 |= (1 << (i - 8));
}
}
}
digitalWrite(PIN_LATCH, LOW);
shiftOut(PIN_SER, PIN_CLK, MSBFIRST, b2);
shiftOut(PIN_SER, PIN_CLK, MSBFIRST, b1);
digitalWrite(PIN_LATCH, HIGH);
}
//------------------------------------------------
// 74HC165 x2 読み取り
//
// 2個の74HC165から16bitぶんのボタン状態を読む。
// LOADをLOWにすると、各入力ピンの状態がIC内部に取り込まれる。
// その後、CLKを動かしながらDATAピンから1bitずつ読む。
//
// プルアップ接続なので、
// ・押していない → 1
// ・押している → 0
// になる。
//------------------------------------------------
unsigned int read165x2()
{
unsigned int data = 0;
digitalWrite(PIN_165_CLK, LOW);
delayMicroseconds(20);
digitalWrite(PIN_165_LOAD, LOW);
delayMicroseconds(20);
digitalWrite(PIN_165_LOAD, HIGH);
delayMicroseconds(20);
data = digitalRead(PIN_165_DATA) ? 1 : 0;
for (int i = 1; i < 16; i++)
{
digitalWrite(PIN_165_CLK, HIGH);
delayMicroseconds(20);
digitalWrite(PIN_165_CLK, LOW);
delayMicroseconds(20);
data <<= 1;
if (digitalRead(PIN_165_DATA))
{
data |= 1;
}
}
return data;
}
//------------------------------------------------
// ボタン割り当て
//
// read165x2()で読んだ16bitのうち、
// どのbitをどのボタンとして扱うかを定義する。
//
// Button0〜Button7 : 1個目の74HC165
// Button8〜Button10 : 2個目の74HC165
//
// H, G, F... の順番で読んでいるため、
// Button0 = #1 H になっている。
//------------------------------------------------
const unsigned int buttonMask[11] =
{
0x8000, // Button0 = #1 H
0x4000, // Button1 = #1 G
0x2000, // Button2 = #1 F
0x1000, // Button3 = #1 E
0x0800, // Button4 = #1 D
0x0400, // Button5 = #1 C
0x0200, // Button6 = #1 B
0x0100, // Button7 = #1 A
0x0080, // Button8 = #2 H
0x0040, // Button9 = #2 G
0x0020 // Button10 = #2 F
};
//------------------------------------------------
// setup
//------------------------------------------------
void setup()
{
// UIAPduino / CH32V003用の初期化処理。
// 書き込みやデバッグピンの都合で必要になる場合がある。
if (FLASH->STATR & (1<<14)) NVIC_SystemReset();
SystemReset_StartMode(Start_Mode_BOOT);
pinMode(PD4, OUTPUT);
pinV32_DisconnectDebug(PD_1);
pinMode(PIN_SPEAKER, OUTPUT);
pinMode(PIN_ALARM, OUTPUT);
digitalWrite(PIN_ALARM, LOW);
pinMode(PIN_SER, OUTPUT);
pinMode(PIN_LATCH, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
pinMode(PIN_165_DATA, INPUT);
pinMode(PIN_165_LOAD, OUTPUT);
pinMode(PIN_165_CLK, OUTPUT);
digitalWrite(PIN_LATCH, HIGH);
digitalWrite(PIN_CLK, LOW);
digitalWrite(PIN_165_LOAD, HIGH);
digitalWrite(PIN_165_CLK, LOW);
clearVRAM();
drawVRAM();
}
//------------------------------------------------
// loop
//
// 1. 74HC165からボタン状態を読む
// 2. 押されたボタンに対応するLEDを点灯する
// 3. Button0〜Button9なら音階を鳴らす
// 4. Button10なら自励式ブザーを鳴らす
// 5. 74HC595へLED状態を反映する
//------------------------------------------------
void loop()
{
unsigned int sw = read165x2();
clearVRAM();
int note = -1;
// Button0〜Button9
// 押されているボタンに対応するLEDを点灯し、
// 最初に見つかったボタンの音を鳴らす。
for (int i = 0; i < 10; i++)
{
if (!(sw & buttonMask[i]))
{
setPixel(i, true);
if (note < 0)
{
note = i;
}
}
}
// Button10
// LED10を点灯し、自励式ブザーを鳴らす。
if (!(sw & buttonMask[10]))
{
setPixel(10, true);
digitalWrite(PIN_ALARM, HIGH);
}
else
{
digitalWrite(PIN_ALARM, LOW);
}
drawVRAM();
if (note >= 0)
{
tone(PIN_SPEAKER, noteTable[note]);
}
else
{
noTone(PIN_SPEAKER);
}
delay(10);
}
シフトレジスタ[74HC595]を使って11個のLEDを点灯させることができたので、次は入力だ! ということでシフトレジスタ[74HC165]を使った11個のキー入力に挑戦したのだけれど、これが苦戦の連続だった。
出力側につかうシフトレジスタ[74HC595]の参考資料やサンプルプログラムは、公式サイトやあちこちのブログに書かれている。でも入力側につかう[74HC165]に関しては、(自分が理解できる)ちょうど良いものを見つけることができなかったのだ。
もちろん資料がゼロというわけではない。データシートや海外の解説記事も見つかった。でも初心者向けに「こう繋げば動くよ」と説明してくれる記事は少なく、自分には少しハードルが高かった。
それから苦戦した原因のもう一つ。これは完全に自分が悪い。すぐに動くだろうと考えて、単体テストを行わずに、いきなり制作中の基板に[74HC165]を2つも繋げてしまった。
そのせいで追加した回路が悪いのか? ICが壊れているのか? 元々動いているLED表示側回路が実は間違っていたのか? テストプログラムが間違っているのか? 原因を特定することができなくなってしまった……。
さんざん試行錯誤をしたあとに冷静になって、入力側のシフトレジスタ[74HC165]を1つだけでテストする別の基板をつくってみた。ChatGPTに回路図やテストプログラムを何度も見てもらいながら、なんとか動かすことができるようになり、その後で[74HC165]を更に追加した。
本当はブレッドボード2枚に全部の回路を納めようと思って詰め込んでいたけれど、また修正する可能性が高い。3枚構成にすることにした。一番下はユーザーインタフェース専用基板、2枚目はLED出力管理専用基板、3枚目はキー入力管理+UIAPduinoを設置する基板となった。
ひとまず11個のLEDを、対応する11個のタクトスイッチを押すと光らせる所までは、つくることができた。次はブザーをつけて、音を鳴らすつもり。
今度は絶対に単体テストをしてからやるぞー!
| ブレッドボード3枚になってしまった! |
シフトレジスタを1つ扱うだけで知らない用語がどんどん出てくる。「いわゆるラッチ」「両方ともポジティブエッジトリガー」「複数のフリップフロップをカスケード接続」など……。用語を知らない自分には、なかなか手ごわいのだ。だから、今はカバンの中に解説サイトをプリントアウトしたものを持ち歩いて勉強中。
公式サイトの説明も、ちょっとだけ不親切かなと思う。機能説明や回路図のあちこちにシフトレジスタが載っているが、実際のピンの位置と図解が一致していないものがあるのだ。詳しい人に聞いたら、「機能の説明として描かれているから、実際の場所と違うのがあたり前」らしい。でもなあ、せめて同じページ内では、あわせて欲しいなあ。
ついでに言うと、日本語リファレンスと英語の公式サイトでは、使っている抵抗の仕様がなぜか違う。日本語は220Ωで、英語は470Ωだ。初心者だから、「この違いに、なにか深い理由があるのでは?」と考えてしまい、作業がいちいち止まってしまう。LEDも抵抗も、そこまで神経質にならなくてもいいのだろうけれど。
マイコンにピンを増やすと言えば、カナダのクリエイターさんから「私たち全員が ch32v003 用の PCB の作成に取り組んでいるのが気に入っています :]」というコメントを頂いた。彼らがつくろうとしている基板の中央には『PCF8574』が配置されている。秋月電子によると「I2Cバスと8ビットパラレルを変換するICです」とのこと。
![]() |
| 中央に【PCF8574】が見えます。 |
![]() |
| CH32V003繋がりでコメントをくれたようです! |
詳しく聞いてみると、「ボードのIOをもっと増やしたかったんです。8574の低品質なIOでも許容範囲内でした。」と教えてくれた。
フムフム……。いろいろなアプローチがあるなあ。以前にもチャーリープレクシングのことをチェコの方が教えてくれた。マイコンを始めたおかげで、思わぬ国際交流が生まれていて、それもまた楽しい。PCF8574は、来週aitendoに行けたら買ってきて試してみよう。
《1人で1万個量産、290円のマイコンボード「UIAPduino」ーー目指す先は100均の棚》という刺激的な記事が、Webメディアのfabscene(ファブシーン)から公開されて話題になっている。
「これがバズるってことなのか……」と驚くことばかり。あっという間に各所の通販サイトから在庫がなくなってしまった。今まで少なかった作例も、次々と公開されはじめた。これは嬉しい。初心者としては、参考例をたくさん見たいので。
作例以外にも、290円でマイコンボードを販売するという値付けや、インタビューを受けた埋田さんのスタンスへの異論・反論もたくさん見ることができた。自分は単純にエンドユーザーだから、明るい話題だと思っていたけれど、立場が違うと意見も変わるものなんだなと改めて感じた。あまりにも目立ったから、反動も大きいのかな。でも当の埋田さんは、「色々議論が活性化してて面白いなぁ〜」という他人事のような感じで、バズった状況との対比が面白い。
このタイミングで、同人誌『290円マイコン、はじめました。』の購入特典をマイコンボード3台に変更したバージョンをリリースしてみた。というのも、SNSでマイコンボードを複数買っている方を見かけたので、そういうものなのかな……と試験的なつもりで。
でも、これが正解だったみたい。今まで通販では無風だったけれど、急に追い風が吹いた感じで最近は梱包と発送に追われている。「マイコンボードが余ったらお返しします〜」と冗談半分に言っていたのにね。
LEDを大量に扱う方法はいくつもあるけれど、最初はシンプルなシフトレジスタ[74HC595]というロジックICを使うやり方を試してみることにした。ネット上にサンプルがたくさんあるから安心だし、Arduino公式のチュートリアルにも解説があった。
チュートリアルにはブレッドボード図も載っていた。だから見たままに繋ぐだけでOKなので、Arduino UNOに再現するのは簡単。あっさりと8個のLEDが次々と点滅した。嬉しくなって、ソースコードの中身を理解する前に部屋を暗くして思わず記念撮影をしてしまった。暗闇の中で光るLEDは、とにかくカッコイイのだ。
次のステップでシフトレジスタを複数繋いでみたが、これも問題はなかった。3つの入出力ピン、2つの電源ピンを使うだけで16個のLEDがコントロールできる。LEDが順々に光っているだけなのに、『ゲームベーダー』への第一歩になった気がして勇気がでてくる。
さて、「今日の最後のステップとして、Arduino UNOから本命のUIAPduinoに移植しよう!」と、勢いのままに進めてみたけれど、ちょっとした落とし穴があった。油断大敵なのだ。
Arduino UNO用のサンプル・プログラムには、
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;
と、使うピンが定義されている。UIAPduinoのピン配置図を見る限り、この3つの番号(8/11/12)は同じように使えるはず。だから特に変更をせずに試してみたけれど。なぜか、うまく動かない……。
いろいろと試行錯誤してみたけれど、結論は「UIAPduinoの場合、11番のピンだと動かない!」らしい。これには本当にビックリした。でも、そういえば狭山ヶ丘寺子屋で、「ちゃんと動かないピンがあるなあ」と、隣の席で作業をしていた方が呟いていたような。あの時は、どんな意味かわからなかったけれど、こういうことだったのか。
検証作業をひと段落させてからUIAPのコミュニティに、「質問です。PD1(11)って、他のピンと仕様が違うのでしょうか? LED繋いでも、このピン(とPD7)だけ光らないので…。気になっちゃって」と投稿をしてみた。
すると、開発者のUmetaさんから、「なぁーーーーぬぅーーーーー!?!?」と光の早さでレスを頂いた。(初期状態の)Arduino開発環境だと、11番のピンは他の用途(デバッグ?)にも使われているらしく、「出力ピンとしては使えない」そうだ。つまり、「入力ピンとしては使える」から、今まで自分がつくっていたキー入力などの回路は普通に動いていたのだ。
void setup() {
pinV32_DisconnectDebug(PD_1); // Disable SWIO (the argument is not "PD1")
pinMode(11, OUTPUT); // Configure output
}
void loop() {
digitalWrite(11, HIGH);
delay(1000);
digitalWrite(11, LOW);
delay(1000);
}
というわけで、公式サイトに「11ピンを使用するにはpinV32_DisconnectDebug(PD_1)が必要です。SWIOが無効化されます。」という注意書きと上記のサンプル・プログラムが加筆されることになった。自分の報告が、他のユーザーさんの役にたつのかもしれないと思うと嬉しい。
印刷所に注文してあった新刊・ソリティア・ブックス『星辰の刻』が到着して、ドキドキしながら箱の封をきった。ククトニアンとしては8冊目の同人誌になるけれど、何度経験しても、この瞬間は手が少し震えてしまう。全部同じ仕様の本にすれば楽なのはわかってるけど……つまらない。ついつい何かを変えてしまう。
今回はクトゥルフ神話がモチーフということもあり、レトロ感を出すために表紙を「両更クラフト紙」にした。本文はゲームだから、なんども繰り返して読んでもらう必要がある。こちらは、ちょっとだけ厚めの「上質 90kg」を採用した。無印良品で売っているノートのような素朴な手触りが気に入っている。読み物じゃなくって、ゲームだから異質にしたかった。
ゲーム業界デビューはアナログゲームだったけれど、すぐにパソコン用のゲーム開発に移行してしまって手がけるチャンスがなかった。三十七年ぶりにアナログゲームの世界に戻ってきた気分だ。
秋葉原にあるロボスタディオンの展開が素敵だ。290円マイコンのニュース記事をみたロボスタディオンが、SNSで「弊店のタバコ用自販機で売りたいッ!!!」と金曜日に呟いた。それを見て開発者のUmetaさんが連絡を取ったらしいのだけれど、なんと! 翌週の火曜日には現実になっていた。このスピード感にワクワクするし、自分も早くアウトプットしたいなと、じっとしていられなくなった。
自分のアウトプットといえば、自作LEDゲーム機『ゲームベーダー』の開発が年内の目標になっている。携帯ゲーム機『Tiny CH32 Pad Lite』を自分の手でブレッドボードに再現してから、「自分ならこういう仕様にするかも?」といったアイデアが、次々と浮かぶようになった。
仕様を書き出したり、ChatGPTに相談していると時間を忘れてしまう。でもいろいろ盛り込もうとすると挫折しがち。だから『雑に作る』の精神で、まずは何か動くものをつくってみようと思っている。
携帯ゲーム機『Tiny CH32 Pad Lite』(試作バージョン)にソフトウェアをインストールする為に、いよいよ『PlatformIO』をインストールしてみる。「そう簡単にはいかないだろうなあ」と覚悟はしていたけれど、本当に難しくって半日以上悪戦苦闘しても、まるで光が見えなかった。
正直なところ、あまりにもうまくいかないので、SNSに「絶望しかないぞw やっぱりArduino環境から、ちょっとずつ勉強するしかないんだな」と投稿して一度は投げ出してしまったくらいだ。
でも翌日のスッキリとした頭で手順を一から見直し、細かくメモを作りながら再インストールをしたらなんとか『PlatformIO』を動かすことができた。モノクロのかわいらしい『Tiny Pacman』とご対面。「なんでスコアがないんだ!」とか「行き止まりがあるなんて!」などと文句を言いながらも繰り返しプレイしてしまった。
しばらく楽しんだ後、『Tiny Pacman』のプロジェクトをじっくりと眺めた。ゲームロジック部分のソースコードは469行。細かくチェックできる規模なのが嬉しい。その後で回路図もあわせて確認したら意外にもシンプルで、「もしかしたら、ブレッドボードでも再現できるかも?」という考えが浮かんできた。
「ボタン周りにあるコンデンサーがたりないけど、たぶん安定動作させる為の補助だろう……」
根拠が乏しいままに組み立ててみたら、あっさりと動いた。ビックリ。Arduboyの組み立てやブロック崩し制作の経験が活きているのかも?
ブレッドボード版のことをUIAPのコミュニティに報告したら、「最高にグレイトでパーフェクトな使い方してくれてます(´゚д゚`)ありがて〜〜」という熱いコメントを開発者のUmetaさんから頂いた。組み立てただけだから申し訳ないなあ。
What is PlatformIO?
A place where Developers and Teams have true Freedom! No more vendor lock-in!
夢がありそうな開発環境だ。公式サイトがなくなったり、法外な値上げをする事例がたまにあるので、こういう選択肢が増えるのは大歓迎です。
まずはChatGPTに相談しながらインストールしてみるつもり。事前にざっと調べた感じでは「自分のようなカジュアルな使い方をする分には、『Arduino IDE』で十分なのだろうなあ」と思っているのだけど……。
『Arduino IDE』ですらよくわかっていないのに、あたらしいソフトを試すのは、ちょっと怖いけれど、大好きなゲームのためなら頑張ってみようと思う。
今日は『わたしの文芸創作』(著:石田千)を読んだ。ストレートなタイトルと、南伸坊さんの装丁に惹かれた。最初は「よくある創作術なのかなあ?」と勝手に思い込み目次を眺めたら、新型コロナウイルスの感染が広がった2020年度に、東海大学の文化社会学部文芸創作学科でおこなった遠隔授業の記録だった。
石田千さんの遠隔授業はメールのやりとりで行われた。毎週丁寧な説明と共に創作課題がだされて、メールで提出してもらうスタイルだ。この『わたしの文芸創作』には、講師側の説明メールが、ほぼ全文掲載されている。
こうやって一冊の本になっているとあっさりと読めてしまうが、実際にやるのは難しかったはずだ。コロナ禍の中で毎週課題を考え、気を配りながらメールを書いて、何十人もいる不安を抱えた生徒達の質問や提出物に向きあうのだから。
当時は自分もゲーム専門学校の講義はオンラインにせざるをえなかった。自宅にパソコンがない生徒もいるし、試行錯誤の繰り返しだったから、とても共感しながら読めた。どの学校も大変だったんだなあ……。