2021.8.10 ATmega328にプログラムを書込む

本日のトピック

以前のブログで、ATmega328のブートローダを書き込みました。

今回は、この続きとして、ATmega328にArduinoと同様にプロブラムを書き込みます。

まず、プログラムを書き込むのに、PCと接続する必要がありますよね。ですが、ATmega328にはUSBがありません。

さてはまた純正のArduinoを用意するかと思いますが、もっと安いもので代用が出来ます。

それが、USB-シリアル変換器です。

USB-TTL変換器

FTDI社FT232RQを使ったUSBシリアル変換モジュールです.
・WindowsXP~10まで幅広いドライバーが有り対応しています。
・DIPスイッチで5V/3.3Vの信号レベルの変更が可能です。

端子は、+5V、GND、CTS、TXD、RXD 、RTSの六端子です。

TXD,RXDということは、そうですUARTの通信になります。

 

ATmega328との接続

次に、ATmega328との接続方法です。

UARTの通信ですので、変換器のTXD(送信)を,ATmega328のRXD(受信)に、変換器のRXD(受信)をATmega328のTXD(送信)に接続します。あとは、TTL変換器の+5VとGNDを、ATmega328にも供給します。

そして、変換器からリセットの信号を送れるように、RTSとATmega328のResetを、0.1uFのコンデンサを経由して接続します。

あとは、ATmega328のクロックとして、16MHzの水晶発振子を接続します。

Arduino IDEの設定

TTL変換器をUSBに接続すれば、あとは普通のArduinoと同様に書き込むことが出来ます。

ただ、ここで書き込めるのは、ブートローダを書込み済のマイコンに限ります。

ブートローダの書込み方法は下記に示しますので参考にしてください。

・ブートローダ書込み方法

さて、Arduinoと同様に書けるとは言ったものの、ATmega328でも、ATmega328P-PUと、ATmega328Uでは少し、設定が違います。

ATmega328P-PUの書込み設定

ATmega328P-PUは、少し割高ですが、純正品のArduino UNOと同じチップを使っているので、「ツール」を開いた設定画面では、ボード「Arduino Uno」を選び、あとはTTL変換器を繋いでいるCOMポートを選択すれば、これで書き込めてしまいます。

Arduino IDEを開きプログラミング
ATmega328P-PUの設定

ATmega328 U(ATmega328PU)

Arduinoに初期から入っているボードマネージャーでは、ATmega328は書き込めません。

「ツール」→「ボード」→「ボードマネージャー」を開き、MiniCoreと検索し、インストール。

ボードマネージャーを起動
MiniCoreをインストール

Arduinoを再起動して、「ツール」→ボード→「MiniCore」→「ATmega328」を選択します。

ボードはATmega328を選択

あとは、左上の書込みボタンで書き込めます。

2021.8.7 SRF-02の使い方

本日のトピック

今回は、超音波センサSRF-02のコマンドについて調べました。

まず、SRF-02の通信には二つのモードがあり、I2CとUARTがありますが、今回はI2Cに焦点を当てて説明します。

まずは、SRF-02の主な特徴です。

◆主な仕様
・使用マイコン:16F687-I/ML
・測定範囲:16cm~6m.
・電源:5V(消費電流4mA Typ.)
・使用周波数:40KHz.
・アナログゲイン:64段階の自動ゲインコントロール
・接続モード:モード1=I2C、モード2=シリアルバス
・全自動調整機能:電源投入後キャリブレーション不要
・測距タイミング:エコー時間計測、ホストによるタスクコントロール
・測定単位:μS(マイクロ秒)、ミリ、インチ
・サイズ:24mmx20mmx17mm
・入出力端子:5ピン
・重量:4.6グラム

SRF-02の主なコマンド

次に、SRF-02で使用される主なコマンドです。

コマンドの通信方法は、ArduinoのWireライブラリを使って通信します。詳細は、以前のブログを参照してください。

I2Cでの通信方法

SRF02をI2Cモードで使用するには、モードピンをオープンにします。

I2Cの通信では、最大16個まで並列で接続できます。並列でつなぐので、それぞれのSlave(超音波センサ)にアドレスを振り分けます。
SRF02の出荷時のアドレスは0xE0です。アドレスはユーザによって変更することができ、最大16個(E0、E2、E4、E6、E8、EA、EC、EE、F0、F2、F4、F6、F8、FA、FC、FE)のアドレスが使用できます。

 

レジスタ

SRF-02には6種類のレジスタがあります。

ロケーション 読む書く
0 ソフトウェアリビジョンコマンドレジスタ
1未使用(0x80を読み取ります)該当なし 
2測定値 上位バイト該当なし
3測定値 下位バイト該当なし
4オートチューン最小-上位バイト該当なし
5オートチューン最小-下位バイト該当なし
レジスタ

 

6個あるレジスタのうち、Masterから書き込むことができるのは、0番のレジスタのみです。

すべて、0番のレジスタに数値を入れることでSRF-02の様々な設定ができます。

0番から読み出す場合は、ソフトウェアリビジョンを返されます。1番は使用していない空きピンです。

2,3番のレジスタが、測定した数値を返すレジスタです。測定値は最大2byteの容量で返します。レジスタ1個は1byteですので、レジスタが二つ(2,3)必要なわけです。この測定値は、設定の状態によって、インチ、センチ、マイクロ秒などで返します。

4、5番のレジスタは、16ビットの符号なし最小範囲です。これは、ソナーが測定できるおおよその最も近い範囲です。

つまり最初0番で指定をしたら、あとは2,3番のレジスタで測定値を参照すればよいということです。

 

SRF-02のコマンド

下記が、SRF-02の0番に指定するコマンドです。

  2進数    16進数  動作
800x50Real Ranging Mode – Result in inches
810x51Real Ranging Mode – Result in centimeters
820x52Real Ranging Mode – Result in micro-seconds
860x56Fake Ranging Mode – Result in inches
870x57Fake Ranging Mode – Result in centimeters
880x58Fake Ranging Mode – Result in micro-seconds
920x5CTransmit an 8 cycle 40khz burst – no ranging takes place
960x60Force Autotune Restart – same as power-up. You can ignore this command.
1600xA01st in sequence to change I2C address
1650xA53rd in sequence to change I2C address
1700xAA2nd in sequence to change I2C address
コマンド

必要に応じて、上記のコマンドを1番のコマンドレジスタに書き込み、必要な時間待機して結果を読み取ります。エコーバッファは、各レンジングの開始時にクリアされます。レンジングは最大66m秒持続します。この後、測定値を2,3番のレジスタから読み取ります。

SRF-02の命令方法

MasterからSRF-02に命令する場合、どのようにしたらよいでしょうか。

下記が、参考に、測定値をcmにするプログラムです。

Wire.beginTransmission(226); //通信先のアドレス
  Wire.write(0x00);    //レジスタを選ぶ
  Wire.write(0xA0);  //コマンドを選ぶ
  Wire.endTransmission();

順番としては、まず Wire.beginTransmission(226); で、Slaveのアドレス(226)を指定。

次に送信するものは、接続するレジスタになります。なにか設定などをする場合は、

0番のレジスタにアクセスするため、Wire.write(0x00);で0を送ります。

次に、送るものが設定するコマンドです。

例えば、測定値をcmで返す設定をする場合は、コマンド0x51を送ればよいので、

Wire.write(0x51);となります。

設定はこれで終了なので、 Wire.endTransmission(); で今回の通信を終わります。

コマンドの内容にもよりますが、基本は、レジスタを指定→そのレジスタのコマンドを送る、の流れです。

 

SRF-02の測定値を読み出すプログラム

次に、SRF-02から測定値を読み出す方法です。

      Wire.beginTransmission(0xE0); // transmit to device #112
      Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
      Wire.endTransmission();      // stop transmitting

     
      Wire.requestFrom(0xE0, 2);    // request 2 bytes from slave device #112
    
      if (2 <= Wire.available())   // if two bytes were received
      {
        reading = Wire.read();  // receive high byte (overwrites previous reading)
        reading = reading << 8;    // shift high byte to be high 8 bits
        reading |= Wire.read(); // receive low byte as lower 8 bits
        Serial.print(reading);   // print the reading
        Serial.println("cm");
      }

まず、SRF-02から数値を読み出す場合、2番目のレジスタ0x02にアクセスします。それが、3行目までのプログラムです。

次に、SRF-02からデータを受信する準備をします。それが、 Wire.requestFrom(0xE0, 2); です。

これは、アドレスE0のSlaveから、2byteのデータを受け取りますという意味です。

あとは Wire.read();で、データを受け取ることが出来ます。しかし、2byteあるため、そのまま受け取ると下位ビットが上書きされます。そのため、まず、上位8ビットのデータを受け取り( reading = Wire.read(); )、readingのビットを (reading = reading << 8; )8bit高い位にシフトさせてから、次に飛んでくる数値(下位ビット)を ( reading = Wire.read(); ) で受信します。

Slaveで分割されたデータは、上位ビットから書き込まれる

そのまま下位ビットを書き込むと上書きされてしまう

そこで、最初に書き込まれた上位ビットを8ビット上にシフト

そのあとで下位ビットを書き込めばすべて正しく送れる

 

 

SRF-02のアドレス指定

次に、SRF-02のアドレス指定手順です。方法は簡単で、上記コマンドの0xA0, 0xAA, 0xA5,を順番に送り、最後に新しいアドレスを送ることで、アドレスを指定するモードになります。例えば、もともとのアドレスE0から新しいアドレスF4に帰る場合は下記のプログラムを動かします。とてもシンプルですよね。

  Wire.beginTransmission(0xE0);
  Wire.write(0x00);
  Wire.write(0xA0);               //A0を書き込む
  Wire.endTransmission();

  Wire.beginTransmission(0xE0);
  Wire.write(0x00);
  Wire.write(0xAA);               //AAを書き込む
  Wire.endTransmission();

  Wire.beginTransmission(0xE0);
  Wire.write(0x00);
  Wire.write(0xA5);               //A5を書き込む
  Wire.endTransmission();

  Wire.beginTransmission(0xE0);
  Wire.write(0x00);
  Wire.write(0xF4);               //新しいアドレスF4を書き込む
  Wire.endTransmission();

今日は、ここまで。

 

2021.8.7 ひいらぎ

2021.8.3 ATmega328にブートローダを書き込む

本日のトピック

今回は、市販のAVRマイコンのATmega328を、Arduinoとして使うための処理をします。

ATmega328とは、Arduinoに搭載されているマイコンチップです。

Arduinoは、定価で買うと大体3000円程度。基板も大きいので実装には不向きです。

そこで、ATmega328を単体でArduinoとして使うようにします。

ATmega328は、通販サイトで結構売られています。

ただ、最近は半導体不足によりATmega328の表面実装や、ATmega328P-PUなどは手に入りにくい状況です。

今のところ、まだ在庫はありそうです。

RSコンポーネンツで一つ323円です。つまり、Arduinoの10分の1の価格で小サイズのArduinoが使えるわけです。

RSコンポーネンツ ATmega328-PU 通販ページ

今回は、このICにArduinoとして使うためのブートローダを書き込みます。

そもそも、ブートローダとは何でしょうか。

 

ブートローダとは

ブートとは、コンピュータなどでOSなどの基本ソフトウェアを起動することを意味する俗語。ブートローダとは、このときに、OS本体や「OSをロードするためのソフトウェア」をメモリに読み込むための小さなソフトウェアを言います。このプログラムは、ATmegaマイコンを動かす上の基礎てきなソフトです。初期設定みたいなものなので、一度書き込んでしまえば、ずっと使えますし、ソフトも何回も書き換えれます。

 

ブートローダを書き込む準備

ブートローダを書き込むためには、純正品のArduinoを用意してください。ATmega328とSPI方式で通信する必要があり、そのために純正のArduinoが必要になります。

純正のArduinoは基本的になんでも構いません。私は、ブレットボードに刺せるArduino Nanoを使いました。

Arduino Nano
ATmega328PU

 Arduino NanoとATmega328PUの配線図は下図の通りです。

要するに、ArduinoNanoとATmega328でSPI通信を行いたいため、お互いのMISO、MOSI、SCKと+5V、GNDを接続します。あとは、ArduinoNanoが指定するタイミングで、328のResetをかけるため、NanoのD10と328のResetを接続し、6.8kΩの抵抗でプルアップしています。

あとは、ATmega328もクロック無しでは動かないので、16MHzの水晶発振子と定番のコンデンサ22pFを入れています。

ブートローダを書き込む接続図

実際にブレッドボードで配線しました。

ブレッドボードで配線

ArduinoIDEの設定

次に、Arduinoの書込みソフトの設定をします。

まず、書き込むICが ATmega328P-PUと、ATmega328PU(部品表記;ATMEGA328 U)では、ブートローダの書込み方が違います。これは、ATmel社がMicroChip社に変わってから、廉価版として発売されたATmega328PUは、書き込むバリアントが違うためです。

 

ATmega328P-PUのブートローダを書き込む

まず、ArduinoIDEを起動します。Arduinoのソフトのインストールは下記のリンクから行ってください。

ArduinoIDEのダウンロード

ArduinoIDEが起動したら、「ファイル」→「スケッチ例」→「11.ArduinoISP」→「ArduinoISP」を開きます。

Arduino IDEを起動
Arduino ISPを起動

まず、ArduinoNanoにArduinoISPのソフトを書き込みます。これで、ArduinoNanoを書き込み機として使えます。

その後、「ツール」を押して、ポート「Arduino Uno」、シリアルポート「ArduinoNanoを接続してるCOMポート」、書込装置「Arduino as ISP」を選択し、一番下の「ブートローダを書き込む」を押して、ブートローダを書き込むことが出来ます。

ArduinoNanoにArduinoISPのソフトを書き込む
ブートローダを書き込む

 

ATmega328PUにブートローダを書き込む

上記で、ArduinoISPをArduinoNanoにISPのソフトを書き込むところまでは同じです。

Arduinoに初期から入っているボードマネージャーでは、ATmega328は書き込めません。

「ツール」→「ボード」→「ボードマネージャー」を開き、MiniCoreと検索し、インストール。

ボードマネージャーを起動
MiniCoreをインストール

Arduinoを再起動して、「ツール」→ボード→「MiniCore」→「ATmega328」を選択します。

ボードはATmega328を選択
シリアルポート、書き込み装置を選択

あとは、「ブートローダを書き込む」を押すと書き込まれます。

これでブートローダの書き込みが完了します。

 

今日はここまでです。

2021.7.31 ArduinoのWire関数について

今回は、Arduinoで超音波センサとI2C通信を行います。

そのなかで、とくに便利なのがWire関数です。

まず最初に、I2C通信の概要を説明します。

本日のトピック

I2C通信とは

I2C(Inter-Integrated Circuit)は、フィリップス社が提唱した周辺デバイスとのシリアル通信の方式で、主にEEPROMメモリICなどとの高速通信を実現する方式です。

基本構成は、マスタ側とスレーブ側を明確に分かれており、マスタ側が全ての制御の主導権を持っています。

接続は、マスターは一機だけですが、スレーブは何機も接続することが出来ます。

接続関係

I2Cは、全ての同じ線(SDA,SCL)を並列で接続します。並列なのに個々と通信ができるのは、インターネットのネットワークと同様に、それぞれにアドレスが割り振られているからです。

アドレスは、2進数でも16進数でも10進数でも構いません。例えば16進数で書く場合は、0x70や、0x56などの形で書きます。また、マスターにはアドレスはありません。

通信をする際は、必ず最初にSlaveの宛先(アドレス)を宣言してから、データを送ります。送り先が変わるときも逐次、宛先を言います。人間の生活でも、手紙、宅配便には必ず宛先を書きますよね。それと同じです。当たり前といえば当たり前ですね。

Slaveにはアドレスが割り振られている

Wire.hの主なコマンド

ここでは、細かい説明は、なるべく省き、使い方に特化させます。

なので、まず使えるコマンドを確認しましょう。

#include<Wire.h>

I2Cで通信する際は、最初に宣言する必要になります。これは、「Wireのライブラリを使います」という宣言文で、プログラムの先頭に書きます。

 

Wire.begin();

wireライブラリを初期化します。自身がSlaveの場合は、括弧の中にアドレスを入力します。Masterはアドレスの入力は不要です。

 

Wire.beginTransmission(slave address);

カッコ内に指定したアドレスのSlaveに対して、通信を開始する準備をします。通信を始めるときは必ず宣言します。

 

Wire.write( data );

Wire.beginTransmissionで指定したアドレスに対して、Wire.writeのカッコ内のデータを送信します。基本的にデータは1byte以内です。

 

 Wire.endTransmission();

Slaveに対してのデータの送信処理を完了します。なお、WireライブラリではbeginTransmissionからendTransmissionまでのデータバッファは32byteなので送信データが多い場合は適宜endTransmissionで区切る必要があります。

Wire.requestFrom(address, byte);

MasterがSlaveにデータを要求するとき、最初に宣言します。要求する先のアドレスと、ほしいデータの容量を書きます。

Wire.available()

read()で読み取ることができるバイト数を返します。

Wire.read()

マスタデバイスでは、requestFrom()を実行したあと、スレーブから送られてきたデータを読み取るときに使用します。スレーブがマスタからのデータを受信するときにも使用します。

超音波センサにおけるI2Cのプログラム

以前のブログでお話した、超音波センサのプログラムを示します。

前回のブログでは、あまり触れていなかった通信の部分に焦点をあてます。


   #include <Wire.h>

    void setup()
    {
      Wire.begin();                // join i2c bus (address optional for master)
      Serial.begin(9600);          // start serial communication at 9600bps
      pinMode(11,OUTPUT);
      
    }

    int reading = 0;
    int SPEAKER = 11;
      int TIME=100;
      int m[9]={262,294,330,349,392,440,494,524,0 };
      int melody=0;

    void loop()
    {
     
      
      // step 1: instruct sensor to read echoes

      Wire.beginTransmission(112); // transmit to device #112 (0x70)
      Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)
      Wire.write(byte(0x51));      // command sensor to measure in "centimeters" (0x51)
      Wire.endTransmission();      // stop transmitting

      // step 2: wait for readings to happen
      delay(20);                   // datasheet suggests at least 65 milliseconds

      // step 3: instruct sensor to return a particular echo reading
      Wire.beginTransmission(112); // transmit to device #112
      Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
      Wire.endTransmission();      // stop transmitting

      // step 4: request reading from sensor
      Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112

      // step 5: receive reading from sensor
      if (2 <= Wire.available())   // if two bytes were received
      {
        reading = Wire.read();  // receive high byte (overwrites previous reading)
        reading = reading << 8;    // shift high byte to be high 8 bits
        reading |= Wire.read(); // receive low byte as lower 8 bits
        Serial.print(reading);   // print the reading
        Serial.println("cm");
        
        if(reading>105){
          
        }else if(reading>95){
          melody=m[7];  
          tone(11,melody) ; 
          delay(TIME);
        }else if(reading>85){
         melody=m[6]; 
         tone(11,melody) ; 
         delay(TIME);       
        }else if(reading>75){
         melody=m[5];   
        tone(11,melody) ; 
         delay(TIME);     
        }else if(reading>65){
          melody=m[4];   
        tone(11,melody) ; 
          delay(TIME);     
        
        }else if(reading>55){
          melody=m[3]; 
        tone(11,melody) ; 
          delay(TIME);       
        
        }else if(reading>45){
          melody=m[2]; 
        tone(11,melody) ; 
          delay(TIME);
          
        }else if(reading>35){
          melody=m[1];  
        tone(11,melody) ; 
          delay(TIME);

        }else if(reading>25){
          melody=m[0];
        tone(11,melody) ; 
          delay(TIME);
          
        }else if(reading>15){
          melody=m[8];
          tone(11,melody) ; 
          delay(TIME);
        }
        tone(11,melody) ; 
 
      }

      delay(5);                  // wait a bit since people have to read the output :)
    }

まず、voidsetup(){ の中に、 #include <Wire.h> と Wire.begin(); が入っています。これはそれぞれ、Wireライブラリの読み出しと、Wireライブラリの初期化の意味があります。



   #include <Wire.h>

    void setup()
    {
      Wire.begin();                // join i2c bus (address optional for master)
      Serial.begin(9600);          // start serial communication at 9600bps
      pinMode(11,OUTPUT);
      
    }

メインのプログラムは、5段構成です。

まず、Wire.beginTransmission(112);で、Slaveデバイスのアドレス(112)を指定します。

次に、Wire.writeで、0x00を送信。超音波センサに通信開始する合図です。

その後、0x51を書き込みます。これは、あとで読み出す、超音波センサの距離を、センチメートルで返す設定をします。

Wire.endTransmissionで送信します。

20ミリ秒待ったのち、0x02を送信。超音波の測定値を送るようにセンサに要求しています。

そして、Wire.requestFormで、受信の準備をします。容量は2byteです。

さいご、Wire.read()で測定値を読み込むという流れになっています。



 // step 1: instruct sensor to read echoes
      Wire.beginTransmission(112); // transmit to device #112 (0x70)
      // the address specified in the datasheet is 224 (0xE0)
      // but i2c adressing uses the high 7 bits so it's 112
      Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)
      Wire.write(byte(0x51));      // command sensor to measure in "centimeters" (0x51)
      // use 0x51 for centimeters
      // use 0x52 for ping microseconds
      Wire.endTransmission();      // stop transmitting


      // step 2: wait for readings to happen
      delay(20);                   // datasheet suggests at least 65 milliseconds


      // step 3: instruct sensor to return a particular echo reading
      Wire.beginTransmission(112); // transmit to device #112
      Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
      Wire.endTransmission();      // stop transmitting


      // step 4: request reading from sensor
      Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112


      // step 5: receive reading from sensor
      if (2 <= Wire.available())   // if two bytes were received
      {
        reading = Wire.read();  // receive high byte (overwrites previous reading)
        reading = reading << 8;    // shift high byte to be high 8 bits
        reading |= Wire.read(); // receive low byte as lower 8 bits
        Serial.print(reading);   // print the reading
        Serial.println("cm");

きょうはここまで。

2021.7.29 超音波で弾く楽器を作りたい1

本日のまとめ

 

唐突ですが、超音波で弾く楽器をつくりたいです。

設計のイメージは右図のように、超音波センサを上向きで置き、そこに手をかざして演奏します。音階はかざす手の高さによって決まっています。

 

次に、楽器のシステムを考えます。超音波センサは、以前のブログでも紹介したSRF-02を使います。また、マイコンから音を出す回路も前回のブログで書いたスピーカー駆動回路を使います。

右図が簡単なシステム図です。

超音波センサSRF02は、検知した距離をI2Cのシリアル通信またはUARTにて出力します。今回は、配線が簡単なI2Cを使うことにしました。

超音波センサからArduinoには、I2Cを経由して距離が数値で入力されます。

その数値をArduino内で処理し、音階のデータに変換して、スピーカーに出力します。

つぎにプログラムを設計するため、フローチャートを書きました。

プログラムをスタートすると、まず超音波センサの値を読み込みます。

すると、超音波センサは、かざした手までの距離をcm単位で数値を返します。

その距離を、Arduino内では、何層にも重ねたif文で条件を分岐し、各音階の周波数を割り当てます。

次に、if文内の処理について説明します。

まず、高さが105cm以上であるかないかを判別します。高さが105cm以上であれば、プログラムや音階は現状維持となります。つまり、前出した音階を継続します。105cmはかなり高い高さなので、かざしていない場合を想定しています。

次に、105cm以上がNoであった場合、次は95cm以上かどうかを判別します。95cm以上であれば、手は95cm~105cmの間にあるということですから、ドの音階を出力させます。

続いて、85cm以上ならシ、75cm以上ならラ、と分岐していき、最後、15cm以上で、下のドとなります。

それぞれ、音階を出力したら、処理はまた振り出しに戻り、センサの値を読み込むところからやり直します。

これを、プログラムのコードに直すと下記のようになります。

  #include <Wire.h>

    void setup()
    {
      Wire.begin();                // join i2c bus (address optional for master)
      Serial.begin(9600);          // start serial communication at 9600bps
      pinMode(11,OUTPUT);
    }
    int reading = 0;
    int SPEAKER = 11;
    int TIME=100;
    int m[9]={262,294,330,349,392,440,494,524,0 };
    int melody=0;

    void loop()
    { 
      // step 1: instruct sensor to read echoes
      Wire.beginTransmission(112); // transmit to device #112 (0x70)
      // the address specified in the datasheet is 224 (0xE0)
      // but i2c adressing uses the high 7 bits so it's 112
      Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)
      Wire.write(byte(0x51));      // command sensor to measure in "centimeters" (0x51)
      // use 0x51 for centimeters
      // use 0x52 for ping microseconds
      Wire.endTransmission();      // stop transmitting
      // step 2: wait for readings to happen
      delay(20);                   // datasheet suggests at least 65 milliseconds
      // step 3: instruct sensor to return a particular echo reading
      Wire.beginTransmission(112); // transmit to device #112
      Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02)
      Wire.endTransmission();      // stop transmitting
      // step 4: request reading from sensor
      Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112
      // step 5: receive reading from sensor
      if (2 <= Wire.available())   // if two bytes were received
      {
        reading = Wire.read();  // receive high byte (overwrites previous reading)
        reading = reading << 8;    // shift high byte to be high 8 bits
        reading |= Wire.read(); // receive low byte as lower 8 bits
        Serial.print(reading);   // print the reading
        Serial.println("cm");
        
        if(reading>105){
        }else if(reading>95){
          melody=m[7];  
          tone(11,melody) ; 
          delay(TIME);
        }else if(reading>85){
         melody=m[6]; 
         tone(11,melody) ; 
         delay(TIME);       
        }else if(reading>75){
         melody=m[5];   
        tone(11,melody) ; 
         delay(TIME);     
        }else if(reading>65){
          melody=m[4];   
        tone(11,melody) ; 
          delay(TIME);     
        
        }else if(reading>55){
          melody=m[3]; 
        tone(11,melody) ; 
          delay(TIME);       
        
        }else if(reading>45){
          melody=m[2]; 
        tone(11,melody) ; 
          delay(TIME);
          
        }else if(reading>35){
          melody=m[1];  
        tone(11,melody) ; 
          delay(TIME);

        }else if(reading>25){
          melody=m[0];
        tone(11,melody) ; 
          delay(TIME);
          
        }else if(reading>15){
          melody=m[8];
          tone(11,melody) ; 
          delay(TIME);
        }
        tone(11,melody) ; 
      }
      delay(5);                  // wait a bit since people have to read the output :)
   }

ここで、新たに登場した関数は、wire関数です。

#include<Wire.h>

Wire.hの関数をincludeで呼び出しています。Wire関数は、I2Cのシリアル通信を行う最に使う関数で、Wire.read();などで、シリアルのデータを読み込むことができるなどします。

私もこの関数は知らなかったのですが、少し奥が深そうなので、後日まとめて掲載できたらと思います。

 

さっそくブレッドボードで配線を組みました。

次回は、これの動作チェックをします。

2021/7/29 ひいらぎ

2021.7.27 tone関数を使いこなす

Arduinoのプログラム[tone関数を使いこなす]

次に、tone関数を用いてArduinoから音を出していきましょう。

tone関数

tone関数のリファレンスは、

tone(pin, 周波数 , 出力時間);

です。なお、出力時間は、省略して書くこともできます。

さっそく、下記のプログラムを作ってみました。

void setup() {
  // put your setup code here, to run once:
pinMode(11,OUTPUT);
}

void loop() {
int TIME=300;
  // put your main code here, to run repeatedly:
tone(11,262,TIME) ; // ド
delay(TIME) ;
tone(11,294,TIME) ; // レ
delay(TIME) ;
tone(11,330,TIME) ; // ミ
delay(TIME) ;
tone(11,349,TIME) ; // ファ
delay(TIME) ;
tone(11,392,TIME) ; // ソ
delay(TIME) ;
tone(11,440,TIME) ; // ラ
delay(TIME) ;
tone(11,494,TIME) ; // シ
delay(TIME) ;
tone(11,523,TIME) ; // ド
delay(TIME) ;
}

 

このプログラムは、ドレミファソラシドを0.3秒ごとに切り替えて、出力するプログラムです。

使っている関数を、いくつか紹介します。

pinMode(pin, OUTPUT);

Arduinoの各入出力ピンが、出力なのか入力なのかを設定します。例題のプログラムでは11番ピンを出力に設定しているので、pinMode(11,OUTPUT);となります。入力に設定する場合は、pinMode(11,INPUT); また、pinMode(11,INPUT_PULLUP);で、入力をプルアップに設定できます。

 

int 変数=数値;

整数の変数を定義するときにint関数を使います。ほかにもfloat , char,doubleなどがありますが、奥が深いので、いつかまた紹介できたらなと思います。

delay(時間);

プログラムを指定した時間だけ遅延させます。単位はミリ秒です。また、マイクロ秒で指定する場合は、

delayMicroseconds(時間);で指示できます。

 

さて、次に音を鳴らす回路です。回路は、前回のブログでも作成した、スピーカーの回路を使います。

 次に、プログラムの内容は同じですが、配列とfor文を使って、短く簡単にまとめたプログラムです。

だいぶ、短いプログラムになりました。

void setup() {
  // put your setup code here, to run once:
pinMode(11,OUTPUT);
}

void loop() {
  int TIME=300;
  int m[8]={262,294,330,349,392,440,494,523};
  
  // put your main code here, to run repeatedly:

  for(int i=0;i<8;i++){
    tone(11,m[i],TIME) ; 
    delay(TIME) ;
  }
}

このプログラムは、先ほどと同じ、ドレミファソラシドを0.3秒ごとに切り替えて、出力するプログラムです。

使っている関数を、いくつか紹介します。

int 変数[データ数] ={数値1,数値2,数値3,・・・};

配列は、大量の数値を同時に宣言するのに便利です。例のプログラムの場合は、ドレミファソラシドの各音階の周波数をまとめて宣言するため、配列を使い、

int m[8]={262,294,330,349,392,440,494,523};

と表現しました。これを使うとき、例えばレの音の周波数を出したければ、2番目の数値を呼び出すので、0,1 で,

m[1]

が、レの変数になります。呼び出すときの数値は、0からスタートする点に注意しましょう。

 

for(初期値 ; 条件式 ; 加算){    };

for文は波カッコに囲まれたブロックを繰り返し実行します。様々な繰り返し処理に活用でき、データやピンの配列と組み合わせて使われることがあります。

例題のプログラムの場合、

for(int i=0;i<8;i++){

tone(11,m[i],TIME) ;

delay(TIME) ;

}

で、加算させる変数 i の初期値を0にし、これが8以下であるうちは、{}内のプログラムを繰り返し実行します。

実行するプログラムは、tone関数で、iの数値に割り当てられた周波数を出力し、TIME㍉秒待機します。

これを、7回、音階を上げながら実行するため、ドレミファソラシドの順に音が鳴るプログラムになります。

 

本日は、ここまでにします。次回は、超音波センサと組み合わせて、音階を鳴らす楽器作りをします。

 

2021/7/27 ひいらぎ

2021.7.25 Arduinoから音を出す(回路編)

さて、次はArduinoのトーン関数を使って、音を出そうと思います。Arduinoのトーン関数は、 

出力するピンと周波数、出力時間を入力するだけで音を出すことができます。

といっても、Arduinoにスピーカーがついているわけではないですから配線をしていかなければなりません。

下図が、Arduinoからスピーカーを駆動する回路です。

さて、まずはこの回路の部品を確認していきましょう。

回路図

スピーカー

スピーカーは、電気信号を音に変換する部品です。基本構成は、コイルでできており、交流信号を流すことで、振動板が前後に触れ、空気を震わせて音が出ます。

トランジスタ

トランジスタは電気の流れをコントロールする部品です。
半導体でできた能動部品の代表と言われるぐらいとても重要な部品で、いろんな電子回路で活躍しています。この回路では、スピーカーに流す電気は大きく、マイコンで直駆動させることは難しいため、トランジスタを間に挟みます。

ArduinoNano

Arduinoは、簡単なC言語のプログラムで、あらゆる出力信号を出すことが出来る。また、アナログ入力を7個積んでいて、分解能255でアナログ値入力できるため、精度の良いセンサーを作ることができる。詳しくは、どこかで説明したい。

スピーカー駆動回路

回路はいたってシンプルです。Arduinoからはデジタル出力の矩形波が出力される。このデジタル信号がトランジスタQ1のベースに入力される。ベースに電流を流すと、コレクタエミッタ間がONとなち、スピーカーに電流が流れる。デジタル信号のHIGH/LOWの周期によって、すぴーかーに電流を流す、流さないが変化する。したがって、デジタル信号の周波数の電子音がスピーカーから発せられる。

R1の抵抗は、デジタル信号の電流が、ベースには高すぎるので、抵抗R1を挟んで電流を小さくしている。

また、R2の抵抗も、スピーカーに流れる直流電流が大きすぎるため、R2の抵抗を挟み電流を小さくしている。

また、D1のダイオードは、スピーカーのコイルを矩形波でON/OFFしてしまうと、スピーカーの電圧が一気に跳ね上がってしまうため、電圧が跳ね上がらないようび、スピーカーのコイルにたまった電流を逃がす回生ダイオードを積んでいる。

次回は、Tone関数を利用して簡単にArduinoから音を出します。

2021/7/25 ひいらぎ

2021.7.24 超音波センサを使いこなす1

先日、八潮の秋月電子で超音波センサを買いました。

今回は、超音波センサSRF-02をがんばって使いこなそうと思います。

超音波センサ(SRF02)

超音波センサ

◆主な仕様
・使用マイコン:16F687-I/ML
・測定範囲:16cm~6m.
・電源:5V(消費電流4mA Typ.)
・使用周波数:40KHz.
・アナログゲイン:64段階の自動ゲインコントロール
・接続モード:モード1=I2C、モード2=シリアルバス
・全自動調整機能:電源投入後キャリブレーション不要
・測距タイミング:エコー時間計測、ホストによるタスクコントロール
・測定単位:μS(マイクロ秒)、ミリ、インチ
・サイズ:24mmx20mmx17mm
・入出力端子:5ピン
・重量:4.6グラム

[秋月電子より引用]

さて、まずは超音波センサの仕組みを確認しましょう。

超音波センサーは、今や自動車の駐車センサや障害物検知など、自動運転などにも欠かせない技術となっています。

まず、超音波とはなんでしょうか。

 

超音波とは

超音波は、広義的に言えば、ただの音です。なぜ、超が付くかと言いますと、それは音の周波数が人間が聞き取れないくらい高いからです。

下図が、音波の分類です。

超音波のスペクトラム

音は、音の高さ(周波数)によって分けられ、20kHzより高い音を超音波と定義しています。

人間が聞き取れるのは、成人では17kHz程度まで聞き取れます。そのため、多くの音楽データでは20kHz以上の音はデータとして記録していません。また、マイクやスピーカーの特性も、20kHz以上の音はほとんど出ない設計であり、その分音波の範囲で最大の性能を発揮できるように作られています。

その、聞き取れない超音波域の音も出すことで、豊かな音になるとうたっているのが「ハイレゾ音源」です。ですが、そもそも人間が聞き取れない音を出すことは、本当に意味があるのか、私もわかりません。

さて、余談が過ぎました。

超音波センサは、空気を伝搬させるため、超音波の中でも比較的低い音で使用します。超音波は、周波数が高いほどまっすぐ進み、密度の濃い媒体の中も良く通ります。そのため、おなかの中を通り抜けなければならないエコー検査装置の超音波は3GHzと高い帯域を使います。

それに対し、障害物センサなどの超音波は、媒体が空気と薄いこと、さらになるべく広い範囲を検知する必要があることから、音波ギリギリの40kHzなどが使われます。

さて、超音波の特徴がわかったところで、つぎは、超音波センサが障害物を検知するしくみを確認します。

 

超音波センサの検知

超音波センサは、超音波を放出するスピーカーと、超音波を受信するマイクからなります。

最近の超音波センサは、スピーカーとマイクが一体型になっているパターンがほとんどです。

超音波の送受信1

センサーから放出した超音波は、音速の速さで進みます。

これが、障害物にあたると、超音波はやまびこのように反射して帰ってきます。この帰ってきた反射波をマイクで拾い、検知します。

もし障害物が無ければ、なにも反射せずに検知できません。

超音波の送受信2

 

また超音波センサは、障害物までの距離も算出することが出来ます。

その仕組みは下図のように、超音波の発信から受信までに要した時間と音速との関係を演算することでセンサから対象物までの距離を算出します。

超音波の送受信3

超音波は、音と同様、音速の速さで進みます。音速は340m/sです。

音速をv 距離をrとし、超音波を放出してから反射波を受信するまでの遅延時間をtとすると、

距離 r = (v× t )/2 で導けます。

例えば、遅延時間が10m秒だった場合、往復距離r は、340×0.01= 3.4m

したがって、障害物までの片道距離は、1.7 mとわかります。

 

超音波センサSRF-02

さて、超音波センサを使いましょう。

秋月のページには、メーカーの製品情報が載っていました。

ここに、詳細な説明とプログラム例のwikiが載っています。

ここに乗っていた、サンプルプログラムを使うことにしました。

接続は、下図の通りです。

Arduinoとセンサの接続図

超音波センサとの通信方法は、二種類選ぶことができ、I2CとUARTから選ぶことが出来ます。

I2CとUARTの特徴は、後程まとめさせていただければと思います。

超音波センサにヘッダピンをはんだ付けして、ブレッドボードに差し込みます。あとは、接続図の通りに配線をして完成。

さっそく、パソコンにUSBをつないで、プログラムを書き込みます。Arduinoの使い方なども後程説明させていただければと思います。

Arduinoのスケッチ

これを書き込むと、センサから障害物までの距離をリアルタイムで見ることができます。

さっそく手をかざしてみます。Arduinoのシリアルモニタを確認すると、センサから手までの距離がリアルタイムで表示されていることがわかります。

 

今日はここまでにします。明日は、超音波センサを使った楽器について構想を練ります。

 

2021/7/24 ひいらぎ

サボテンの骨について調べてみた

先日、東京新木場の木材専門店「もくもく」にいきました。

https://www.mokumoku.co.jp/

国内の貴重な木材(木曽檜、コクタン、神代杉、屋久杉等)から、海外の木材まで、100種類以上を取り扱っています。そのなかで見つけたのがサボテンの骨です。

お店で最初見たときは、「サボテンの木。。。?」と思わず言ってしまってたのですが、完全に失礼でしたね。

「サボテンの骨」ですよ。

サボテンは、砂漠などの過酷な環境で生育しています。サボテンと言えど、砂漠では 雨が降らない日が続くと自然枯死し、緑色の幹は「木」に変化していきます。 そうなったのが、サボテンの骨だそうです。さっそく2本購入しました。ほかの木材との相性も良さそうなので、なにか工作ができそうです。

googleでサボテンの骨を検索すると沢山、飾り方の例が載っています。

そのまま飾る方も多いようですが、穴がたくさん開いているので、どうやら小さい草花を詰めて飾っている方が多いようです。なるほど、、、

 

でも私はこれを、光らせたいなと思います。

サボテンの骨は、中が空洞状になっているため、下からLEDでライトアップしたら、お洒落じゃないかなと思いました。

さっそく実験しました。

サボテンの骨の下から、試験管立て(LA-01)の基板を当てて光らせます。

なかなか良いのではないでしょうか。

本格的に、作ることにしました。

さっそく、3D-CADでサボテンの骨を置く、光る台を設計しました。基板は、試験管立ての基板を流用します。ドーナツ状に開いている穴から、光が出ます。

この台座を右図のように立てます。台座には、檜の切り株を使いました。

  

下図が設計図になります。切り株の裏側から、ホールソーでΦ35の穴をあけ、基板を取り付けるシンプルな構造です。あとは、USB端子を格納するための穴をΦ7.5で開けています。

今日は、設計まで行いました。

次回は、これを加工していきます。

試験管を光らせたい

先週、東京の清澄白河にある、コルク瓶の仕入れ元、「リカシツ」のお店に行ってきました。

[https://rurubu.jp/andmore/article/7921]

リカシツは、理化医療用ガラスの卸業の関谷理化株式会社が運営する、「理化学+インテリア」を目指したアンテナショップです。実際に研究室でプロが使用している理化学製品そのモノと理化学ガラス職人が加工したオリジナルなモノを販売しています。

昨今では少子化で学校・研究所の統合などで理化学ガラス職人の仕事も減っている中、一般の方に使ってもらいアイデアを貰うことで理化学ガラス職人の技術が活かせる「新たな仕事つくり」ができると考え、アンテナショップができたそうです。(リカシツHPより要約)

実際に行きましたが、とても洒落な空間が広がっていました。

理科の実験って、こんな映えるんだなあと。新しい価値観にびっくりします。

リカシツで衝動買いしたのが、木でできた試験管立てです。

もう、お店で見た瞬間から、光らせたくてたまらないです。

そこで、試験管立てには、裏から穴をあけ、試験管には造花を詰めてみました。

いろんな色のLEDを下から入れて光らせました。かなり、いい感じじゃないですか。

もう、これは基板化決定です。フルカラーLEDと小さなマイコンでカラフルに光らせる基板を作ろうと思います。

さっそく回路設計

基板を発注してみたい

2021年3月17日 柊工房

突然ですが、基板を基板メーカーに発注して本格的な基板を作ってみたいです。

家電や製品で当たり前に使われている回路基板、

こんなのを自分で本格的に作ってみたいなと思いました。

今まで、エッチングを使って基板を作ることはしてきましたが、見た目がこんな感じ

これもこれで味があっていいのですが、やっぱり、レジストがしっかり貼られていて、シルク印刷がある

本格的な基板を作りたいと思いました。

さっそく基板メーカーを比較。

まず日本メーカーだと、P板ドットコムが最大手かと思います。

10cm×10cm 2層基板 10枚の場合の見積もりが、

なんと、35530円。結構お値段貼りますね。そりゃそうですよね。企業の開発からしたらものすごく安いと思いますけども。個人では厳しいですね。

ほぼ同条件でunicraftでもweb見積もり。28640円

やはり、日本メーカーは三万円前後が相場のようです。

海外メーカーではどうでしょうか。

中国のSeed Fusion PCBでは、

ほぼ同条件で、$4.90 約550円。 輸送コスト含めて約3000円ってところでしょうか。

圧倒的な安さです。たとえ、歩留まりが悪かったとしても、大量に注文しても対応できそうです。

まず、本格的な基板にするのは、瓶詰めLED時計にしようと思います。