Tamesuke-Goto Maker的Blog

Tamesuke-Goto Maker的Blog

地域ISP管理者だけれど、ここ3年ほどMakerなJobが増えたのでまとめてみたいと思います 旧ハンドル Ringoro

ふと 二十四節気クロックを作ってみたいと 思いました。暦は季節の移り変わりに即したものがよかろうという考えからですが。

 

節気計算の式はネットにある様なので容易かと思ったのですが、結構厄介でした。参考にしたのは、下記

 

https://www.metds.co.jp/wp-content/uploads/2019/03/TE_SunPosition_160401.pdf

 

にあるC++コードからお借りしましたが、これはこれで略式の様で今年の立春 を計算したところ 本当の2/3 23:59 立春時刻 にはギリギリで誤差が出てしまって2/4が立春になってしまいました。。。 これと同様の式を用いたと思われる節気サイトがありますが、同じく立春が2/4 00:00 に計算されているサイトがある様でした。

いまいち精確な計算法が分からず、、暫定的ですがこの式の結果に補正を加えることでどうにか節気としては正確に求められる様にしました。具体的にはこの式から求めたψに角度で 0.0072度程度を加えただけというアバウトな方法です。

 

次に、節気クロックでは 「立春5日、雨水前11日」 みたいな表示をしたいのですが、節気と節気間の日数は15日だったり16日だったりまちまち(当たり前ですね) 「今日の節気は何」 は分かっても 何日目なのか、黄経の角度だけから計算しても誤差が発生してしまい、立春の3日目が二日続いたり変な事も発生。。。

結局今日の黄経から一日ずつ遡って節気から何日目かを知り、一日づつ進めて次の節気日まで勘定するという方法で対処しました。

 

以下サンプルプログラムです。のちほどM5Stackに実装したいと思います。

 

 


/*

   Sekki Day Calc

  cc sekkiday.c -lm -o sekkiday


  2021/2/10   calc with julian today



*/

#include <stdio.h>
#include <math.h>
#include <stdbool.h>

#define deg2rad(deg)  ((deg) / 180.0 * 3.14159265358979323846)

#define  daydeg (360/365.24219)

#define false 0
#define true  1

double julian(int nYear, int nMonth, double dDay);

double getlamda(int yr , int month , double aday);

// new funcs
typedef const int cint;
typedef const double cdouble;

double JC(double);
double CLongit( cdouble aJC);

int yr=2000;
int mn=4;
int dy=1;
double ddy=1.0;
double ddy1=1.0;

int sekki;
int sday;

int sekki2;
int sday2;

double dsday;

//double  hosei = 0.386874;     //  from eco.mtk.nao.ac.jp
double  hosei = 0.0072;
//double  hosei = 0.102753;


int main()
{
   int i,n;
   int hoseideg;
   double psi,psi0,psi1,psit,psin;
   double jday,jday1;
   double jc;

   yr = 2021;    // Year
   mn = 3;       // Month
   dy = 10;      //  Day



       ddy  = (double)dy-(9.0/24.0) + 0.99930;  // 23:59
       ddy  = (double)dy-(9.0/24.0) + 0.9999930;  // 23:59:58


       jday= julian(yr,mn,ddy);   // today julian day


       jc =  JC(jday);
       psit  = CLongit(jc)+hosei;

       sekki = (int)(psit / 15);
       sekki2 = sekki+1;
       psi0 = sekki*15;          //  today's sekki degree
       psin = sekki2*15;         // next sekki degree

      sday=1;
      while(sday<=16){

         jday1=jday-1.0*sday;
         jc =  JC(jday1);
         psi1  = CLongit(jc)+hosei;
        if(sekki==0 && psi1 >= 345){
          psi1 = psi1-360.0;
         }

         printf("%d ,  %f ,  %f , %f  \n",sday,psi1,psi0,psit);

         if(psi1 < psi0){
            break;
          }
         sday++;
      }
      printf("%d/%d : sekki=%d , sday=%d \n",mn,dy,sekki,sday);

      sday2=1;

    while(sday2<=16){
       jday1=jday+1.0*sday2;
       jc=JC(jday1);
       psi1 = CLongit(jc)+hosei;
       if(sekki2 == 24 && psi1 <= 15){
       psi1 = psi1+360;
       }
       printf("%d ,  %f ,  %f , %f  \n",sday2,psi1,psin,psit);
       if(psi1 > psin){
          break;
       }
     sday2++;
     }

     printf("%d/%d : sekki2=%d , sday2=%d \n",mn,dy,sekki2,sday2);
  return sekki;
}




double julian(int nYear, int nMonth, double dDay)
{
    double da, db;
    double dJD;


    if (nMonth < 3){
        nMonth += 12;
        nYear--;
    }

    // Calc. body
    da = floor(nYear/100.0);
    db = 2.0 - da + floor(da / 4.0);
    dJD = floor(365.25 * nYear) + floor(30.6001 * (nMonth + 1)) + dDay + db +

1720994.5;
//  dJD = floor(365.25 * nYear) + floor(30.6001 * (nMonth + 1)) + dDay + db +

1721088.5;

    if (dJD < 2299160.5){
        dJD -= db;
    }

    return (dJD);
}




/*
          psi :  psi - koukei

*/


#define _rpd   (3.14159 / 180.0)


typedef struct {
bool T;
double P, Q, R;
} SCoef;

#define PCOEF_MAX (18)

const SCoef PCoef[PCOEF_MAX] = {
{ false, 1.9147, 35999.05, 267.52, }, // 1
{ false, 0.0200, 71998.10, 265.10, }, // 2
{ false, 0.0020, 32964.00, 158.00, }, // 3
{ false, 0.0018, 19.00, 159.00, }, // 4
{ false, 0.0018, 445267.00, 208.00, }, // 5
{ false, 0.0015, 45038.00, 254.00, }, // 6
{ false, 0.0013, 22519.00, 352.00, }, // 7
{ false, 0.0007, 65929.00, 45.00, }, // 8
{ false, 0.0007, 3035.00, 110.00, }, // 9
{ false, 0.0007, 9038.00, 64.00, }, // 10
{ false, 0.0006, 33718.00, 316.00, }, // 11
{ false, 0.0005, 155.00, 118.00, }, // 12
{ false, 0.0005, 2281.00, 221.00, }, // 13
{ false, 0.0004, 29930.00, 48.00, }, // 14
{ false, 0.0004, 31557.00, 161.00, }, // 15
{ true, -0.0048, 35999.00, 268.00, }, // 16*
{ false, 0.0048, 1934.00, 145.00, }, // 17
{ false, -0.0004, 72002.00, 111.00, }, // 18
};
//

double CLongit( cdouble aJC)
{

//
//    aJC : julian year
//
        bool IsAP = true;

        double T = aJC;
        double psi = 0.0, qtr, p;
        int icmax = (IsAP ? PCOEF_MAX : PCOEF_MAX - 2);
        for ( int ic = icmax; ic >= 1; ic-- ) {
                qtr = fmod( PCoef[ic - 1].Q * T + PCoef[ic - 1].R, 360.0 ) * _rpd;
                p = PCoef[ic - 1].P;

                if ( PCoef[ic - 1].T ) p *= T;
                psi += p * cos( qtr );

        }



        if ( IsAP ) psi -= 0.00569;
        psi += 36000.7695 * T + 280.4602;
        psi = fmod(psi,360.0);
        return ( psi );
}

/*

   julian day to julian seiki;


*/

double JC(double jday)
{
    double jc;

    jc = (jday - 2451545.0)/36525;

   return jc;
}


 

 

 

スイッチサイエンス ダストセンサー SPS30 を ESP32で使ってみました。

 

センサーモジュールはこちら、、

 

https://www.switch-science.com/catalog/5328/

 

モジュールの接続には JST ZHR-5 を使います。スイッチサイエンスのモジュールには専用ケーブルが付いてきますが先がピンでブレッドボード用になっているので先バラがないかと探してみたらaitendoにあったのでこれを使ってみます。(今見たら売り切れてた。。)

 

 

 

接続:

 

SPS30 pin     ESP32

  1 VCC -------- VUSB

  2 RX  -------- TX  pin 26

  3 TX  -------- RX  pin 25

  4 Select      (NOT CONNECTED)

  5 GND -------- GND

 

 

スケッチは こちらのサンプルを参考にして

 

https://github.com/paulvha/sps30

 

このクラスライブラリ、ESP32用と書いてありますが、Example1_sps30_BasicReadings がそのままでコンパイルが通りません。 ライブラリソースSPS30.h を開いて、

 

#define INCLUDE_SOFTWARE_SERIAL 1

 

の行をコメントアウトしてください。

 

Example1_sps30_BasicReadings.ino をコンパイルして実行すると計測を開始します。

 

動作中センサ内のモータが動いているのがわかります。

 

 

-------------Mass -----------    ------------- Number --------------   -Average-

     Concentration [μg/m3]             Concentration [#/cm3]             [μm]

P1.0    P2.5    P4.0    P10    P0.5    P1.0    P2.5    P4.0    P10    PartSize

 

0.94    1.33    1.61    1.70    5.59    7.06    7.43    7.48    7.49    0.61

1.08    1.13    1.13    1.13    7.51    8.67    8.69    8.69    8.69    0.46

1.25    1.30    1.30    1.30    8.71    10.05    10.08    10.08    10.08    0.41

1.35    1.41    1.41    1.41    9.38    10.82    10.85    10.85    10.85    0.43

1.43    1.49    1.49    1.49    9.92    11.44    11.48    11.48    11.48    0.39

1.47    1.52    1.52    1.52    10.17    11.73    11.77    11.77    11.77    0.41

1.50    1.57    1.57    1.57    10.45    12.05    12.09    12.09    12.09    0.43

1.57    1.64    1.64    1.64    10.92    12.59    12.63    12.63    12.63    0.43

1.60    1.66    1.66    1.66    11.09    12.79    12.83    12.83    12.83    0.42

1.65    1.71    1.71    1.71    11.44    13.19    13.23    13.23    13.23    0.43

1.69    1.76    1.76    1.76    11.73    13.52    13.56    13.56    13.56    0.45

1.73    1.80    1.80    1.80    12.04    13.89    13.93    13.93    13.93    0.44

 

計測はできたので次にwww post する機能など追加したいと思います。

 

 

 

 

 

昨年作った ハロウィン用LEDチカを今年も作ってみました

 

 

 

今回は秋月のLEDストリングを使ってやってみます。

LEDストリングは4-5個づつ切り取って、抵抗値は 220Ωでやってみます。

 

LEDストリング

 

今回はATTiny13Aのウォッチドッグタイマーを使ってDeppSleepをさせながら動かしてみました。

512msecのWDタイマーで0.5sec点灯 1sec消灯にしてみます。

 

ウォッチドッグの省電力化はなかなかです。CR2032一個で2週間くらい点灯しっぱなしですが、まだ光っています。

 

消費電力を計算してみます  LEDの電圧降下2.8V として

 

(3-2.8)/220 * 2 = 0.9 mA

 

これが連続ではなく1.5sec間に0.5sec なので消費電力約1/3。 CR2032ボタン電池の容量が 220mAHなので、、、ATTinyの待機電流は10μAとかなのでとりあえず無視。

 

220/(0.9/3) = 733h   ... 30日


大分長持ちする計算です。少なくとも20日くらいは持つと考えて良いでしょう。

 

 

 

スケッチはこんな感じ

 
/*
     Blink 2 LEDs
     for  ATTiny13 LED Board

     2018/10/17
 
   PCINT5/A0/D5/RST |1---O---8| VCC
      *PCINT3/A3/D3 |2       7| D2/A1/INT0/PCINT2*
       PCINT4/A2/D4 |3       6| D1/PWM/PCINT1
                GND |4-------5| D0/PWM/A0/PCINT0*

  *Use PIN
  PIN5 (D0) ... PCINT SW ON/OFF connect to GND
 
 */
 
//#include <avr/pgmspace.h>

#include <avr/interrupt.h>
#include <avr/sleep.h>

#define LED1 3
#define LED2 4
#define LED3 0
#define LED4 1
#define LED5 2

volatile int pcint;
volatile bool wait;

/*
 *    Random
 */

unsigned int randshort(unsigned int init)
{
  static unsigned int seed;
  if(init!=0){
  seed ^= init;
  }
  seed *= 52341;
  seed += 37;
  return(seed ^ 0x1234);
}


ISR(PCINT0_vect) {
  if(digitalRead(0)==0){
    pcint=pcint ^ 1;
  }
}  


void setup() {
  randshort(analogRead(0));
  pinMode(LED1, OUTPUT);
//  pinMode(LED2, OUTPUT);
//  pinMode(LED3, OUTPUT);
//  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);

  pinMode(0, INPUT_PULLUP);
  GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
  PCMSK |= _BV(PCINT0);                   // Use PB1 as interrupt pin for My Board

  // set timer to 0.5s
  WDTCR |= (1<<WDP2) | (1<<WDP0);

// set timer to 4 sec
//  WDTCR |= (1<<WDP3);

// Set watchdog timer in interrupt mode
  WDTCR |= (1<<WDTIE);
  WDTCR |= (0<<WDE);
  sei(); // Enable global interrupts
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}


ISR(WDT_vect) {

}

void loop() {
  static unsigned char d;
  static unsigned char t;

  if(pcint){
    sleep_mode();
    return;
  }


//  d = randshort(0) & 0x60;

//  digitalWrite(LED1,(d & 0x11));
//  digitalWrite(LED2,(d & 0x22));
//  digitalWrite(LED4,(d & 0x44));
//  digitalWrite(LED5,(d & 0x88));
//  digitalWrite(LED3,(d & 0x41));

  d = randshort(0) & 0x05;
//  d++;
  digitalWrite(LED1,(d));
  digitalWrite(LED5,(d^0x01));
//  digitalWrite(LED2,(d^0x01));

  sleep_mode();
  digitalWrite(LED1,0);
  digitalWrite(LED5,0);
//  digitalWrite(LED2,0);
  sleep_mode();
  sleep_mode();

}
 
----------------------