teaのアイコン画像
tea 2022年09月05日作成 (2022年09月17日更新)
製作品 製作品 閲覧数 630
tea 2022年09月05日作成 (2022年09月17日更新) 製作品 製作品 閲覧数 630

サイバードラレコ方向指示器

動画

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

概要

自転車で有るといいもの乗っけもり
ドラレコ機能、方向指示器、ブレーキランプ、フロントライト、そして変形

夜間自転車に乗ることが多いのですが、手信号は見えないため
方向指示器があれば安全に乗ることができます
万が一のためにドラレコ機能も搭載

構成図

キャプションを入力できます

Spresense カメラボードでドラレコ機能を実装します
自動ブレーキランプ機能ありのテールランプと連携させます
方向指示の連携はシリアル通信で行うことで、自転車の前後をスッキリと繋ぐことが出来ます
Spresense のGPSにて速度計測を行う予定でしたが、未実装
ボディは3Dプリンタで作成。
自転車用ですが、メインユニットは取り外し可能で、車でもつかえるようにします
路面にレーザ表示し、車幅を車に知らせます
加速度センサーでブレーキを感知し、ブレーキランプを明滅
そして、変形機能!起動時にサーボで左右に展開します
機能テンコ盛り~

使用しているパーツ

  • メインユニット
    Spresenseメインボード
    Spresenseカメラボード
    Spresense拡張ボード 4000円
    WINGONEER 1.8インチフルカラー128×160 SPIフルカラーTFT LCDディスプレイモジュールST7735S 3.3V 899円
    ALITOVE WS2812B LEDテープ1m 144連 NeoPixel RGB TAPE LED 5050 SMD LEDテープライトピクセル 1,839円
    SDカード
    IIC I2C シリアルOLED液晶ディスプレイモジュール I2C SSD1306 白色I2C OLEDスクリーンドライバ0.91" Arduino用DC 128x32 3.3V〜5V 1400円

  • 電源ユニット
    モバイルバッテリー 100均
    スイッチ

  • ハンドル
    スイッチ×3
    コネクタ

  • 後部ユニット
    中華製ArduinoNano 1000円
    サーボ×2
    ブザー

メインユニット

カメラは可動出来るようにしています。また車でも使えるように取り外し可能にしておきます
他のユニットとの接続はコネクタを利用します
キャプションを入力できます

方向指示器(フラッシャー)

LEDテープで方向を表示します
Arduino用のライブラリで制御しようとして四苦八苦していたのですが
Spresense 用の物が必要みたいです こちら
前方向指示器はナイトライダーのセンサーライトをイメージして作っています
ナイトライダーっておじさんしか知らないかも
あのヒュンヒュンいいながらライトが光るの萌える!
常時動作させたいため、サブコア側でプログラムは走らせます
しかし、どうにも別の色になったりノイズが入ります。
原因はTFTディスプレイドライバのAdafruit_ST7735とLEDテープの相性が悪い模様
TFTをやめ、OELDディスプレイに変更したところ改善しました。
キャプションを入力できます

後部ユニット

キャプションを入力できます
以前に作成したテールランプをサイバーチックに改造しています
起動するとライトが左右にサーボで展開します
カッコイイ・・・かな?変形はロマン!
幅が広い方が方向指示器が見やすいので、ムダではない!
キャプションを入力できます
しかし、中身ごちゃごちゃ。上手い配線の仕方を覚えないと

後部ユニットとのシリアル通信

シリアル通信で後部ユニットのArduinoと通信を行います
しかし、ここからが苦闘の歴史・・・
メインボードからTXを繋いでArduinoのRXに送ってみます
が、送信されている気配はあるのに文字が送れない、数値もダメ・・・なぜ~
原因はメインボードのTXでは1.8Vのため、電圧が足りなく信号が送れない模様
レベルシフタ無いといかんらしい。まじか
Spresense拡張ボードが必須でした。無いとメインボードだけだと何もできない!
最初からモニター応募しておけばよかった・・・
泣く泣くぽちりました4000円なり
購入したSpresense拡張ボードで通信してみるも文字が送れない
5Vではなくどうやら3.3Vでないとだめらしい(ArduinoNanoの動作電圧5Vじゃ?)
その後、うまくいったのでマルチコア化をして再試験・・・動かない
マルチコアにするとSerial2が使えなくなるようです。Spresenseのバグ?
結局ソフトウエアシリアルを使用することで回避しました

ドラレコ

カメラサンプルをちょちょっと変更して、画像を永続的にファイル保存すれば終わり!
となるはずでしたが、欲をかいてプレビュー機能を付けようと安いディスプレイを購入
一応表示できるところまで出来ましたが、表示があまりに遅くてプレビューには使えませんでした
ディスプレイは早いものを選びましょう

速度表示

GPSのサンプルをちょちょっと変更して、速度を取得してディスプレイに表示すれば終わり!
となるはずでしたが、何分たっても時速が取得できない・・・
時間などは取得できているので壊れているわけではなさそう。今回は諦めました

フロントライト

普通の自転車のライトをモバイルバッテリーで点灯します
本当はSpresenseで制御したかったのですが、
デジタル入出力端子は 6mA
ということなので
100mAのフロントライトは直では制御できません
モータードライバとかFETで電流を流す方法は、色々手はあるのですが、
モバイルバッテリーから直で供給することとしました

ハンドル方向指示スイッチ

キャプションを入力できます
3Dプリンタで作成します。意外と設計が難しくて5,6回試作してしまいました。
ちなみに私は初心者でも簡単に扱えるTinkercad](https://www.tinkercad.com/)使っています
STLのモデルが欲しい方はコメントして頂いたらアップします
4端子のコネクタにスイッチはつなげておきます
キャプションを入力できます

電源ユニット

キャプションを入力できます
100均のモバイルバッテリーを電源にします
拡張ボードの方には電源スイッチが無いため、電源ユニット側にスイッチを付けます
USBケーブルを切断し、途中にスイッチを付けるのですが、ここで注意しないといけないのが
電源用として使用する場合、信号線を短絡する必要があるらしいです
短絡しないとデータ通信用と認識され、拡張ボードに供給できませんでした。

今後のやりたいこと

  • スイッチで操作ではなくSpresenseでフロントライトや後部ユニットの電源制御がしたい
  • オートパワーOFF
  • 盗難防止機能で移動されるとブザーがなるのですが、GPSで位置も送るとか
  • 電磁加速装置を追加したい
  • 防水?雨の日は自転車乗らないので問題なし!

Spresense落とし穴ポイントまとめ

  • メインボードは1.8V。arduinoと連携できない
  • デジタル入出力端子は 6mA
  • サブコアでSerial.begin(115200);を入れると固まる
  • マルチコアにするとSerial2が使えなくなる
  • Adafruit_ST7735とサブコアでLEDテープの相性が悪い
  • SDカードへのアクセスするとLEDテープにノイズが乗る
    マニュアルをよく読め!ということですかね
    こういった情報、皆さんの役に立つかな?
    Spresenseの情報がやっぱり少ないので
    コンテストバンバンやって使ってもらうのが普及に繋がりそう

メインコアコード

メインユニットで同時に複数の処理を行う必要があるので、
折角のマルチコアですので、コアごとに処理を分けてみました
ただ、分けるとLEDテープにノイズが乗るようです
何故?原因はSDカードへのアクセスのようです
拡張ボードのSDカードを引っこ抜くと改善する・・・
一応抵抗を咬ますと軽減されるようですがノイズなのかなあ

メインコア(カメラ・GPS)

#ifdef SUBCORE #error "Core selection is wrong!!" #endif #include <MP.h> /* include the GNSS library */ #include <GNSS.h> #include <Adafruit_GFX.h> // Core graphics library #if TFT #include <Adafruit_ST7735.h> // Hardware-specific library for ST7735 #endif #include <Adafruit_SSD1306.h> #include <SPI.h> #include <SDHCI.h> #include <stdio.h> /* for sprintf */ #include <Camera.h> #define STRING_BUFFER_SIZE 128 /**< %Buffer size */ #define RESTART_CYCLE (60 * 5) /**< positioning test term */ static SpGnss Gnss; /**< SpGnss object */ #define BAUDRATE (115200) #define TOTAL_PICTURE_COUNT (5000) SDClass theSD; int take_picture_count = 0; #if TFT #define TFT_CS 10 #define TFT_RST 9 // Or set to -1 and connect to Arduino RESET pin #define TFT_DC 8 #define TFT_MOSI 11 // Data out #define TFT_SCLK 13 // Clock out // For ST7735-based displays, we will use this call Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); #endif #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); /** * @enum ParamSat * @brief Satellite system */ enum ParamSat { eSatGps, /**< GPS World wide coverage */ eSatGlonass, /**< GLONASS World wide coverage */ eSatGpsSbas, /**< GPS+SBAS North America */ eSatGpsGlonass, /**< GPS+Glonass World wide coverage */ eSatGpsBeidou, /**< GPS+BeiDou World wide coverage */ eSatGpsGalileo, /**< GPS+Galileo World wide coverage */ eSatGpsQz1c, /**< GPS+QZSS_L1CA East Asia & Oceania */ eSatGpsGlonassQz1c, /**< GPS+Glonass+QZSS_L1CA East Asia & Oceania */ eSatGpsBeidouQz1c, /**< GPS+BeiDou+QZSS_L1CA East Asia & Oceania */ eSatGpsGalileoQz1c, /**< GPS+Galileo+QZSS_L1CA East Asia & Oceania */ eSatGpsQz1cQz1S, /**< GPS+QZSS_L1CA+QZSS_L1S Japan */ }; /* Set this parameter depending on your current region. */ static enum ParamSat satType = eSatGps; unsigned long timeCamera; unsigned long timeLed; unsigned long timeGnss; int mode = 1; /** * @brief Turn on / off the LED0 for CPU active notification. */ static void Led_isActive(void) { static int state = 1; if (state == 1) { ledOn(PIN_LED0); state = 0; } else { ledOff(PIN_LED0); state = 1; } } /** * @brief Turn on / off the LED1 for positioning state notification. * * @param [in] state Positioning state */ static void Led_isPosfix(bool state) { if (state) { ledOn(PIN_LED1); } else { ledOff(PIN_LED1); } } /** * @brief Turn on / off the LED3 for error notification. * * @param [in] state Error state */ static void Led_isError(bool state) { if (state) { ledOn(PIN_LED3); } else { ledOff(PIN_LED3); } } void CoreSetup() { int ret = 0; int subid; //Serial.begin(115200); while (!Serial); /* Boot SubCore */ for (subid = 1; subid <= 1; subid++) { ret = MP.begin(subid); if (ret < 0) { MPLog("MP.begin(%d) error = %d\n", subid, ret); } } } /** * @brief Activate GNSS device and start positioning. */ void setup() { /* Set serial baudrate. */ Serial.begin(115200); //Serial2.begin(9600); CoreSetup(); #if TFT //tft.initR(INITR_GREENTAB); // Init ST7735S chip, green tab tft.initR(INITR_BLACKTAB); // タブが緑なのにブラック? /* ライブラリの245行目に下記を追加 _colstart = 2; _rowstart = 1;*/ tft.setTextWrap(false); tft.fillScreen(ST77XX_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST77XX_RED); tft.setTextSize(1); tft.println("Hello World!"); tft.setTextColor(ST77XX_YELLOW); tft.setTextSize(2); #endif if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } display.clearDisplay(); display.setTextSize(3); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); display.print("START"); display.display(); if(mode == 1){ /* Set serial baudrate. */ CameraSetup(); } if(mode == 2){ GnssSetup(); } } void GnssSetup() { int error_flag = 0; /* Wait HW initialization done. */ sleep(3); /* Turn on all LED:Setup start. */ ledOn(PIN_LED0); ledOn(PIN_LED1); ledOn(PIN_LED2); ledOn(PIN_LED3); /* Set Debug mode to Info */ Gnss.setDebugMode(PrintInfo); int result; /* Activate GNSS device */ result = Gnss.begin(); if (result != 0) { Serial.println("Gnss begin error!!"); error_flag = 1; } else { /* Setup GNSS * It is possible to setup up to two GNSS satellites systems. * Depending on your location you can improve your accuracy by selecting different GNSS system than the GPS system. * See: https://developer.sony.com/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_gnss * for detailed information. */ switch (satType) { case eSatGps: Gnss.select(GPS); break; case eSatGpsSbas: Gnss.select(GPS); Gnss.select(SBAS); break; case eSatGlonass: Gnss.select(GLONASS); break; case eSatGpsGlonass: Gnss.select(GPS); Gnss.select(GLONASS); break; case eSatGpsBeidou: Gnss.select(GPS); Gnss.select(BEIDOU); break; case eSatGpsGalileo: Gnss.select(GPS); Gnss.select(GALILEO); break; case eSatGpsQz1c: Gnss.select(GPS); Gnss.select(QZ_L1CA); break; case eSatGpsQz1cQz1S: Gnss.select(GPS); Gnss.select(QZ_L1CA); Gnss.select(QZ_L1S); break; case eSatGpsBeidouQz1c: Gnss.select(GPS); Gnss.select(BEIDOU); Gnss.select(QZ_L1CA); break; case eSatGpsGalileoQz1c: Gnss.select(GPS); Gnss.select(GALILEO); Gnss.select(QZ_L1CA); break; case eSatGpsGlonassQz1c: default: Gnss.select(GPS); Gnss.select(GLONASS); Gnss.select(QZ_L1CA); break; } /* Start positioning */ result = Gnss.start(COLD_START); if (result != 0) { Serial.println("Gnss start error!!"); error_flag = 1; } else { Serial.println("Gnss setup OK"); } } /* Start 1PSS output to PIN_D02 */ //Gnss.start1PPS(); /* Turn off all LED:Setup done. */ ledOff(PIN_LED0); ledOff(PIN_LED1); ledOff(PIN_LED2); ledOff(PIN_LED3); /* Set error LED. */ if (error_flag == 1) { Led_isError(true); exit(0); } } /** * @brief %Print position information. */ static void print_pos(SpNavData *pNavData) { char StringBuffer[STRING_BUFFER_SIZE]; display.clearDisplay(); display.setTextSize(1); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); #if TFT tft.fillRect(0, 40, tft.width(), 16, ST77XX_BLUE); tft.setCursor(0, 40); tft.setTextSize(1); #endif /* print time */ snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day); Serial.print(StringBuffer); snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec); Serial.print(StringBuffer); #if TFT tft.println(StringBuffer); #endif display.println(StringBuffer); /* print satellites count */ snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites); Serial.print(StringBuffer); #if TFT tft.print(StringBuffer); #endif display.print(StringBuffer); display.display(); /* print position data */ if (pNavData->posFixMode == FixInvalid) { #if TFT tft.println("N"); #endif Serial.print("No-Fix, "); } else { #if TFT tft.println("F"); #endif Serial.print("Fix, "); } if (pNavData->posDataExist == 0) { Serial.print("No Position"); } else { Serial.print("Lat="); Serial.print(pNavData->latitude, 6); Serial.print(", Lon="); Serial.print(pNavData->longitude, 6); } Serial.println(""); } /** * @brief %Print satellite condition. */ static void print_condition(SpNavData *pNavData) { char StringBuffer[STRING_BUFFER_SIZE]; unsigned long cnt; /* Print satellite count. */ snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites); Serial.print(StringBuffer); #if TFT tft.setCursor(0, 60); tft.setTextSize(1); #endif display.setCursor(0,16); // Start at top-left corner display.println(StringBuffer); for (cnt = 0; cnt < pNavData->numSatellites; cnt++) { const char *pType = "---"; SpSatelliteType sattype = pNavData->getSatelliteType(cnt); /* Get satellite type. */ /* Keep it to three letters. */ switch (sattype) { case GPS: pType = "GPS"; break; case GLONASS: pType = "GLN"; break; case QZ_L1CA: pType = "QCA"; break; case SBAS: pType = "SBA"; break; case QZ_L1S: pType = "Q1S"; break; case BEIDOU: pType = "BDS"; break; case GALILEO: pType = "GAL"; break; default: pType = "UKN"; break; } /* Get print conditions. */ unsigned long Id = pNavData->getSatelliteId(cnt); unsigned long Elv = pNavData->getSatelliteElevation(cnt); unsigned long Azm = pNavData->getSatelliteAzimuth(cnt); float sigLevel = pNavData->getSatelliteSignalLevel(cnt); /* Print satellite condition. */ //snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2ld] Type:%s, Elv:%2ld, Azm:%3ld, CN0:", cnt, pType, Elv, Azm ); snprintf(StringBuffer, STRING_BUFFER_SIZE, "El:%2ld,Az:%3ld,CN:%2ld", Elv, Azm, sigLevel ); Serial.print(StringBuffer); #if TFT tft.fillRect(0, 60 +cnt*16, tft.width(), 16, ST77XX_BLUE); tft.println(StringBuffer); #endif display.println(StringBuffer); Serial.println(sigLevel, 6); } display.display(); } /** * @brief %Print position information and satellite condition. * * @details When the loop count reaches the RESTART_CYCLE value, GNSS device is * restarted. */ void loop() { if(mode == 1 && micros() -timeCamera > 2000) { timeCamera = micros(); CameraLoop(); //Serial2.println("L"); //Serial2.write(2); } if(mode == 2 && micros() -timeGnss > 10000) { timeGnss = micros(); LoopGnss(); } } void LoopGnss() { char StringBuffer[STRING_BUFFER_SIZE]; static int LoopCount = 0; static int LastPrintMin = 0; /* Blink LED. */ Led_isActive(); /* Check update. */ if (Gnss.waitUpdate(-1)) { /* Get NaviData. */ SpNavData NavData; Gnss.getNavData(&NavData); #if TFT //tft.fillScreen(ST77XX_BLACK); tft.fillRect(0, 0, tft.width(), 40, ST77XX_BLUE); tft.setCursor(0, 0); tft.setTextColor(ST77XX_GREEN); tft.setTextSize(2); snprintf(StringBuffer, STRING_BUFFER_SIZE, "Sp:%.2f", NavData.velocity/60/60); tft.println(StringBuffer); snprintf(StringBuffer, STRING_BUFFER_SIZE, "Gg:%ld", NavData.direction ); tft.println(StringBuffer); Serial.print(StringBuffer); #endif /* Set posfix LED. */ bool LedSet = (NavData.posDataExist && (NavData.posFixMode != FixInvalid)); Led_isPosfix(LedSet); /* Print satellite information every minute. */ if (NavData.time.minute != LastPrintMin) { print_condition(&NavData); LastPrintMin = NavData.time.minute; } /* Print position information. */ print_pos(&NavData); } else { /* Not update. */ Serial.println("data not update"); } /* Check loop count. */ //LoopCount++;//リスタートしない if (LoopCount >= RESTART_CYCLE) { int error_flag = 0; /* Turn off LED0 */ ledOff(PIN_LED0); /* Set posfix LED. */ Led_isPosfix(false); /* Restart GNSS. */ if (Gnss.stop() != 0) { Serial.println("Gnss stop error!!"); error_flag = 1; } else if (Gnss.end() != 0) { Serial.println("Gnss end error!!"); error_flag = 1; } else { Serial.println("Gnss stop OK."); } if (Gnss.begin() != 0) { Serial.println("Gnss begin error!!"); error_flag = 1; } else if (Gnss.start(HOT_START) != 0) { Serial.println("Gnss start error!!"); error_flag = 1; } else { Serial.println("Gnss restart OK."); } LoopCount = 0; /* Set error LED. */ if (error_flag == 1) { Led_isError(true); exit(0); } } } //ここからカメラ関連 void printError(enum CamErr err) { Serial.print("Error: "); switch (err) { case CAM_ERR_NO_DEVICE: Serial.println("No Device"); break; case CAM_ERR_ILLEGAL_DEVERR: Serial.println("Illegal device error"); break; case CAM_ERR_ALREADY_INITIALIZED: Serial.println("Already initialized"); break; case CAM_ERR_NOT_INITIALIZED: Serial.println("Not initialized"); break; case CAM_ERR_NOT_STILL_INITIALIZED: Serial.println("Still picture not initialized"); break; case CAM_ERR_CANT_CREATE_THREAD: Serial.println("Failed to create thread"); break; case CAM_ERR_INVALID_PARAM: Serial.println("Invalid parameter"); break; case CAM_ERR_NO_MEMORY: Serial.println("No memory"); break; case CAM_ERR_USR_INUSED: Serial.println("Buffer already in use"); break; case CAM_ERR_NOT_PERMITTED: Serial.println("Operation not permitted"); break; default: break; } } /** * Callback from Camera library when video frame is captured. */ void CamCB(CamImage img) { /* Check the img instance is available or not. */ if (img.isAvailable()) { /* If you want RGB565 data, convert image data format to RGB565 */ //img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); //img.convertPixFormat(CAM_IMAGE_PIX_FMT_GRAY); //tft.drawRGBBitmap(0, 0, (uint16_t *)img.getImgBuff(), 128, 160);// img.getWidth(), img.getHeight()); // #if TFT tft.drawRGBBitmap(0, 38, (uint16_t *)img.getImgBuff(), 160, 120);// img.getWidth(), img.getHeight()); // #endif /* You can use image data directly by using getImgSize() and getImgBuff(). * for displaying image to a display, etc. */ Serial.print("Image data size = "); Serial.print(img.getImgSize(), DEC); Serial.print(" , "); Serial.print("buff addr = "); Serial.print((unsigned long)img.getImgBuff(), HEX); Serial.println(""); /*char filename[16] = {0}; sprintf(filename, "PICT_MINI%03d.JPG", take_picture_count); theSD.remove(filename); File myFile = theSD.open(filename, FILE_WRITE); myFile.write(img.getImgBuff(), img.getImgSize()); myFile.close();*/ } else { Serial.println("Failed to get video stream image"); } } /** * @brief Initialize camera */ void CameraSetup() { CamErr err; /* Open serial communications and wait for port to open */ Serial.begin(BAUDRATE); while (!Serial) { ; /* wait for serial port to connect. Needed for native USB port only */ } /* Initialize SD */ while (!theSD.begin()) { /* wait until SD card is mounted. */ Serial.println("Insert SD card."); } /* begin() without parameters means that * number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */ Serial.println("Prepare camera"); err = theCamera.begin(1, CAM_VIDEO_FPS_5, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V, CAM_IMAGE_PIX_FMT_YUV422);//CAM_IMAGE_PIX_FMT_RGB565);// if (err != CAM_ERR_SUCCESS) { printError(err); } /* Start video stream. * If received video stream data from camera device, * camera library call CamCB. */ /*Serial.println("Start streaming"); err = theCamera.startStreaming(true, CamCB); if (err != CAM_ERR_SUCCESS) { printError(err); } */ /* Auto white balance configuration */ Serial.println("Set Auto white balance parameter"); err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Set parameters about still picture. * In the following case, QUADVGA and JPEG. */ Serial.println("Set still picture format"); err = theCamera.setStillPictureImageFormat( CAM_IMGSIZE_3M_H,// CAM_IMGSIZE_HD_H,// CAM_IMGSIZE_QUADVGA_H, CAM_IMGSIZE_3M_V/2,// CAM_IMGSIZE_HD_V,// CAM_IMGSIZE_QUADVGA_V, CAM_IMAGE_PIX_FMT_JPG); if (err != CAM_ERR_SUCCESS) { printError(err); } } /** * @brief Take picture with format JPEG per second */ void CameraLoop() { //sleep(1); /* wait for one second to take still picture. */ /* You can change the format of still picture at here also, if you want. */ /* theCamera.setStillPictureImageFormat( * CAM_IMGSIZE_HD_H, * CAM_IMGSIZE_HD_V, * CAM_IMAGE_PIX_FMT_JPG); */ /* This sample code can take pictures in every one second from starting. */ /* Take still picture. * Unlike video stream(startStreaming) , this API wait to receive image data * from camera device. */ //tft.fillRect(0, 0, tft.width(), 16, ST77XX_BLUE); Serial.println("call takePicture()"); CamImage img = theCamera.takePicture(); /* Check availability of the img instance. */ /* If any errors occur, the img is not available. */ if (img.isAvailable()) { /* Create file name */ char filename[16] = {0}; sprintf(filename, "PICT%03d.JPG", take_picture_count); Serial.print("Save taken picture as "); Serial.print(filename); Serial.println(""); theSD.remove(filename); File myFile = theSD.open(filename, FILE_WRITE); myFile.write(img.getImgBuff(), img.getImgSize()); myFile.close(); display.clearDisplay(); display.setTextSize(1); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); sprintf(filename, "%03d", take_picture_count); display.print(filename); display.display(); } else { /* The size of a picture may exceed the allocated memory size. * Then, allocate the larger memory size and/or decrease the size of a picture. * [How to allocate the larger memory] * - Decrease jpgbufsize_divisor specified by setStillPictureImageFormat() * - Increase the Memory size from Arduino IDE tools Menu * [How to decrease the size of a picture] * - Decrease the JPEG quality by setJPEGQuality() */ Serial.println("Failed to take picture"); } if (take_picture_count >= TOTAL_PICTURE_COUNT) { take_picture_count=0; } /* else if (take_picture_count == TOTAL_PICTURE_COUNT) { Serial.println("End."); theCamera.end(); } */ take_picture_count++; }

サブコアコード(LEDテープ・シリアル通信)

サブコアコード(LEDテープ・シリアル通信)

#if (SUBCORE != 1) #error "Core selection is wrong!!" #endif #include <MP.h> #include <SpresenseNeoPixel.h> #include <SoftwareSerial.h> #define PIN 2 // On Trinket or Gemma, suggest changing this to 1 #define NUMPIXELS 28// 10 // Popular NeoPixel ring size #define PIN_L 26 #define PIN_R 25 #define PIN_C 16 SpresenseNeoPixel<PIN, NUMPIXELS> neopixel; unsigned long timeLed; int knightCount[4]; int arrow[4]; int winCount; SoftwareSerial mySerial(4, 7); // RX, TX void setup() { MP.begin(); //Serial2.begin(9600); mySerial.begin(9600); pinMode(PIN_L, INPUT_PULLUP); pinMode(PIN_R, INPUT_PULLUP); pinMode(PIN_C, INPUT_PULLUP); //テープLED neopixel.clear(); neopixel.framerate(40); // default framerate is 40[fps] for(int i=0; i<4; i++) { arrow[i] = 1; knightCount[i] = i; } } void loop() { //if(micros() -timeLed > 1800) { timeLed = micros(); led(); } /*ledOn(LED0); delay(1000); ledOff(LED0); delay(1000);*/ } void led() { neopixel.clear(); //レフト if (digitalRead(PIN_L) == LOW ){ for(int i=10; i<NUMPIXELS; i++) { neopixel.set(i, 0, 0, 20); } if(winCount/6%2 == 0){ for(int i=0; i<10; i++) { int a = 255; neopixel.set(i, a, a/2, 0); } } winCount++; //mySerial.print("L"); //Serial2.print("L"); mySerial.write(2); MPLog("left\n"); } // ライト else if (digitalRead(PIN_R) == LOW ){ for(int i=0; i<NUMPIXELS -10; i++) { neopixel.set(i, 0, 0, 20); } if(winCount/6%2 == 0){ for(int i=0; i<10; i++) { int a = 255; neopixel.set(NUMPIXELS -i -1, a, a/2, 0); } } winCount++; //Serial2.print("R"); mySerial.write(1); MPLog("right\n"); } else{ winCount = 0; for(int i=0; i<NUMPIXELS; i++) { int a = 2; neopixel.set(i, 0, a/2, a); } for(int i=0; i<4; i++) { int a = (i*80 +10)%255; neopixel.set(knightCount[i], 0, a/2, a); } for(int i=0; i<4; i++) { knightCount[i] += arrow[i]; if(knightCount[i] < 0){ knightCount[i] = 0; arrow[i] = 1; } if(knightCount[i] > NUMPIXELS-1){ knightCount[i] = NUMPIXELS -1; arrow[i] = -1; } } } //センター if (digitalRead(PIN_C) == LOW ){ //Serial2.print("C"); mySerial.write(3); MPLog("center\n"); delay(1000);//連続送信しない } neopixel.show(); // Send the updated pixel colors to the hardware. delay(20); }

サブコアのsetupにSerial.begin(115200);を入れると何故かフリーズ
気を付けましょう

後部ユニットコード

サブコアコード(LEDテープ・シリアル通信)

#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <avr/sleep.h> #include <Adafruit_NeoPixel.h> #ifdef __AVR__ #include <avr/power.h> // Required for 16 MHz Adafruit Trinket #endif #include <SoftwareSerial.h> #include "ServoEasing.hpp" #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels int FRONT_PIN = 11; SoftwareSerial mySerial(FRONT_PIN, 1); // RX, TX #define PIN 9 // On Trinket or Gemma, suggest changing this to 1 #define PIN_L 7 // On Trinket or Gemma, suggest changing this to 1 #define NUMPIXELS 28// 10 // Popular NeoPixel ring size Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel pixelsL(NUMPIXELS, PIN_L, NEO_GRB + NEO_KHZ800); // 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 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // MPU-6050のアドレス、レジスタ設定値 #define MPU6050_WHO_AM_I 0x75 // Read Only #define MPU6050_PWR_MGMT_1 0x6B // Read and Write #define MPU_ADDRESS 0x68 #define SERVO1_PIN1 4 #define SERVO1_PIN2 8 int LASER_PIN = 10; int BEEP_PIN = 12; // 変数に7を割り当てる(デジタルピン7番) int DISP_PIN = 3; // 変数に7を割り当てる(デジタルピン7番) int wakePin = 5; //割り込み用のピン番号 int wakePin2 = 6; //割り込み用のピン番号 bool active; float acc_old_z; float acc_old_y; int keyCount; bool keyFlag; int keyWait; ServoEasing Servo1; ServoEasing Servo2; float old1; float old2; float old3; float old4; float blinkTime; int count; int blinkCount; int knightCount[4]; int arrow[4]; int sindouCount; int sindouSinpuku; int sleepCount; int renCount; int mode; bool ledCloseFlag; // デバイス初期化時に実行される void setup() { mySerial.begin(9600); pinMode(13, OUTPUT); // デジタルピン7番を出力モードに設定 Serial.begin(115200); //115200bps //シリアル通信テスト /*for(;;){ digitalWrite(13, LOW); // turn the LED off by making the voltage LOW Serial.println("x"); //while(mySerial.available()>0){ digitalWrite(13, HIGH); // turn the LED off by making the voltage LOW Serial.print(mySerial.read());//String //mode //} }*/ Serial.println("Start"); pinMode(wakePin, INPUT_PULLUP); pinMode(wakePin2, INPUT_PULLUP); pinMode(A0, INPUT); Wire.begin(); // PCとの通信を開始 //Serial.begin(115200); //115200bps // 初回の読み出し Wire.beginTransmission(MPU_ADDRESS); Wire.write(MPU6050_WHO_AM_I); //MPU6050_PWR_MGMT_1 Wire.write(0x00); Wire.endTransmission(); // 動作モードの読み出し Wire.beginTransmission(MPU_ADDRESS); Wire.write(MPU6050_PWR_MGMT_1); //MPU6050_PWR_MGMT_1レジスタの設定 Wire.write(0x00); Wire.endTransmission(); //ここから文字表示 if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } Serial.println("Start"); //BLINK pinMode(LED_BUILTIN, OUTPUT); pinMode(LASER_PIN, OUTPUT); // デジタルピン7番を出力モードに設定 pinMode(BEEP_PIN, OUTPUT); // デジタルピン7番を出力モードに設定 pinMode(DISP_PIN, OUTPUT); // デジタルピン7番を出力モードに設定 digitalWrite(DISP_PIN, HIGH); // turn the LED off by making the voltage LOW digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW active = true; keyFlag = true; pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixelsL.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) boot(); } void boot() { delay(80); int i, j; display.clearDisplay(); display.setTextSize(3); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); display.print("START"); display.display(); pixels.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixelsL.Color(0, 0, 0)); } pixelsL.show(); // Send the updated pixel colors to the hardware. delay(80); //サーボ Servo1.attach(SERVO1_PIN1, 90); Servo1.setEasingType(EASE_QUADRATIC_IN_OUT); delay(80); Servo1.easeTo(180, 80); delay(80); Servo1.detach(); Servo2.attach(SERVO1_PIN2, 90); Servo2.setEasingType(EASE_QUADRATIC_IN_OUT); Servo2.easeTo(0, 80); delay(80); Servo2.detach(); //ここからTEST用 /* for(int i=0; i<4; i++) { arrow[i] = 1; knightCount[i] = i; } for(;;){ pixels.clear(); pixelsL.clear(); for(int i=0; i<NUMPIXELS; i++) { int a = 2; pixels.setPixelColor(i, pixels.Color(a, a/2, 0)); pixelsL.setPixelColor(i, pixels.Color(a, a/2, 0)); } for(int i=0; i<4; i++) { int a = (i*80 +10)%255; pixels.setPixelColor(knightCount[i], pixels.Color(a, a/2, 0)); pixelsL.setPixelColor(knightCount[i], pixels.Color(a, a/2, 0)); } for(int i=0; i<4; i++) { knightCount[i] += arrow[i]; if(knightCount[i] < 0){ knightCount[i] = 0; arrow[i] = 1; } if(knightCount[i] > NUMPIXELS-1){ knightCount[i] = NUMPIXELS -1; arrow[i] = -1; } } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.show(); // Send the updated pixel colors to the hardware. delay(40); } //end */ for(j=0; j<256; j++) { pixels.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, (255-j)/2, 255-j)); } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixelsL.Color(0, (255-j)/2, 255-j)); } pixelsL.show(); // Send the updated pixel colors to the hardware. delay(2); } } void LedClose() { for(int j=0; j<256; j++) { pixels.clear(); // Set all pixel colors to 'off' for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255-j, (255-j)/2, 0)); } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.clear(); // Set all pixel colors to 'off' for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixelsL.Color(255-j, (255-j)/2, 0)); } pixelsL.show(); // Send the updated pixel colors to the hardware. delay(2); } //サーボ Servo1.attach(SERVO1_PIN1, 90); Servo2.attach(SERVO1_PIN2, 90); Servo1.easeTo(90, 80); Servo2.easeTo(90, 80); delay(80); Servo1.detach(); Servo2.detach(); } void loop() { pixels.clear(); // Set all pixel colors to 'off' pixelsL.clear(); // Set all pixel colors to 'off' if(!active){ //set_sleep_mode(SLEEP_MODE_PWR_DOWN); //スリープモードの設定 //interrupt(); delayWDT2(70); } Wire.beginTransmission(0x68); Wire.write(0x3B); Wire.endTransmission(false); Wire.requestFrom(0x68, 14, true); while (Wire.available() < 14); int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, Temperature; axRaw = Wire.read() << 8 | Wire.read(); ayRaw = Wire.read() << 8 | Wire.read(); azRaw = Wire.read() << 8 | Wire.read(); Temperature = Wire.read() << 8 | Wire.read(); gxRaw = Wire.read() << 8 | Wire.read(); gyRaw = Wire.read() << 8 | Wire.read(); gzRaw = Wire.read() << 8 | Wire.read(); // 加速度値を分解能で割って加速度(G)に変換する float acc_x = axRaw / 16384.0; //FS_SEL_0 16,384 LSB / g float acc_y = ayRaw / 16384.0; float acc_z = azRaw / 16384.0; // 角速度値を分解能で割って角速度(degrees per sec)に変換する float gyro_x = gxRaw / 131.0;//FS_SEL_0 131 LSB / (°/s) float gyro_y = gyRaw / 131.0; float gyro_z = gzRaw / 131.0; bool flag = false; //動きありか if(acc_z >= acc_old_z -0.02 && acc_z <= acc_old_z +0.02 && acc_y >= acc_old_y -0.02 && acc_y <= acc_old_y +0.02){ flag = true; } if(!keyFlag){ //キー無し if(!digitalRead(wakePin)){ Serial.print("Key "); active = true; sleepCount = 0; if(keyCount == 1){ keyFlag = true; boot(); } keyCount = 0; } if(!digitalRead(wakePin2)){ Serial.print("Key2 "); active = true; sleepCount = 0; if(keyCount == 0){ keyCount = 1; } } } else{ //遠隔収納 if(mode == 3){ if(ledCloseFlag){ boot(); } else{ LedClose(); } ledCloseFlag = !ledCloseFlag; } //収納 if(!digitalRead(wakePin)){ LedClose(); //スリープへ sleepCount = 500; flag = true; } //スリープからの復帰 if(!active && !digitalRead(wakePin2)) { boot(); } } if(flag){ //動いていない場合 //Serial.print("no active "); //Serial.print(sleepCount); //Serial.print(" "); //Serial.print(acc_y); Serial.println(""); if(sleepCount > 600){ //全消灯 display.clearDisplay(); display.setCursor(0,0); // Start at top-left corner display.print("SLEEP"); display.display(); for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); pixelsL.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); pixelsL.show(); digitalWrite(LASER_PIN, LOW); digitalWrite(DISP_PIN, LOW); active = false; acc_old_z = acc_z; acc_old_y = acc_y; keyFlag = false; keyWait = 0; return; } sleepCount++; } else{ digitalWrite(DISP_PIN, HIGH); //Serial.print("active "); active = true; sleepCount = 0; } acc_old_z = acc_z; acc_old_y = acc_y; //キーが入っていない場合ブザー if(!keyFlag && keyWait > 500){ digitalWrite(BEEP_PIN, HIGH); for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255, 0, 0)); pixelsL.setPixelColor(i, pixels.Color(0, 0, 255)); } pixels.show(); pixelsL.show(); //digitalWrite(FRONT_PIN, HIGH); delay(120); digitalWrite(BEEP_PIN, LOW); for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 255)); pixelsL.setPixelColor(i, pixels.Color(255, 0, 0)); } pixels.show(); pixelsL.show(); //digitalWrite(FRONT_PIN, LOW); delay(120); sleepCount+=10; } keyWait++; // Serial.print((Temperature+521)/340+35); Serial.print(","); //Serial.print(acc_x); Serial.println("");//上下 //Serial.print(acc_z); Serial.println("");//傾き //Serial.print(acc_y); Serial.println("");//前後 //Serial.print(gyro_x); Serial.print(","); //Serial.print(gyro_y); Serial.print(","); //Serial.print(gyro_z); Serial.println(""); float sa = 0.12; float heikinOld = (old4*0.5 +old3*0.3 +old2*0.2); float heikinNew = (acc_x +old1)/2; //振動 if(heikinOld < heikinNew -sa && sindouSinpuku != 1){ sindouCount+=4; sindouSinpuku = 1; } if(heikinOld > heikinNew +sa && sindouSinpuku != -1){ sindouCount+=4; sindouSinpuku = -1; } //振動以外で減速したとき if(heikinOld < heikinNew -sa && sindouCount < 2){ blinkTime = 28; } sindouCount--; if(sindouCount < 0){ sindouCount = 0; sindouSinpuku = 0; } if(sindouCount > 10){ sindouCount = 10; } old4 = old3; old3 = old2; old2 = old1; old1 = acc_x; digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW display.clearDisplay(); display.setTextSize(2); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); display.print((Temperature+521)/340+35); display.print("C "); display.print(cpuVcc()); // 電源電圧測定 http://radiopench.blog96.fc2.com/blog-entry-490.html //display.print(analogRead(A0)); display.println("V"); if(keyFlag){ display.print("KEY "); } else{ display.print("INPUT "); display.print((500 -keyWait)/10); } display.drawLine(display.width()/2, display.height() -2, display.width()/2 +heikinNew*100, display.height() -2, SSD1306_WHITE); display.drawLine(display.width()/2, display.height() -4, display.width()/2 +(heikinNew-heikinOld)*200, display.height() -4, SSD1306_WHITE); display.drawLine(display.width()/2, display.height() -6, display.width()/2 +sa*200, display.height() -6, SSD1306_WHITE); if(blinkTime > 0){ //display.println(heikinNew*100); display.println("brake"); //digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) if(count%2 == 0){ digitalWrite(LASER_PIN, HIGH); } else{ digitalWrite(LASER_PIN, LOW); } if(mode == 1){//ライトブリンク if(blinkCount/4%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255, 100, 0)); } } blinkCount++; } else{ if(count%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255, 50, 50)); } } else{ for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 50)); } } } if(mode == 2){//レフトブリンク if(blinkCount/4%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixels.Color(255, 100, 0)); } } blinkCount++; } else{ if(count%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixels.Color(0, 0, 50)); } } else{ for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixels.Color(255, 50, 50)); } } } blinkTime--; } else{ //digitalWrite(BEEP_PIN, LOW); for(int i=0; i<NUMPIXELS; i++) { if(mode == 2){//ライトブリンク if(blinkCount/4%2 == 0){ pixels.setPixelColor(i, pixels.Color(255, 100, 0)); } } else{ pixels.setPixelColor((blinkCount+i)%NUMPIXELS, pixels.Color((i*25)%255, 0, 0)); } if(mode == 1){//レフトブリンク if(blinkCount/4%2 == 0){ //digitalWrite(BEEP_PIN, HIGH); pixelsL.setPixelColor(i, pixels.Color(255, 100, 0)); } } else{ pixelsL.setPixelColor((blinkCount+i)%NUMPIXELS, pixels.Color((i*25)%255, 0, 0)); } } blinkCount++; if(count%4 == 0){ digitalWrite(LASER_PIN, HIGH); } else{ digitalWrite(LASER_PIN, LOW); } } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.show(); // Send the updated pixel colors to the hardware. count++; display.display(); //シリアル通信受信 mode = 0; while(mySerial.available()>0){ mode = mySerial.read(); } Serial.print("mode:"); Serial.println(mode); delay(20); } //割込み関数 void interrupt(){ //attachInterrupt(0,wakeUp, LOW); //割り込み処理の設定、2番ピンがLowで復帰 PRR = PRR | 0b00100000; //8bitタイマーdisable sleep_mode(); //スリープモードを有効にする //detachInterrupt(0); //割り込み処理を解除する } void wakeUp(){ //Serial.println("Wake up from standby."); //復帰時にシリアルモニターに表示 PRR = PRR & 0b00000000; //8bitタイマーenable //delay(30000); //時間調整 } void delayWDT2(unsigned long t) { // パワーダウンモードでdelayを実行 Serial.flush(); // シリアルバッファが空になるまで待つ delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定 // ADCを停止(消費電流 147→27μA) ADCSRA &= ~(1 << ADEN); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード指定 sleep_enable(); // BODを停止(消費電流 27→6.5μA) MCUCR |= (1 << BODSE) | (1 << BODS); // MCUCRのBODSとBODSEに1をセット MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // すぐに(4クロック以内)BODSSEを0, BODSを1に設定 asm("sleep"); // 3クロック以内にスリープ sleep_mode();では間に合わなかった sleep_disable(); // WDTがタイムアップでここから動作再開 ADCSRA |= (1 << ADEN); // ADCの電源をON(BODはハードウエアで自動再開される) } void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。 // 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記 // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms // 6=1sec, 7=2sec, 8=4sec, 9=8sec byte bb; if (ii > 9 ) { // 変な値を排除 ii = 9; } bb = ii & 7; // 下位3ビットをbbに if (ii > 7) { // 7以上(7.8,9)なら bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする } bb |= ( 1 << WDCE ); MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0 // start timed sequence WDTCSR |= (1 << WDCE) | (1 << WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット) // set new watchdog timeout value WDTCSR = bb; // 制御レジスタを設定 WDTCSR |= _BV(WDIE); } ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理 // wdt_cycle++; // 必要ならコメントアウトを外す } float cpuVcc(){ // 電源電圧(AVCC)測定関数 long sum=0; adcSetup(0x4E); // Vref=AVcc, input=internal1.1V for(int n=0; n < 10; n++){ sum = sum + adc(); // adcの値を読んで積分 } return (1.1 * 10240.0)/ sum; // 電圧を計算して戻り値にする } void adcSetup(byte data){ // ADコンバーターの設定 ADMUX = data; // ADC Multiplexer Select Reg. ADCSRA |= ( 1 << ADEN); // ADC イネーブル ADCSRA |= 0x07; // AD変換クロック CK/128 delay(10); // 安定するまで待つ } unsigned int adc(){ // ADCの値を読む unsigned int dL, dH; ADCSRA |= ( 1 << ADSC); // AD変換開始 while(ADCSRA & ( 1 << ADSC) ){ // 変換完了待ち } dL = ADCL; // LSB側読み出し dH = ADCH; // MSB側 return dL | (dH << 8); // 10ビットに合成した値を返す } void testfillcircle(void) { for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) { // The INVERSE color is used so circles alternate white/black display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE); } }

余談

Spresenseを使ってみて、遊びで使うにはちょっと使いづらい面も
メインボードと拡張ボードが一体化した6000円ぐらいの物があれば使いやすそう
メインボードは省電力設計となっているので電圧1.8Vなのかもしれないですが、arduinoと同一だと使いやすそう
カメラは高機能だなあ。そこら辺はSONYらしいというか
キャプションを入力できます
こんな高画質で連続で撮影できます

  • tea さんが 2022/09/05 に 編集 をしました。 (メッセージ: 初版)
  • tea さんが 2022/09/17 に 編集 をしました。
ログインしてコメントを投稿する