SSブログ

踏切警報音 リトライ [Arduino]

以前にも踏切の音を出してみるのをやったけど、もうちょっとリアルに。



以下から情報をいただきました。感謝。

【参考にさせていただいたところ】
Web Nucky Blog |踏切警報音の実験 その1
 https://webnucky.blog.fc2.com/blog-entry-296.html
踏切警報音 - くるまや軽便鉄道 PartⅡ
 https://kurumayakeiben.wordpress.com/category/%E8%B8%8F%E5%88%87%E8%AD%A6%E5%A0%B1%E9%9F%B3/
鉄道マニヤに捧ぐ 首都圏主要鉄道会社の踏切音に使用される微分音:左近治の囈(たはごと):SSブログ
 https://tawauwagotsakonosamu.blog.ss-blog.jp/2019-09-19

★いきなりまとめ
・本物の踏切の音と光は安全のため別回路になっていて、同期していない。
・現在の電子ホーン式のほかに電鈴式、電鐘式がある。
・音は2(~3(京急))和音で、12音階に属さない「微分音」というものらしい。
  JR、相鉄、名鉄、京阪、近鉄、阪神、西鉄、阪急、南海、京成 他 700Hz、750Hz
  小田急 450Hz、550Hz
  東急、京急 550Hz、650Hz
  東武 600Hz、650Hz
  西武 520Hz、660Hz

★スケッチの方向性
・ATtiny202 (megaTinyCore) を使う
・TCA0のPWMをDACもどきとして使用 (mills(), micros()や他のPWMは使用不可)
・電子ホーン式のみ
・CPU周波数に依存しない

スケッチつくったけど、半分くらいが初期値の設定やレジスタ設定や正弦波の配列などで埋まりました。
音の周波数の組み合わせを選択できるようにした。
音のリズムはとりあえず130/分にしたけど変更可能。
正弦波、鋸歯状波、矩形波を試してみたけど、正弦波が一番近いかな?
踏切の動画をミュートで見ながら、手元で音を出しても違和感なし。

// railroad crossing sound and signals : ATtiny202 (megaTinyCore 4-20MHz)
#include <util/delay.h>
#define F_SIGN    100           // light signal : 100/min (1.666Hz, 0.6  sec)
#define F_DING    130           // ding sound   : 130/min (2.166Hz, 0.461sec)
#define ATHALF    200           // attenuation half-life : 200 msec
static const uint16_t FRQ[][2] = {              // frequency combination (Hz)
      { 750,  700 },            // JR, SOTETSU, MEITETSU, KEIHAN, KINTETSU, HANSHIN, NISHITETSU, HANKYU, NANKAI, KEISEI..
      { 450,  550 },            // ODAKYU
      { 550,  650 },            // TOKYU, KEIKYU  
      { 600,  650 },            // TOBU
      { 520,  660 }             // SEIBU
};
static const uint8_t  SIN[] = {                 // array of sine wave
    0,  0,  0,  0,  1,  1,  1,  2,  2,  3,  4,  5,  5,  6,  7,  9,  10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
   37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,  79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124,
  128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,
  218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244, 245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,
  255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246, 245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,
  218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179, 176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,
  128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82,  79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40,
   37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11,  10,  9,  7,  6,  5,  5,  4,  3,  2,  2,  1,  1,  1,  0,  0,  0 
};

void setup() {
  PORTA.DIRSET        = PIN7_bm;                // PA7   SP  OUTPUT (mTC:1) (mTC default : PA3(mTC:4) to PA7(mTC:1) )
  PORTA.DIRSET        = PIN1_bm | PIN2_bm;      // PA1,2 LED OUTPUT (mTC:2,3)
  PORTA.DIRCLR        = PIN3_bm;                // PA3   SW  INPUT  (mTC:4)
  PORTA.PIN3CTRL      = PORT_PULLUPEN_bm;
  TCA0.SINGLE.INTCTRL = 0;                      // turn off Arduino(mTC) time system
  TCA0.SINGLE.CTRLD   = 0;                      // turn off split mode
  TCA0.SINGLE.CTRLC   = 0;                      // PWM output pins override - disable
  TCA0.SINGLE.CTRLB   = TCA_SINGLE_CMP0EN_bm    // enable compare channel 0
                      | TCA_SINGLE_WGMODE_SINGLESLOPE_gc;   // set Single-slope PWM mode
  TCA0.SINGLE.CTRLA   = TCA_SINGLE_CLKSEL_DIV1_gc           // 20MHz / 1 / 256 -> 78,125Hz
                      | TCA_SINGLE_ENABLE_bm;   // start timer 
  TCA0.SINGLE.PERBUF  = 0xff;                   // top value = 255
}

void loop() {
  static uint8_t  ch = 0;
  uint16_t  cDing,  iDing = 60 * (F_CPU >> 8) / F_DING;         // counter and initial cycles of ding sound
  uint16_t  cSign,  iSign = 60 * (F_CPU >> 8) / F_SIGN;         // counter and initial cycles of lignt signal
  uint16_t  cAttn,  iAttn = ATHALF * (F_CPU >> 8) / 1000 / 356; // counter and initial cycles of attenuation
  uint16_t  iA, diA = FRQ[ch][0] * 0x010000 / (F_CPU >> 8);     // array subscript and its difference
  uint16_t  iB, diB = FRQ[ch][1] * 0x010000 / (F_CPU >> 8);
  uint16_t  env;                                                // envelope
  PORTA.OUTSET = PIN1_bm;                       // LED On
  PORTA.OUTCLR = PIN2_bm;                       // LED Off
  cDing = cSign= 0;
  do{
    if( !cDing-- ) {                            // reset ding conter
      cAttn = iAttn;  env = 0xffff;   cDing = iDing;  
      iA = iB = 0;
    }
    if( !cAttn-- ) {                            // reset attenuation conter
      cAttn = iAttn;  env -= (env>>9);
    }
    if( !cSign-- ) {                            // reset light counter
      cSign = iSign;
      PORTA.OUTTGL = PIN1_bm | PIN2_bm;         // toggle LEDs
    }
    TCA0.SINGLE.CMP0BUF = ( SIN[ (iA+=diA)>>8 ] + SIN[ (iB+=diB)>>8 ] ) * (env>>9) >>8;
    while( !(TCA0.SINGLE.INTFLAGS & TCA_SINGLE_OVF_bm) );       // Waiting for TCA0 overflow
    TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;   // cleared by writing a '1'
  } while( (PORTA.IN & PIN3_bm) );
  PORTA.OUTCLR = PIN1_bm | PIN2_bm;             // turn LEDs off
  TCA0.SINGLE.CMP0 = 0;
  _delay_ms(1000);
  if( ++ch == sizeof(FRQ)/sizeof(*FRQ) ) ch = 0;
}

202railroadc.jpg
小さいスピーカより大きめのスピーカのほうがいい音が出た。
attenuation.png
音の減衰具合。半分の値になるのが、356cyclesくらい。

nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

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

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。