SSブログ

SPRESENSE の RTC をGPS 時計に設定して時報アプリを作ってみた! [SPRESENSE]

SPRESENSEはGPSを受信できるので、正確な時間を取得できます。それならその時間をRTCに設定してみて、時報アプリを作れないかなと思い作ってみました。

DSC_0001_BURST20191019170915259.JPG


時報の音源は次のURLの「Sine波 予報音3回」のMP3ファイルを拝借させていただきました。

時報音の音源
https://ultra.zone/jihou.ja


スケッチは、メインループと "pthread" で構成されています。メインループはGPS時間を取得をしてRTCを更新し、"pthread" は RTCの時間を監視して1分毎に時報を鳴らすというものです。

もともとは、task_create でスレッドを生成していたのですが、なぜかPANICが起きるので pthread に置きかえました。^^;

#include <GNSS.h>
#include <RTC.h>
#include <SDHCI.h>
#include <Audio.h>
#include <pthread.h>

static SDClass theSD;
static SpGnss Gnss; 
AudioClass *theAudio = AudioClass::getInstance();

#define JST_IN_SECONDS  (9 * 60 * 60);

static File myFile;
static bool bTimeFixed = false;

static void time_signal_thread(void *arg) {

  while(true) {
    usleep(100000);
    if (bTimeFixed == false) continue;
  
    RtcTime now = RTC.getTime();
    if (now.second() != 56) continue;

    myFile = theSD.open("jihou.mp3");
    if (!myFile) {
      Serial.println("File open error");
      while(1);
    }

    theAudio->writeFrames(AudioClass::Player0, myFile);
    theAudio->setVolume(-60);
    theAudio->startPlayer(AudioClass::Player0);
    while (true) {
      sleep(1);  //  To ensure not re-entering the audio routine. 
      int err = theAudio->writeFrames(AudioClass::Player0, myFile);
      if (err == AUDIOLIB_ECODE_FILEEND) {
        theAudio->stopPlayer(AudioClass::Player0);
        myFile.close();
        break;
      }
    }
  }

  return 0;
}

void setup() {
  int result;

  Serial.begin(115200);
  theSD.begin();
  sleep(3);  /* Wait HW initialization done. */
  
  theAudio->begin();
  theAudio->setRenderingClockMode(AS_CLKMODE_NORMAL);
  theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, AS_SP_DRV_MODE_LINEOUT);
  theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_MP3, "/mnt/sd0/BIN"
                     , AS_SAMPLINGRATE_AUTO, AS_CHANNEL_MONO);
  Serial.println("Audio initialized");
  
  Gnss.begin();
  Gnss.select(GPS);
  Gnss.start(COLD_START);
  Serial.println("Gnss start...");

  int policy;
  struct sched_param param;
  pthread_t m_pid = pthread_self();
  pthread_getschedparam(m_pid, &policy, &param);
  Serial.println("Main Priority is : " + String(param.sched_priority));

  pthread_t t_pid;
  pthread_create(&t_pid, NULL, time_signal_thread, NULL);
  param.sched_priority = 130;
  pthread_setschedparam(t_pid, policy, &param);
  Serial.println("time_signal_thread start: " + String(param.sched_priority));
}


void loop() {
 
  if (!Gnss.waitUpdate(-1)) return;

  SpNavData NavData;
  Gnss.getNavData(&NavData);
  
  Serial.println("numSat: " + String(NavData.numSatellites));

  if (NavData.time.year == 1980) return;
  bTimeFixed = true;
  
  /* Create RTC time */
  RtcTime gtime(NavData.time.year, NavData.time.month, NavData.time.day
          , NavData.time.hour, NavData.time.minute, NavData.time.sec
          , NavData.time.usec * 1000 /* RtcTime requires nsec */);

  gtime += JST_IN_SECONDS; /* convert UTC to JST */

  printf("%04d/%02d/%02d %02d:%02d:%02d\n"
          , gtime.year(), gtime.month(), gtime.day()
          , gtime.hour(), gtime.minute(), gtime.second());
  
  /* When time is different more than 1 sec, update RTC time */
  if (abs(RTC.getTime() - gtime) >= 1) {
    RTC.setTime(gtime);
    Serial.println(" * Updated RTC time * ");
  }
}




わざわざスレッドにしなくてもいいんじゃないかというコードではありますが、スレッドにすることでRTC の効用を少し分かりやすくしてみたつもりです。^^;

SPRESENSEはGPS時刻を取得できるので、複数のカメラ付きSPRESENSEを時刻同期で撮影すれば全球カメラができそうですね。ヘルメットにつけたりしたら面白いかも。
(^^)





nice!(25)  コメント(2) 

nice! 25

コメント 2

ピストン

拙ブログにコメントを頂きありがとうございます。
アドセンスで何かご質問があれば気軽に聞いてください。何かお役に立てるかもしれません。
by ピストン (2019-11-25 02:47) 

ys_taro

ピストンさん、おかげ様で復活しました!ありがとうございます。
by ys_taro (2019-12-01 22:36) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。