踏切警報音 UNO R4

踏切警報音スケッチをUNO R4用にも作ってみた。
UNO R4にはDACがあるのと、速度も速いので、レジスタ操作なしの純粋Arduinoでいけた。
量子化ビット数は DACの12ビット。
micros()でタイミングをとっているので、サンプリング周波数は 1,000,000(μsec)の約数。そのなかで処理が間に合う最大の50kHzとした。

UNO R4はAVRマイコンに比べてドライブ能力が低いので、アンプを使わないとそこそこの音量が出ないのが難点。
r4_piezo.jpg
とりあえず圧電サウンダで。


// railroad crossing sounds and signals : UNO R4
#define F_SAMP    50000         // sampling frequency (Hz) (divisor of 1,000,000 (usec))
#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)
     { 700,  750 },            // JR etc.
     { 450,  550 },            // ODAKYU
     { 550,  650 },            // TOKYU, KEIKYU  
     { 600,  650 },            // TOBU
     { 520,  660 }             // SEIBU
};
static uint16_t  SIN[256];      // array of sine wave

void setup() {
 analogWriteResolution(12);    // A0 : DAC
 pinMode( A1, OUTPUT );        // A1 : LED1
 pinMode( A2, OUTPUT );        // A2 : LED2
 pinMode( A3, INPUT_PULLUP );  // A3 : SW
 for (uint16_t i = 0; i < 256; i++) {
   SIN[i] = 32767.9 * (1 - cos(6.283185 * i / 256)) / 2;       // 15bit
 }
}

void loop() {
 static uint8_t ch;
 uint16_t  cDing, iDing = 60 * F_SAMP / F_DING;        // counter and initial cycles of ding sound
 uint16_t  cSign, iSign = 60 * F_SAMP / F_SIGN;        // counter and initial cycles of lignt signal
 uint16_t  cAttn, iAttn = ATHALF * F_SAMP /1000 /356;  // counter and initial cycles of attenuation
 uint16_t  iA, diA = (FRQ[ch][0] << 16) / F_SAMP;      // array subscript and its difference
 uint16_t  iB, diB = (FRQ[ch][1] << 16) / F_SAMP;
 uint16_t  env;                                        // envelope
 uint32_t  usInt = 1000000 / F_SAMP;                   // sampling time interval(usec)
 uint32_t  usPre = micros();                           // sampling time previous value(usec)
 digitalWrite( A1, HIGH );     // LED1 On
 digitalWrite( A2, LOW  );     // LED2 Off
 cDing = cSign= 0;
 do {
   if( !cDing-- ) {            // reset ding counter
     cDing = iDing;
     cAttn = iAttn;
     env   = 0xffff;
     iA    = 0;
     iB    = 0;
   }
   if( !cAttn-- ) {            // reset attenuation counter
     cAttn = iAttn;
     env  -= env >> 9;
   }
   if( !cSign-- ) {            // reset light counter
     cSign = iSign;
     digitalWrite( A1, !digitalRead(A1) );
     digitalWrite( A2, !digitalRead(A2) );
   }
   analogWrite( DAC, (SIN[(iA+=diA)>>8] + SIN[(iB+=diB)>>8]) * env >> 20 );
   while( micros() - usPre < usInt );
   usPre += usInt;
 } while( digitalRead(A3) );   // Press the tact switch to end
 analogWrite( DAC, 0 );
 digitalWrite( A1, LOW  );     // LED1 Off
 digitalWrite( A2, LOW  );     // LED2 Off
 delay(1000);
 if( ++ch == sizeof(FRQ)/sizeof(*FRQ) ) ch = 0;
}

この記事へのコメント