-
作品概要
•RISC-Vマイコン「CH32V003」を搭載した8×8 LED制御ボード
•電源はコンパクトなCR2032コイン電池で駆動
•英数字のスクロール表示が可能(プログラム制御) -
特徴
•青色LEDが優しく光り、見ているだけで心が落ち着く
•WCH-LinkEデバッガと接続することで書き込み・デバッグが可能
•3Dプリンタ製の専用ケースで持ち運びもスマート -
ハードウェアの主な仕様
• マイコン:CH32V003(低消費電力・高性能なRISC-Vベース)
• LED表示:8×8の青色LEDマトリクスを制御可能
• 電源:CR2032ボタン電池で駆動、屋外でも気軽に持ち運び可能
WCH-LinkEを使った書き込み・デバッグ対 -
RISC-Vマイコン CH32V003でLチカボード ボード概要
LED実装は、外部スイッチを下にしてアノード側が上側に来ます。
書き込み方法(WCH-LinkE使用)
• 接続ピン:
・5V 書き込み電源供給 供給する端子は5V側につないでください。
・GND
・SWDIO(デバッグ・書き込み用)
• 操作手順:
・WCH-LinkEと基板を接続
・スイッチを「WRITE」側に倒すことで書き込み可能
注意点
• PD7ピン(NRST)について:通常はリセット機能を持つNRSTピンですが、
本ボードではGPIOとして使用しています
・そのため、外部リセット信号は使用できません
コード解説:CH32V003によるLED文字スクロール表示
このプログラムは、CH32V003マイコンを使って8×8の青色LEDマトリクスに英数字メッセージをスクロール表示するものです。Arduino記述で、視覚的に美しく、イベント展示にも最適です。
主な機能と構成
-
ピン設定
・行ピン(縦方向):PA1〜PD0
・列ピン(横方向):PC1〜PA2
→ マトリクスLEDの各ピクセルを制御するための配線 -
表示文字列
「HELLO NT TOKYO 2025.9.6. BLINKING WITH LOVE. DIY OR DIE」
→ メッセージをスクロール表示 -
フォント定義
・英大文字(A〜Z)、数字(0〜9)、スペース、ピリオドを8×8ドットで定義
・文字を左に90度回転させて、縦スクロールに対応 -
スクロール処理
・文字列をバッファに展開し、1列ずつ表示
・スクロール速度は scrollDisplay(100) で調整可能(100ms)
#include <Arduino.h>
// 行ピン (上端 PA1 → 下端 PD0)
const uint8_t rawPins[8] = { PA1, PD7, PD6, PD5, PD4, PD3, PD2, PD0 };
// 列ピン (左端 PC1 → 右端 PA2)
const uint8_t colPins[8] = { PC1, PC2, PC3, PC4, PC5, PC6, PC7, PA2 };
// 表示文字列
const char message[] =
" HELLO NT TOKYO 2025.9.6. BLINKING WITH LOVE. DIY OR DIE ";
// フォント定義(スペース、A~Z、0~9、ピリオド)
const uint8_t font[][8] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x3C,0x42,0x81,0x81,0xFF,0x81,0x81,0x81}, // A
{0xFE,0x81,0x81,0xFE,0x81,0x81,0x81,0xFE}, // B
{0x7E,0x81,0x80,0x80,0x80,0x80,0x81,0x7E}, // C
{0xFC,0x82,0x81,0x81,0x81,0x81,0x82,0xFC}, // D
{0xFF,0x80,0x80,0xFC,0x80,0x80,0x80,0xFF}, // E
{0xFF,0x80,0x80,0xFC,0x80,0x80,0x80,0x80}, // F
{0x7E,0x81,0x80,0x80,0x8F,0x81,0x81,0x7E}, // G
{0x81,0x81,0x81,0xFF,0x81,0x81,0x81,0x81}, // H
{0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x7E}, // I
{0x1F,0x06,0x06,0x06,0x06,0x86,0x86,0x7C}, // J
{0x81,0x82,0x84,0xF8,0x84,0x82,0x81,0x81}, // K
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF}, // L
{0x81,0xC3,0xA5,0x99,0x81,0x81,0x81,0x81}, // M
{0x81,0xC1,0xA1,0x91,0x89,0x85,0x83,0x81}, // N
{0x7E,0x81,0x81,0x81,0x81,0x81,0x81,0x7E}, // O
{0xFE,0x81,0x81,0xFE,0x80,0x80,0x80,0x80}, // P
{0x7E,0x81,0x81,0x81,0x89,0x85,0x82,0x7D}, // Q
{0xFE,0x81,0x81,0xFE,0x84,0x82,0x81,0x81}, // R
{0x7E,0x81,0x80,0x7E,0x01,0x81,0x81,0x7E}, // S
{0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18}, // T
{0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x7E}, // U
{0x81,0x81,0x81,0x81,0x42,0x24,0x18,0x18}, // V
{0x81,0x81,0x81,0x99,0xA5,0xC3,0x81,0x81}, // W
{0x81,0x42,0x24,0x18,0x24,0x42,0x81,0x81}, // X
{0x81,0x42,0x24,0x18,0x18,0x18,0x18,0x18}, // Y
{0xFF,0x02,0x04,0x08,0x10,0x20,0x40,0xFF}, // Z
{0x7E,0x81,0x89,0x91,0xA1,0xC1,0x81,0x7E}, // 0
{0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x7E}, // 1
{0x7E,0x81,0x01,0x02,0x0C,0x30,0x40,0xFF}, // 2
{0x7E,0x81,0x01,0x1E,0x01,0x01,0x81,0x7E}, // 3
{0x02,0x06,0x0A,0x12,0x22,0xFF,0x02,0x02}, // 4
{0xFF,0x80,0x80,0xFE,0x01,0x01,0x81,0x7E}, // 5
{0x3E,0x40,0x80,0xFE,0x81,0x81,0x81,0x7E}, // 6
{0xFF,0x01,0x02,0x04,0x08,0x10,0x20,0x20}, // 7
{0x7E,0x81,0x81,0x7E,0x81,0x81,0x81,0x7E}, // 8
{0x7E,0x81,0x81,0x81,0x7F,0x01,0x02,0x7C}, // 9
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00} // .
};
const uint8_t* getFont(char c) {
if (c == ' ') return font[0];
if (c >= 'A' && c <= 'Z') return font[c - 'A' + 1];
if (c >= '0' && c <= '9') return font[c - '0' + 27];
if (c == '.') return font[37];
return font[0];
}
// 90°左回転 (左右反転なし)
void rotateLeft90(const uint8_t* src, uint8_t* dst) {
for (int y = 0; y < 8; y++) {
dst[y] = 0;
for (int x = 0; x < 8; x++) {
// 元 [x][y] が新 dst[y][7-x] に来る
if (src[x] & (1 << (7 -y))) {
dst[y] |= (1 << ( x));
}
}
}
}
uint8_t scrollBuffer[512];
int scrollLen = 0; // 実際に書き込まれたデータ長
void buildScrollBuffer(const char* msg) {
int len = strlen(msg), pos = 0;
for (int i = 0; i < len; i++) {
uint8_t tmp[8];
rotateLeft90(getFont(msg[i]), tmp);
// 文字データ 8列
for (int c = 0; c < 8; c++) {
if (pos < sizeof(scrollBuffer)) scrollBuffer[pos++] = tmp[c];
}
// 文字間隔 1列
if (pos < sizeof(scrollBuffer)) scrollBuffer[pos++] = 0x00;
}
// 末尾スペースを文字間隔と同じ1列だけ追加
if (pos < sizeof(scrollBuffer)) scrollBuffer[pos++] = 0x00;
// 実データ長を記録
scrollLen = pos;
}
void scrollDisplay(uint16_t speed) {
int total = scrollLen; // 修正:全長ではなく実データ長を使う
// 0 → total-8 で左→右に流す
for (int offset = 0; offset <= total - 8; offset++) {
unsigned long start = millis();
while (millis() - start < speed) {
for (int row = 0; row < 8; row++) {
digitalWrite(rawPins[row], LOW);
for (int col = 0; col < 8; col++) {
bool on = (scrollBuffer[offset + col] >> row) & 0x01;
digitalWrite(colPins[col], on ? HIGH : LOW);
}
delayMicroseconds(1000);
digitalWrite(rawPins[row], HIGH);
for (int col = 0; col < 8; col++)
digitalWrite(colPins[col], LOW);
}
}
}
}
void setup() {
for (int i = 0; i < 8; i++) {
pinMode(rawPins[i], OUTPUT); digitalWrite(rawPins[i], HIGH);
pinMode(colPins[i], OUTPUT); digitalWrite(colPins[i], LOW);
}
buildScrollBuffer(message);
}
void loop() {
scrollDisplay(100); // スクロール速度(ms)
}
コード解説:CH32V003で動く「ランダム点灯LEDマトリクス」
このプログラムは、CH32V003マイコンを使って8×8の青色LEDマトリクスにランダムな光のパターンを表示するものです。ArduinoIDEで、シンプルながら視覚的に心地よい「癒しの点滅」を実現しています。
#include <Arduino.h>
// RAWピン(行)
const uint8_t rawPins[8] = {PA1, PD7, PD6, PD5, PD4, PD3, PD2, PD0};
// カラムピン(列)
const uint8_t colPins[8] = {PC1, PC2, PC3, PC4, PC5, PC6, PC7, PA2};
// 表示用バッファ(8x8)
bool ledMatrix[8][8];
void setup() {
// 初期化
for (int i = 0; i < 8; i++) {
pinMode(colPins[i], OUTPUT);
digitalWrite(colPins[i], LOW); // 列はLOWで消灯
pinMode(rawPins[i], OUTPUT);
digitalWrite(rawPins[i], HIGH); // 行はHIGHで消灯
}
randomSeed(millis()); // ランダム初期化
}
void loop() {
// ランダムに8か所選んで点灯
clearMatrix();
for (int i = 0; i < 8; i++) {
int x = random(0, 8);
int y = random(0, 8);
ledMatrix[y][x] = true;
}
// 0.5秒間表示
unsigned long start = millis();
while (millis() - start < 500) {
displayMatrix();
}
}
// LEDマトリクスを表示(1行ずつスキャン)
void displayMatrix() {
for (int y = 0; y < 8; y++) {
digitalWrite(rawPins[y], LOW); // 行をLowに(点灯可能)
for (int x = 0; x < 8; x++) {
digitalWrite(colPins[x], ledMatrix[y][x] ? HIGH : LOW);
}
delay(2); // スキャン時間(ちらつき防止)
// 行を戻す
digitalWrite(rawPins[y], HIGH);
for (int x = 0; x < 8; x++) {
digitalWrite(colPins[x], LOW);
}
}
}
// バッファ初期化
void clearMatrix() {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
ledMatrix[y][x] = false;
}
}
}
// 行ピン (上端 PA1 → 下端 PD0)
const uint8_t rawPins[8] = { PA1, PD7, PD6, PD5, PD4, PD3, PD2, PD0 };
// 列ピン (左端 PC1 → 右端 PA2)
const uint8_t colPins[8] = { PC1, PC2, PC3, PC4, PC5, PC6, PC7, PA2 };
PushSW=PD0に割り当て。
初期値 HI、Push LO
ボタンを押したらLOになるので
立下りエッジでスイッチ入力を判定する