SSブログ

AtomS3 Liteで赤外線リモコン [Arduino]

AtomS3 Liteには赤外線LEDが付いていて、サンプルにもNECタイプのリモコンスケッチがあった。
でも、うちのテレビはソニー製。うちのソニーのテレビリモコンは電源ボタン以外は赤外線ではないものの、テレビ本体は赤外線リモコンの受信は可能。
というわけで、サンプルスケッチをいじってソニーのテレビの操作。
といってもボタンも1つしかないので単機能、ミュートのトグル。

// Infrared remote control  (M5atomS3, SIRC version)
#define DISABLE_CODE_FOR_RECEIVER
#define SEND_PWM_BY_TIMER                       // use hardware PWM
#define IR_TX_PIN 4
#include "M5AtomS3.h"
#include <IRremote.hpp>

void setup() {
    auto cfg = M5.config();
    AtomS3.begin(cfg);
    IrSender.begin(DISABLE_LED_FEEDBACK);       // Start with IR_SEND_PIN as send pin
    IrSender.setSendPin(IR_TX_PIN);
}

void loop() {
    AtomS3.update();
    if( AtomS3.BtnA.wasPressed() ) {
        IrSender.sendSony( 0x01, 0x14, 3, SIRCS_12_PROTOCOL );  // SONY TV mute toggle
    }   // address:0x01(TV,5bits), command:0x14(mute,7bits), repeat:3times, 12bits
}

それにしても、うちの遅いパソコンではコンパイルに時間がかかる。

調べてみると、ESP32は簡単にPWMをつくることができるようだ。
というわけでリモコン信号も簡単にできた。

// Infrared remote control with 40kHz PWM (ESP32, SIRC version)
uint8_t ledIR = 4;

void setup() {
  ledcSetup( 1, 40000, 8 );             // 40 kHz PWM, 8-bit resolution
  ledcAttachPin( ledIR, 1 );            // assign IR LED pin to channel
  pinMode( 41, INPUT_PULLUP );
}

void loop() {
  while( digitalRead( 41 ) );
  sendIrSIRCesp32( 0x14 | 0x01 << 7 );  // SONY mute toggle (cmd:0x14(7bit), adrs:0x01(5bit))
  sendIrSIRCesp32( 0x14 | 0x01 << 7 );  //   repeat 3 times
  sendIrSIRCesp32( 0x14 | 0x01 << 7 );
}

void sendIrSIRCesp32( uint32_t d ) {                    //   T = 0.60msec
  uint8_t  b = (d & 0xF8000) ? 20 : 
               (d & 0x07000) ? 15 : 12;                 // number of bits
  uint16_t usON, usTrailer = 42000;                     // 70T = interval(75T) - leader(5T)
  ledcWrite( 1, 85 ); delayMicroseconds( 2400 );        // leader ON  (4T)
  ledcWrite( 1,  0 ); delayMicroseconds(  600 );        // leader OFF (1T)
  for(uint8_t i = 0; i < b; i++) {                      // data(command + address)
    usON = ((d>>i)&1) ? 1200 : 600;                     // data(0:1T / 1:2T)
    ledcWrite( 1, 85 ); delayMicroseconds( usON );      // data ON
    ledcWrite( 1,  0 ); delayMicroseconds(  600 );      // data OFF (1T)
    usTrailer -= (usON + 600);                          // trailer
  }
  delayMicroseconds( usTrailer );
}

ライブラリ不要となり、多少コンパイル時間も短くなり、プログラムのサイズも減った。

m5atoms3ir.jpg
AtomS3 Liteの赤外線LEDが光っている様子。
nice!(0)  コメント(0) 

AtomS3 Lite 買ってみた。 [Arduino]

無線(というかWi-Fi)を使ってみたくてちょっと調べてみた。

・Uno R4 WiFi でもいいんだけど、、小さいやつ希望
・type-Cで
・技適通ってるやつで
・DIPの幅狭めで
・新しめで
・情報多めのやつで

Nano ESP32 | Arduino Documentation
https://docs.arduino.cc/hardware/nano-esp32
nanoesp32.jpg
「Arduino Nano ESP32」がtype-CでArduino純正のボードだけど、技適通ってないっぽい。

Seeed Studio XIAO ESP32S3 — スイッチサイエンス
https://www.switch-science.com/products/8968
xiaoesp32s3.jpg
同じESP32S3使ってる「Seeed Studio XIAO ESP32S3」もいいけど、アンテナが外付け&本体よりでかい。
ESP32-C3 か S3 かどっちがいいのかもよくわからない。
UNO R4 WiFi や nano ESP32 には S3 が載っているので、とりあえず S3 の方向で。

ほかにESP32S3で探すと、M5Stack関連が出てきた。
M5Stackというとディスプレイとかボタンとかいろいろ付いている系と思っていたけど、割とシンプルなボードもあったので購入してみた。

AtomS3 Lite
https://docs.m5stack.com/en/core/AtomS3%20Lite
atoms3lite_p.jpg
AtomS3 Lite:ボタン、RGB LED、赤外線LEDが付いている。

M5StampS3 PIN2.54
https://docs.m5stack.com/en/core/M5StampS3%20PIN2.54
m5stamps3_p.jpg
M5stampS3:ボタン、RGB LEDだけ。ブレッドボードで遊べるように2.54mm DIPタイプを選択。

とりあえず、AtomS3 Liteを開封
atoms3lite_1.jpg
技適通ってる。

atoms3lite_2.jpg
裸眼では読めない部分あり。




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

UNO R4で音楽演奏 [Arduino]

音楽演奏のスケッチをいろいろなバージョンで作ってきたけど、UNO R4でもやってみた。

・DAC(12bit)を使用
・正弦波は計算で作成
・音程も計算で作成
・レジスタ触らない
・ところどころブラッシュアップ

r4music.jpg
10kΩの可変抵抗の前に100kΩの抵抗を挟んで約10分の1に分圧したらボリュームとしてちょうどいい感じ。(理論上は40kΩかな)

楽譜の作成と定義のファイルは以前と同様。
https://hello-world.blog.ss-blog.jp/2022-07-04

// Uno R4 DAC Score Replay Sketch
#include "notes2.h"                     // note definition data (pitch(octave,scale) + length)
#define F_SAMP      50000               // sampling frequency (Hz) (divisor of 1,000,000 (usec))
#define MAX_TRACK   4                   // Maximum tracks
static uint16_t   SIN[256];             // array of sine wave
static uint16_t   OCT9[12];             // array subscript difference in the 9th octave
static const uint16_t Jesus[] = {       // J.S.Bach "Jesu, Joy of Man's Desiring"
  125 , 0 ,
  b4e , g4e , a4e , b4e , d5e , c5e , c5e , e5e , d5e , d5e , g5e , F5e , g5e , d5e , b4e , g4e , a4e , b4e ,
  e4e , d5e , c5e , b4e , a4e , g4e , d4e , g4e , F4e , g4e , b4e , d5e , g5hd,                           0 ,
  d4q       , F4e , g4q       , F4e , g4q       , a4e , b4q       , a4e , b4q       , g4e , e4q       , g4e ,       
  a4q       , F4e , g4q       , e4e , a3q       , c4e , b3w ,                                             0 ,
  g3qd            , e3qd            , c3qd            , b2qd            , e3qd            , d3qd            ,
  c3qd            , C3qd            , d3qd            , g2w ,                                             0 , 0 };
  
void setup(){
  uint16_t  i;
  analogWriteResolution(12);
  for(i=0; i<256; i++)  SIN[i]  = 16383.9 * (1 - cos(6.283185 * i / 256)) / 2;      // 14bit sine wave
  for(i=0; i< 12; i++)  OCT9[i] = (440 << 16) * pow(2, (i + 51) / 12.0) / F_SAMP;   // A4=440
}

void loop(){
  playR4( Jesus );
}

void playR4( const uint16_t *score ){ 
  uint8_t  Tracks = 0;                  // track count
  uint16_t note;                        // note (pitch(octave,scale) + length)
  uint16_t NoteCycle, n;                // reference note (96th note) cycle and its counter (n)
  uint16_t   p[MAX_TRACK];              // pointer for each track
  uint8_t  len[MAX_TRACK];              // note length (how many 96th notes)
  uint16_t   s[MAX_TRACK] = {0};        // waveform subscript  (s)  (x256)
  uint16_t  ds[MAX_TRACK] = {0};        //  and its difference (ds) (x256)
  uint16_t env[MAX_TRACK];              // sound envelope
  uint16_t atn = 0, Atn;                // attenuation counter and initial value
  // *** Preparing Scores ***
  Atn = 150 * F_SAMP / 1000 / 356;                  // attenuation half-life : 150 msec
  NoteCycle = F_SAMP *4*60 / score[0] / MIN_NOTE;   // reference note(96th note) cycles
  for( uint16_t i = 1; Tracks < MAX_TRACK; ) {      // Get track count and starting location
    if( score[i++] != 0 ) continue;     // Skip until 0 comes
    if( score[i]   == 0 ) break;        // If two 0s follow, end of data
    len[ Tracks ] = 1;                  // note length subtraction counter to 1
    p[ Tracks++ ] = i;                  // Get location in memory, Count up the tracks
  }
  // *** Playback ***
  n = Tracks;                           // To play immediately after the loop starts
  uint32_t  usInt = 1000000 / F_SAMP;   // sampling time interval(usec)
  uint32_t  usPre = micros();           // sampling time previous value(usec)
  do {
    if( --n < Tracks ) {                // Processing of score for each reference note length
      if( !--len[n] ) {
        note   = score[ p[n]++ ];
        len[n] = note & 0x00ff;         // The lower 8 bits are note length (Multiples of 96th notes)
        if( note & 0xff00 ) {           // If not a rest... (Leave a lingering sound even with rests)
           ds[n] = OCT9[ (note>>8) & 0x0f ] >> (9 - (note>>12));    // increment subscript (x256)
            s[n] = 0;                   // start of waveform cycle
          env[n] = 0xffff;              // the maximum amplitude initially
        }
      }
      if( !n ) n = NoteCycle;
    }
    switch( Tracks ) {                  // Change output by number of tracks
      case 1: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0] ) >> 18 );  // 14x16=30bit >> 18 = 12bit
              break;
      case 2: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0]
                                + SIN[ (s[1]+=ds[1])>>8 ] * env[1] ) >> 19 );  // 30/30(31bit)
              break;
      case 3: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0]
                                + SIN[ (s[1]+=ds[1])>>8 ] * env[1]
                                + SIN[ (s[2]+=ds[2])>>8 ] * env[2] ) >> 20 );  // 30/30/30(31.5bit)
              break;
      case 4: analogWrite( DAC, ( SIN[ (s[0]+=ds[0])>>8 ] * env[0]
                                + SIN[ (s[1]+=ds[1])>>8 ] * env[1]
                                + SIN[ (s[2]+=ds[2])>>8 ] * env[2]
                                + SIN[ (s[3]+=ds[3])>>8 ] * env[3] ) >> 20 );  // 30/30/30/30(32bit)
    }
    if( !atn-- )            atn   = Atn;            // subtract attenuation counter
    if(  atn < Tracks ) env[atn] -= (env[atn]>>9);  // amplitude attenuation
    while( micros() - usPre < usInt );              // wait for next cycle
    usPre += usInt;
  } while( note );                      // Exit if note data is 0
  analogWrite( DAC, 0 );                // Set output to 0
}

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