HakoHiroのアイコン画像

球体残像表示装置  

HakoHiro 2021年02月28日に作成

概要

回転するボールの外側にテープLEDを配置して、回転により 残像表示をします。(Povとも、バーサライタとも呼びます)
とりあえずは時刻表示からと思っていましたが、今回はテストパターンの描画までで、キャンペーンの締め切り時間切れになってしまいました。
全てにおいて完成度は低いですが、とりあえず第一報として投稿します。(キャンペーンの賞品が欲しいので・・・)

※非常に長文です。お時間のあるときに御覧ください。

コンセプト

  • メカ的にはあまり凝らない。ガチガチに固めたものにはしない。
  • 駆動はメカ系で行う。昔の分銅時計のイメージで出来れば良い。
  • 表示の安定性は、Atom matrixの角速度検知で行う
  • ボールからの外部への配線は無しとする。
    そもそもケーブルがついていたら回転できない!!
  • ケーブルを使えない為、以下を採用
    • 状態モニターにはESP-NOWによるWifi通信
    • Atomプログラムの修正には、OTA(On The Air)によるWifi経由の書換
      プログラム修正のときだけケーブルを繋ぐという手もあるが、やはり繋がないで書き換えできるのは便利!!
  • テープLEDには、SPIで高速アクセスできる APA102 5050 LEDテープを使用

概略図

キャプションを入力できます 
マブチモーターは、ソフト調整時に定速回転をさせるためです。定電圧電源につないで、回転数を調整できます。

実は当初、Leafonyのコンテストに、この球体残像表示を企画していました。M5StickCとかでは、このLEDをSPIで駆動できていたのですが、Leafonyでは駆動できませんでした。Leafonyは3.3V系で5Vの出力系を取るのが困難なので断念いたしました。当然工夫すれば5V系も可能なのですが、シンプルさを失ってしまいます。その点、M5Atomは小型で、GROVE端子は5V SPIを使用でき、なんとかまとまりました。

機構系

M5Atom、電源を内蔵し、外部に配線の出ない状態で回転しなければなりません。
そこで、セパタクローという籐で編んだボールを元にした編み物のボールを作成。その中に、ベニア板(シナ合板)から切り出したベースと、回転軸を入れました。
編み物のボールなので、編んだ後で、編み目をずらしてやれば、これらのものを入れることが出来ます。LEDのテープは ボールの外周部に配置しました。
以下に部品、組み立て手順を説明します。

セパタクローボール

紙テープで編んだボールです
9世紀の昔から東南アジアの各国各地で伝えられてきた伝統スポーツのセパタクローで使われるボール。元は、籐製。
それを、百円ショップの紙テープで編んで作成しました。なぜこれを選んだかと言うと、あまりガチガチの機構にしたくなかった為です。中空のボールに電子系、電池を入れてまともに動くものを真面目に制作するとかなりの手間になって、かつ変更が大変になります。この編物だと、編んだ後から色々物を入れれるし、外からアクセスもしやすい。電池交換も外からアクセスして簡単に出来ます。要は手を抜きたかったと言うことです。
ベースを中に入れた状態

【参考資料】
日本セパタクロー協会
http://jstaf.jp
正多面体クラブ 「紙バンドで作るセパタクローボール」
http://polyhedra.cocolog-nifty.com/blog/2013/07/post-e7d8.html

回転軸機構

回転機構台座
アルミパイプ両端にベアリングを設置、それを台座に取り付けます。
電池 + AtomMatrix + 電源Swのベース
M5Atom Matrixと単三電池を設置するベースを、ベニア板からレーザ加工機で切り出します。
回転軸に組み込み、LEDを取付
そしてそのベースを入れたセパタクローボールを取り付けます。(回転軸にはめ込む)これも、編み物ボールの融通性がものをいいます。セパタクローボールの外側には テープLEDを設置します。
台座の横側面にはマブチモーター用の取付台座が見えています。

レーザー加工機

SMART DIYsさんのEcher Laser 3.5Wを使用しています。
https://www.smartdiys.com
当方のものづくりには欠かせない装置になっています。イラストレーターで作成した「svg」ファイルを読み込ませて加工します。精度が良いため、繰り返し加工すれば数ミリの板も切り出せます。購入時に 3Dプリンタとどっちにしようかと迷っていたのですが、当方の用途にはこちらのほうが良かったと思います。なにせ、錫の鋳型に木や紙を使えるので・・・・
上の写真の組立てた状態からでも、全てばらして取り出せます。特に回転軸との嵌合は接着とかは一切使っていませんので。

電気系

電気系としては、Atom MatrixとLED、そして単3電池だけです。

LED

APA102 5050 LED
SPIで入力でき、高速。かつLEDの配置密度が高いことから選定しました。
アマゾンで4,000円弱(1m長)、ただし到着まで2週間ほどかかります。

ところで、最初に一個LEDを焼いてしまいました。到着したLEDテープについていた配線の色を見て、ついつい 赤=Vcc 黒=GRNDと思いこんで、配線してしまいました。煙が出て実物確認した所、色が逆でした。恐るべし中華電子部品!!皆さんもこんなミスはしないように注意しましょう。

M5Atom Matrix

選定理由

  • サイズが小さい
  • IMU6886内蔵(Atom liteには内蔵されていない)
  • GROVE端子で5V SPIが使用できる

100円玉と比べてこの大きさ
右端はAtom lite(ちょっと薄い)

電源

単3電池を3個直列につないで、On/Offスイッチを介して、Atom Matrixの背面 5V ,Gnd端子につないでいます。

ソフトウェア

ソフトソースは、詳細を吟味しておりません。動作したこともある一例と理解ください。

デバッグ環境・ツール

デバッグ環境
なにせ、ボールの中のAtomは、回転するので、シリアルケーブルを繋げれない。そこで、回転状況の確認に ESP-NOW、プログラムの修正&調整の為に OTAを組込みました。これで、ケーブルを繋がなくても 回転させている状態で、状況モニター、プログラム修正が WiFi経由で出来る様になるはずでした。ところが、ESP-NOWとOTAが共存できませんでした。色々解決策を模索しましたが、時間切れでした。ESP-NOWは状態確認のさいにだけ使うのでとりあえず OTAを組込んで開発しています。

ESP-NOW

ESP-NOWとはなに?というところからですが、
ESP32同士の直接通信です。Wi-Fiを使って 相手のMACアドレスを指定して通信する方法です。

プログラムを組む上で一番参考になったのは、英文ですが、

AtomMatrix送信側のプログラム

/* based on Rui Santos Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/ IMU6886の有無Checkは省略 Atom Matrix: 有り Atom lite: 無し */ #include <M5Atom.h> #include <WiFi.h> #include <esp_now.h> // REPLACE WITH YOUR RECEIVER MAC Address //uint8_t broadcastAddress[] = {0x50, 0x02, 0x91, 0x8E, 0xF9, 0x5C}; uint8_t broadcastAddress[] = {0x50,0x02,0x91,0x8e,0x9e,0x21}; // Structure example to send data // Must match the receiver structure typedef struct struct_message { unsigned long msec; float pitch; float roll; float yaw; } struct_message; // Create a struct_message called myData struct_message myData; struct_message gyroData; // callback when data is sent void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } void setup() { M5.begin(true, false, true); // Serial:Enable I2C:Disable DisplayLED:Enable delay(50); M5.dis.drawpix(13, 0x400000); // Red M5.IMU.Init(); M5.IMU.SetGyroFsr(M5.IMU.GFS_2000DPS); // Init Serial Monitor Serial.begin(115200); delay(1000); // Set device as a Wi-Fi Station WiFi.mode(WIFI_STA); // Init ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } M5.dis.drawpix(7, 0xf00000); // WiFi OK >> Green // Once ESPNow is successfully Init, we will register for Send CB to // get the status of Trasnmitted packet esp_now_register_send_cb(OnDataSent); // Register peer esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; // Add peer if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("Failed to add peer"); return; } } void loop() { // Set values to send myData.msec = millis(); M5.IMU.getGyroData( &gyroData.pitch, &gyroData.roll, &gyroData.yaw); M5.IMU.getAhrsData( &myData.pitch, &myData.roll, &myData.yaw); // Serial.printf("%09d %+04.2f,%+04.2f,%+04.2f \n", myData.msec, myData.pitch, myData.roll, myData.yaw); myData.pitch = gyroData.roll; myData.roll = gyroData.yaw; // Send message via ESP-NOW esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&myData, sizeof(myData)); if (result == ESP_OK) { Serial.println("Sent with success"); } else { Serial.println("Error sending the data"); } delay(10); }

上記のPlatformio.ini

[env:m5stick-c] platform = espressif32 board = m5stick-c framework = arduino upload_speed = 115200 monitor_speed = 115200 lib_deps = m5stack/M5Atom@^0.0.1 fastled/FastLED@^3.4.0

受信側M5StickC

#include <M5StickC.h> #include <esp_now.h> #include <WiFi.h> void OnDataRecv(const uint8_t* mac, const uint8_t* data, int data_len) { Serial.printf("Recv from:%02x:%02x:%02x:%02x:%02x:%02x Data:%d\r\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], *data); } void setup() { M5.begin(); M5.Lcd.setRotation(1); M5.Lcd.setCursor(0, 0, 1); M5.Lcd.setTextColor(BLUE); M5.Lcd.setTextSize(2); M5.Lcd.print("Start ESP-Now GetData"); Serial.begin(115200); delay(100); WiFi.mode(WIFI_STA); WiFi.disconnect(); esp_now_init(); esp_now_register_recv_cb(OnDataRecv); delay(100); Serial.println("Data Get Start"); } void loop() { taskYIELD(); }

WiFi-MACaddress取得の例

/* * https://github.com/espressif/arduino-esp32/issues/932 */ #include <M5StickC.h> #include "esp_system.h" void setup() { // put your setup code here, to run once: Serial.begin(115200); delay(10000); // Get MAC address for WiFi station uint8_t baseMac[6]; esp_read_mac(baseMac, ESP_MAC_WIFI_STA); char baseMacChr[18] = {0}; sprintf(baseMacChr, "%02X:%02X:%02X:%02X:%02X:%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]); Serial.print("MAC: "); Serial.println(baseMacChr); } void loop() { // put your main code here, to run repeatedly: }

注意)接続形式が ステーションモード、アクセスポイントモードによって、MACアドレスとMACアドレス取得関数が異なります。上記はステーションモードの場合です。

OTA(On The Air)

On The Airとは、WiFi又はBluetoothを経由してファームウェアを書き換える方法です。(それにしてもこの略号はあんまりだと思いますが・・・)
ESP32のArduino 環境では、[ファイル]-[スケッチ例]-[ArduinoOTA]-[BasicOTA] とすることで、サンプルを参照することができます。

参考記事 トランジスタ技術SPECIAL No,144 Wi−Fiアルデュイーノ無線活用
Webでは、
[IoT] PlatformIO を使って ESP8266 を OTA できるまでの手順おさらい
https://software.small-desk.com/diy/2021/01/05/iot-platformio-esp8266-ota-stepbystep/
が参考になりました。
特に、Platformioではiniの修正が必要になります。

AtomMatrixでのOTA

#include <M5Atom.h> #include <WiFi.h> #include <ArduinoOTA.h> const char* ssid = "自分のWiFiルーターのSSID"; const char* password = "自分のWiFiルーターのパスワード"; // function prototype void setupExceptOTA(void); void loopExceptOTA(void); IPAddress ip(192,168,11,103); //設定したい IP Addr. IPAddress gw(192,168,1,1); //Gateway IP Addr. IPAddress subnet(255,255,255,0); IPAddress DNS(192,168,1,1); //DNS IP Addr. uint8_t DisBuff[2 + 5 * 5 * 3]; void setBuff(uint8_t Rdata, uint8_t Gdata, uint8_t Bdata) { DisBuff[0] = 0x05; DisBuff[1] = 0x05; for (int i = 0; i < 25; i++) { DisBuff[2 + i * 3 + 0] = Rdata; DisBuff[2 + i * 3 + 1] = Gdata; DisBuff[2 + i * 3 + 2] = Bdata; } } void setup() { M5.begin(true,false,true); // serial:True I2C:False Display:True Serial.begin(115200); setBuff(0,0x10,0); // LED 弱い Green M5.dis.displaybuff(DisBuff); // Program Start表示 WiFi.mode(WIFI_STA); WiFi.config(ip,gw,subnet); // IP address等の設定 WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { //Serial.println("Connection Failed! Rebooting..."); setBuff(0x10,0,0); // LED 弱い赤 M5.dis.displaybuff(DisBuff); // 接続NG Rebooting delay(5000); ESP.restart(); setBuff(0,0,0); // LED 消灯 M5.dis.displaybuff(DisBuff); } setBuff(0,0,0); // LED all Off M5.dis.displaybuff(DisBuff); ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() //Serial.println("Start updating " + type); setBuff(0,0,0x10); // LED 弱いBlue M5.dis.displaybuff(DisBuff); // OTA Start }) .onEnd([]() { setBuff(0,0,0); // LED 消灯 M5.dis.displaybuff(DisBuff); // OTA 終了 }) .onProgress([](unsigned int progress, unsigned int total) { //Serial.printf("Progress: %u%%\r", (progress / (total / 100))); unsigned int ledNum = progress / total * 24; M5.dis.drawpix(ledNum,0); //進捗に応じ LED消灯 全部消えると完了 }) .onError([](ota_error_t error) { /* Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); */ uint8_t ledNum; switch (error) { case OTA_AUTH_ERROR: // Auth Failed >> 1列目赤 for (ledNum=0; ledNum<5; ledNum++) {M5.dis.drawpix(ledNum,0x10);} break; case OTA_BEGIN_ERROR: // Begin Failed >> 2列目赤 for (ledNum=5; ledNum<10; ledNum++) {M5.dis.drawpix(ledNum,0x10);} break; case OTA_CONNECT_ERROR: // Connect Failed >> 1列目赤 for (ledNum=10; ledNum<15; ledNum++) {M5.dis.drawpix(ledNum,0x10);} break; case OTA_RECEIVE_ERROR: // Receive Failed >> 1列目赤 for (ledNum=15; ledNum<20; ledNum++) {M5.dis.drawpix(ledNum,0x10);} break; case OTA_END_ERROR: // End Failed >> 1列目赤 for (ledNum=20; ledNum<25; ledNum++) {M5.dis.drawpix(ledNum,0x10);} break; default: break; } }); ArduinoOTA.begin(); setupExceptOTA(); // Serial.println("Ready"); // Serial.print("IP address: "); // Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); loopExceptOTA(); } void setupExceptOTA() { M5.dis.drawpix(18,0x100000); //Green弱め } int i = 0; void loopExceptOTA() { M5.dis.drawpix(i,0x200000); //Green弱め delay(1000); i++; M5.dis.drawpix(i-1,0); // 消灯 if (i>=25) { i=0;} // M5.dis.drawpix(0,0x004000); //Redちょっと弱め // delay(2000); // M5.dis.drawpix(0,0x000040); //Blueちょっと弱め // delay(2000); }

Platformio.ini

[env:m5stick-c] platform = espressif32 board = m5stick-c framework = arduino ;upload_speed = 115200 upload_protocal = espota ; OTA 指定 upload_port = 192.168.11.103 ; OTA 対象とするIP指定 lib_deps = m5stack/M5Atom@^0.0.1 fastled/FastLED@^3.4.0

OTAを使用する場合、upload_protocal,upload_portを指定する。
Arduino IDEでは、設定が呼び出されるようですが、OTAでは使っていないのでよくわかりません。

ESP-NOWとOTAの共存

上記のプログラムで、ESP-NOWとOTAと各単体で動作は確認OKでしたが、いざ共存しようとするとうまくいきません。ステーションモードとアクセスポイントモードをうまく組み合わせて出来るのではと考えて色々トライしましたが、時間切れとなってしまいました。
そもそも、ESP-NOWの利用方法は、角度、角速度情報の取得ですので、BluetoothSirialでも良いはずですが OTAと共存するとプログラムサイズの制限が出ないかと考えて適用しませんでした。
こういう機構では、OTAは必須ですので、共存がどうしても無理なら BluetoothSirial、UDP通信等他の方法を考えていこうとも考えております。

角速度検知

当初、getAhrsData関数を利用して、pitch,roll,yawの姿勢データを取得しようと考えていました。
確かに上記でデータは取れるのですが、下記のArduino IDE シリアルプロッターのグラフを見ればわかるように、当たり前ですが、プラマイ180°のノコギリ波となり、処理が難しいことと、ドリフトが大きいので、getGyroData関数により、z軸の角速度を求めることにしました。

Arduino IDE シリアルプロッターでのyawData10msec単位 横軸1目盛=1秒

Timer割込、割込周期変更

Timer割込により、その時の角速度を求め、その角速度の値により割込周期を変え、表示を安定させようと考えました。
割込周期はレジスタに出ていてそれを書き換えればいいだろうと思っていたのですが、標準でその様な関数は無く、とりあえずタイマ割込毎に、タイマをDetach,Attachをするというダサい方式で実現してみました。

Timer割込周期変更確認テスト(LED30個でテストを実施)

/ Timer駆動 APA102  // test 30LED 動作OK #include <M5Atom.h> #define NUM_LEDS 30 #define CLOCK_PIN 26 #define DATA_PIN 32 hw_timer_t* timer = NULL; volatile SemaphoreHandle_t timerSemaphore; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; volatile uint32_t isrCounter = 0; volatile uint32_t lastIsrAt = 0; volatile uint64_t cyclecounter = 10000; // 10msec void IRAM_ATTR onTimer() { // Increment the counter and set the time of ISR portENTER_CRITICAL_ISR(&timerMux); isrCounter++; lastIsrAt = millis(); portEXIT_CRITICAL_ISR(&timerMux); // Give a semaphore that we can check in the loop xSemaphoreGiveFromISR(timerSemaphore, NULL); // It is safe to use digitalRead/Write here if you want to toggle an output } CRGB leds[NUM_LEDS]; void setup() { FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB, DATA_RATE_MHZ(80)>( leds, NUM_LEDS);           //本当にこのサイクルで動いているのかどうか不明 LEDS.setBrightness(80); // Timer 設定 timerSemaphore = xSemaphoreCreateBinary(); // バイナリセマフォ作成 timer = timerBegin(0, 80, true); // timer:0,// Set 80 divider for prescaler timerAttachInterrupt(timer, &onTimer, true); timerAlarmWrite(timer, cyclecounter, true); // 10msec timerAlarmEnable(timer); // Timer有効化 } void loop() { if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE) { uint32_t isrCount = 0, isrTime = 0; cyclecounter += 1000;          // 1msec周期を長くする // Read the interrupt count and time portENTER_CRITICAL(&timerMux); isrCount = isrCounter; isrTime = lastIsrAt; timerDetachInterrupt(timer); timerAttachInterrupt(timer, &onTimer, true); timerAlarmWrite(timer, cyclecounter, true); // timerAlarmEnable(timer); // Timer有効化 portEXIT_CRITICAL(&timerMux); // Print it // Serial.print("onTimer no. "); // Serial.print(isrCount); // Serial.print(" at "); // Serial.print(isrTime); // Serial.println(" ms"); for (int i = 1; i < NUM_LEDS; i++) { leds[i] = 0x001000; leds[i-1] = 0; FastLED.show(); } } }

確かにこれで、Timer割込周期は変わっていることを確認しました。
ちなみに、timerAlarmWrite(timer, cyclecounter, true); のtrueをfalseにするとOneShotタイマーになるはずなのですが、うまくいきませんでした。ただし、確認不充分ですので 怪しい情報と思ってください。

LED SPI駆動

上記にテスト駆動のソースを上げているが、本当にこの設定が正しいのかどうかは不明です。
あまり信用しないでください。

動作状況

ここに動画が表示されます

あまり、残像がうまく撮影できていないのですが、動画を掲載しておきます。

現状の問題点

  • ESP-NOWとOTAの共存
  • ESP-NOWの代替えとしてのBLE-Sirial or 他の方法
  • Timer割込の周期変更がダサダサ
  • データ解析方法
    Arduino IDEのシリアルプロッターは、さっとデータ確認するにはいいのだが、スケーリングがどんどん変わる。複数の系列データの取り扱いは出来るのだが、スケーリング等にやはり問題がある。
    Pythonでシリアルデータのプロット化の良いソフトは無いものですかね?
    Jupyter Lab(notebook)で動けば最高なのですが、自分で作るのは面倒くさいですしね。
  • ビデオ動画のとり方
    目視ではもっとよく見えるのですがね。残像表示で公表する場合、これが一番重要な気がします。
    elchikaメンバーの方なにか良い知恵はないですかね?
    Povの第一人者の方もメンバーにいるみたいですが、アドバイスを頂ければ幸いです。
  • 電池の持ちor 電圧チェック
    電池がなくなってくれば、あちこちおかしくなってくるのですが、特に開発中は 自分のプログラムを疑う前に、電池を疑ってしまいます。(プログラムミスの方が90%)それを防ぐためにも 電圧チェックを入れたいと思います。また、充電池のほうが良いのかなとも思います。幸いにして回転機構がスムーズに動いていますので、重量バランスさえ取れればもっと重いものでも搭載可能です。かえって重いほうが回転安定性が良いかもしれません。
    先々は、低消費電力化も図らねばとも考えていますが、遠い先の話です。

感想

  1. APA102 LED
    物理的密度も高く、その点ではいいのですが、まだ全体性能評価までこちらが至っていません。
  2. ESP-NOW
    1対多の通信もでき、面白い通信規格です。最近ESP32が家の中にゴロゴロしているので、もっと使いみちを考えてみようとも思っています。
  3. OTA
    こんな機構では、OTAは必須ですね。また、OTAで書き換えたほうがUSBシリアルよりも早いような気がします。実際測定してみればよいのですが、次回報告する機会があったときにでもご報告します。
  4. 角速度検知
    安定性、再現性の確認が全然出来ていません。姿勢データのyawデータは、オフセットが酷いのですが、ライブラリの定数をいじって良くなる場合もありますが、これも確認が不充分な状況です。

今後の課題

何分にも完成度が低いので課題はいっぱいあるのですが、以下のことをやっていきたいと思っています。
ただ、そこそこ作ってしまうと やる気が無くなるタイプなのでどこまでできるやら・・・・・

  • パターンエディタ
    制御Softの次は、これが問題になると思います。 
    球体のパターンを作るのに、出来るだけ既存のソフトを利用して簡単に出来ないか?
    既存のSoftでなにかいいものがあるに違いないと思っているのですが探しきれません。いわゆる「車輪の再発明」はしたくないですからね。
    球体Povなら、地球儀を表示してみたいです。
  • 振り下げで駆動
    単体で動作するので、振り下げて回して表示してみたい。
  • 独楽で駆動(というか独楽にする)
    独楽だと、かなり回転数も出るので面白そう。

最後に

Povの得意な方もメンバーにいるようです。
皆さん、気がついたこと、アドバイス等ありましたらご連絡いただければ幸いです。

長文にお付き合いいただきありがとうございます。

HakoHiroのアイコン画像
函館在住のOldエンジニアです。マイコンは Z80ワンボードの頃から使っています。なにせあの頃は、ハンドアセンブルでプログラム作成していました。(ニーモニックを手書きで書き、それを表を見ながら機械語コードに落とします)おかげで リターンコード(RTN=0xC9)はいまだに覚えています。RTNまで来るとサブルーチンが一段落でホッとするので・・・ 現在は、電子工作の他に錫で色々作って楽しんでいます。
ログインしてコメントを投稿する