Arduinoで遊ぶページ
Arduinoで遊んだ結果を残すページです
逆引きArduino

はじめに

Arduinoでのプログラムに関して、こんなときにはどうすればいいのかという、いわゆる逆引きの観点で一覧を作成中です。内容を見るには、小項目をクリックしてください。リファレンスの目次と大差ないかもしれませんが…

Arduinoのバージョンについてはもはや追跡不能なので、特定のバージョンでは動作しない可能性もあります。

このページに記載のプログラムは断片だけのものがあり、これだけではコンパイルできないものもあります。注意してください。

Arduinoソフトウェアは、Arduinoのサイトダウンロードページから入手することができます。

Arduino Dueに対応したバージョンは、Uno用のソフトウェアをインストールした後、追加インストールします。

最終更新日: April 12, 2020

Arduinoソフトウェアのインストールのページを参照してください。

最終更新日: April 12, 2020

Arduino-1.6.2以降からは、AVR用のツールチェーン以外は、追加インストールを行う必要があります。Arduinoソフトウェアのインストールのページを参照してください。

最終更新日: April 12, 2020

(Arduino UNOの場合)デジタルピンの0番や1番にデバイスを接続している場合に表示されたときは、接続を解除してからマイコンボードへの書き込みを行ってください。

デジタルピンの0番と1番はシリアル通信に利用されていて、これは、USB経由での通信にも利用されています。このため、0番ピンや1番ピンにデバイスが接続されているとスケッチのアップロードに失敗することがあります。

他にもいろいろ理由があるようですので、事例があれば教えてください。

最終更新日: April 12, 2020

(Arduino UNOの場合)適切なシリアルポートが選択されていない可能性があります。Arduino ソフトウェアのメニューの、“ツール > シリアルポート” からArduinoが接続されているポートを選択してください。

Arduino用のドライバがインストールされていない場合は、そもそも選択肢に適切なシリアルポートが現れないので、Arduinoソフトウェアのインストールのページを参考にして、ドライバをインストールしてください。

この例は、このページをご覧いただいた方から情報をいただきました。ありがとうございました。

最終更新日: April 12, 2020

Arduinoソフトウェアのメニューから、「ファイル > 環境設定」 を選択し、「エディタの文字の大きさ」を変更し、Arduinoソフトウェアを再起動します。

フォントの大きさだけでなく、フォントそのものを変えたい場合は、設定ファイルを変更します。

最終更新日: April 12, 2020

Arduinoソフトウェアのメニューから、「ファイル > 環境設定」 を選択し、「行番号を表示する」をチェックします。

最終更新日: April 12, 2020

Arduinoソフトウェアのメニューから、「ファイル > 環境設定」 を選択し、「より詳細な情報を表示する」の「コンパイル」にチェックを入れた後、スケッチをコンパイルします。

最終更新日: April 12, 2020

IDEで、Ctrl+tを入力すると、ソースコードを自動整形します。

最終更新日: April 12, 2020

Arduinoの設定ファイルを直接編集します。editor.auto_close_bracesという設定を、falseにすると閉じ波括弧を自動で挿入しません。trueにすると自動で挿入します。

最終更新日: April 12, 2020

Arduinoの設定ファイルを直接編集します。editor.indentという設定を、falseにすると自動インデントをやめることができます。

trueにすると自動インデントします。

最終更新日: April 12, 2020

Arduinoの設定ファイルを直接編集します。editor.tabs.sizeという設定を変更します。例えば、4文字に設定するには、以下のように設定します。

1
editor.tabs.size=4

ただし、Ctrl-Tによる自動整形を行うと、前述の設定に関係なく、インデントは2文字分になるようです(Arduino 1.8.9で確認)。

最終更新日: April 12, 2020

Microsoftが提供している、Visual Studio Code extension for Arduinoや、PlatformIOが提供する、PlatformIO IDEを利用することができます。

Visual Studio Code extension for Arduinoを利用する方法は、Visual Studio Codeを参照してください。

最終更新日: May 3, 2020

Arduinoでデジタルピンを利用する場合は、入出力モードを正しく設定しておく必要があります。入出力モードの設定には、pinMode()を利用します。第二引数にINPUTを設定すると入力モードに、OUTPUTを設定すると出力モードになります。また、INPUT_PULLUPという値を設定すると、内蔵のプルアップ抵抗が有効になります。

1
2
3
4
5
const int inputPin = 10;
const int outputPin = 11;
 
pinMode(inputPin, INPUT);  /* inputPin を入力モードに設定する */
pinMode(outputPin, OUTPUT); /* outputPin を出力モードに設定する */

最終更新日: April 12, 2020

pinMode()でデジタルピンを入力モードにしてから、digitalRead()で値を読み取ります。digitalRead()は、HIGHもしくはLOWを返します。アナログピンもデジタルピンとして利用できます。アナログの0番ピンはA0、1番ピンはA1、という風に変数が定義されています。

1
2
3
4
5
6
7
8
const int digitalPin = 10;
int val;
 
pinMode(digitalPin, INPUT);  /* pin を入力モードに設定する */
val = digitalRead(digitalPin); /* val には HIGH か LOW が代入される */
 
pinMode(A0, INPUT); /* A0 を入力モードに設定する */
val = digitalRead(A0); /* val には HIGH か LOW が代入される */

最終更新日: April 12, 2020

pinMode()でデジタルピンを出力モードにしてから、digitalWrite()で値を出力します。出力できるのは、HIGHもしくはLOWです。

1
2
3
4
const int digitalPin = 10;
 
pinMode(digitalPin, OUTPUT); /* pin を出力モードに設定する */
digitalWrite(digitalPin, HIGH); /* pin にHIGHを出力する */

最終更新日: April 12, 2020

analogWrite()で値を出力します。これによりPWM出力を行うことができます。PWM出力することができるのは、(Arduino Unoの場合)3、5、6、9、10、11の6つのピンです。5番ピンと6番ピンに出力されるPWMの周波数は約977Hz、他のピンに出力されるPWMの周波数は約490Hzです。

1
2
3
const int digitalPin = 3;
 
analogWrite(digitalPin, 128); /* デューティ比 128/255 のPWM出力 */

最終更新日: April 12, 2020

tone()を使えば、周波数を変更することができます。ただし、デューティ比は固定です。

analogWrite()を使えば、デューティ比を変更することができます。ただし、周波数は固定です。

デューティ比と周波数の双方を変更するには、レジスタの操作が必要です。詳細は、tone()の内部構造analogWrite()の内部構造を参照してください。

関数等 周波数 デューティ比
tone() ×
analogWrite() ×
レジスタ操作

最終更新日: April 12, 2020

pinMode()でプルアップ抵抗を有効にすることができます。 ただし、Arduino 1.0以前では、利用できません。

1
2
3
const int digitalPin = 10;
 
pinMode(digitalPin, INPUT_PULLUP); /* pin のプルアップ抵抗を有効にする */

最終更新日: April 12, 2020

デジタルピンに押しボタンを接続して、その押しボタンが押されているかどうかを検出するには、デジタルピンの値を読み取ります。

利用する回路によってスケッチが異なるので、今回は、図に示すような回路を前提としたスケッチ例を記述します。

まず、プルアップ抵抗を接続します。この抵抗がないと、押しボタンが押されていないときに入力ピンの値が不定となります。Arduino(ATmega328P)には、プルアップ抵抗が内蔵されているので今回はそれを用います。この回路では、押しボタンを押していないときに入力ピンの値を読み取るとHIGHになり、押しボタンを押しているときに読み取るとLOWになります。

あとは、入力ピンの値を読み出すし、読み出した値によって必要な処理を行います。

以下に、押しボタンを押したときに内蔵のLEDを点灯させるスケッチの例を示します。押しボタンをデジタルの2番ピンに接続し、内蔵のLED(13番ピン)を制御します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 押しボタンを接続するピン */
const int inputPin = 2;
 
void setup () {
  /* inputPinを入力モードにし内蔵プルアップ抵抗を有効にする */
  pinMode(inputPin, INPUT_PULLUP);
   
  /* LED_BUILTINを出力モードにする */
  pinMode(LED_BUILTIN, OUTPUT);
}
 
void loop () {
  /* inputPinの値を読み取る */
  int buttonState = digitalRead(inputPin);
   
  /* 押しボタンが押されていたらLOWになる */
  if (buttonState == LOW) {
    /* LED_BUILTINをHIGHにする */
    digitalWrite(LED_BUILTIN, HIGH); 
  } else {
    /* LED_BUILTINをLOWにする */
    digitalWrite(LED_BUILTIN, LOW);
  }
}

最終更新日: April 12, 2020

アナログピンをデジタルピンとして利用することができます。Arduino Unoの場合は、A0からA5をデジタルピンの14から19として利用することができます。14とか15という数字を指定しても、A0やA1という変数を指定しても問題ありません。

最終更新日: April 12, 2020

Arduinoソフトウェアでは、デジタル入出力を簡単に利用できるようにするため、操作を抽象化しています。このため、速度を少し犠牲にしています。avr-gccでは、チップのレジスタを直接利用することもできます。詳細はこちらのページを見てください。ただし、Arduinoを利用する意味が少なくなるので、利用する際は本当に必要かを検討するのがいいと思います。

また、アナログ出力(PWM出力)ができるピンは、デジタル入出力の際にPWM出力をオフにする操作を行っているので、PWM出力ができないピンよりも少し速度が落ちています。詳細はこちらのページを見てください。

最終更新日: April 12, 2020

analogRead()でアナログピンにかかっている電圧を読み取ることができます。analogRead()が出力するのは、0から1023までの整数です。実際の電圧は、参照電圧により異なります。

(Arduino Unoの場合)参照電圧は、DEFAULT(5V)、INTERNAL(1.1V)、EXTERNAL(Arefピンにかけた電圧)の3種類から選ぶことができます。analogReference()で参照電圧を設定します。デフォルトは5Vです。それ以外の参照電圧を利用する場合は、analogRead()を呼ぶ前に設定します。すべてのアナログピンの参照電圧が変更されます。また、Arefピンにかける電圧は0Vから5Vの範囲とする必要があります。範囲外の電圧をかけるとArduinoが壊れる可能性があるので注意してください。

1
2
3
4
5
6
	
const int analogPin = 0;
int val;
 
analogReference(INTERNAL); /* 参照電圧を1.1Vに設定する */
val = analogRead(analogPin); /* valには0から1023までの値が代入される */

analogRead()が出力する値(val)と実際の電圧(V)との関係は、参照電圧をVrefとすると、以下の通りです。数式を見てわかるように、参照電圧の1023/1024までの値まで測定可能です。

1
V =val / 1024.0 * Vref

アナログピンはデジタルピンとして利用することもできるので、digitalRead()を使えば、デジタル信号を読み取ることもできます。

最終更新日: April 12, 2020

アナログピンはデジタルピンとして利用することもできます。アナログの0番ピンはA0、1番ピンはA1…という風に変数が定義されているので、これらを使うことで、digitalRead()digitalWrite()を使うことができます。

最終更新日: April 12, 2020

Arduinoソフトウェアには、シリアルコンソールが付属していて、Arduinoから簡単に情報を表示することができます。この場合、ArduinoとPCとをUSBケーブルで接続し、Arduinoソフトウェアを起動する必要があります。

シリアルコンソールは、情報を表示(出力)するだけではなく、情報を入力することもできるようになっています。

シリアルコンソールを使うには、シリアルライブラリを利用します。

詳細は、シリアルモニタを参照してください。

最終更新日: May 3, 2020

Arduinoソフトウェアには、シリアルプロッタが付属していて、Arduinoから数値データを送信することで、グラフ表示することができます。

詳細は、シリアルプロッタを参照してください。

最終更新日: May 3, 2020

Hitachi HD44780互換のキャラクタ液晶ディスプレイ向けのライブラリが用意されています。市販されている多くのキャラクタ液晶ディスプレイは、Hitachi HD44780互換なので、簡単に利用することができます。

キャラクタ液晶ディスプレイを使った例も参照してください。

最終更新日: May 3, 2020

7セグメントLEDを、Arduinoから利用する原理は、4桁7セグメントLEDで始めるArduinoを参照してください。

シフトレジスタを利用した例は、シフトレジスタと4桁7セグメントLEDを参照してください。

実際には、LEDドライバを利用するのが簡単です。7セグメントLEDの例ではありませんが、例えば、LEDドライバ(TM1630)も利用することができます。

利用する7セグメントLEDの種類(カソードコモン、アノードコモン)や、電圧・電流に注意して、適切なドライバを利用してください。

最終更新日: May 3, 2020

Arduinoは、シリアル通信のインターフェイスを標準で持っています。

使い方はこちらを参照してください。

以下は、Arduino Unoの場合の話です。Arduino Unoでは、USBケーブルもしくはデジタルピンの0番(受信用)と1番(送信用)を使って通信することができます。

Arduino Unoでは、Serialというオブジェクトが既に定義されていて、このオブジェクトを利用します。Serial.begin()で初期化(通信速度の設定)を行います。その後は、Serial.available()Serial.read()Serial.write()を使うことで通信を行うことができます。詳細はリファレンスを参照してください。以下に、一番簡単な使い方の例を示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
	
void setup() {
  Serial.begin(9600);
}
 
void loop() {
  int c;
 
  if (Serial.available() > 0) {
    c = Serial.read();
 
    Serial.write(c);
  }
}

Arduinoソフトウェアを接続しているときは、右上のSerial Monitorをクリックするとシリアルコンソールが現れます。シリアルコンソールの一番上は、テキストボックスになっていて、Arduinoに対してテキストを送信することができます。下側は、Arduinoから送信されたデータを表示する領域です。上記のプログラムを動作させると、テキストボックスに入力した文字がそのままコンソールに表示されます。

Arduino 1.0では、Serial.print()は、文字ではなくその文字に対応するASCIIコード(例えば、大文字の’A’は、10進数で65です)が表示されます。文字を表示したいときは、Serial.write()を使ってください。

最初にUSBケーブルもしくはデジタルピンの0番と1番と書きましたが、これらは、内部では共通のピンを利用しているようです。このため、デジタルピンの 0番と1番を他のデバイスなどに接続していると、スケッチのアップロードに失敗することがあるので、スケッチをアップロードする際は、デジタルピンの0番 と1番には何も接続しないようにしてください。

Arduino Leonarodではシリアルポートをオープンしてもスケッチを再起動しません。このため、シリアル通信を利用する際には、以下のコードを入れて、シリアルポートが開くのを待つ必要があります。

1
while (!Serial)

最終更新日: April 12, 2020

Arduinoは、標準で付属するWireライブラリを利用することで、I2Cインターフェイスにマスターデバイスとしてもスレーブデバイスとしても参加することができます。マスターデバイスとしての使い方はこちら

最終更新日: April 25, 2020

Arduinoに、標準で付属するSPIライブラリを利用することで、SPIインターフェイスを利用することができます。

最終更新日: April 12, 2020

EthernetシールドとArduinoを取り付け、標準で付属するEthernetライブラリを利用することで、有線LANインターフェイスを利用することができます。クライアントもサーバも実装することができます。

Ethernetシールドの実験も参照してください。

最終更新日: April 12, 2020

Arduino単体では現在時刻を取得することはできません。ただし、Arduinoをリセットしてから経過した時間を取得することはできます。Arduinoはこのための関数を2種類用意しています。一つは、millis()でもう一つはmicros()です。名前が示す通り、millis()はミリ秒を、micros()はマイクロ秒を返却します。

1
2
3
4
unsigned long ms, us;

ms = millis();  // Arduino をリセットしてからの時間(ミリ秒)
us = micros();  // Arduino をリセットしてからの時間(マイクロ秒)

millis()が返す値の型は、unsigned long(32ビット)なので、2^32=4,294,967,296ミリ秒後に0に戻ります。

4294967296ミリ秒 = 4294967.296秒 ≒ 71583分 ≒ 1193時間 ≒ 49.7日です。49.7日以上連続して動作させる場合の動作は、こちら。使い方次第では気にする必要はありません。

時刻情報が必要な場合は、外付けのリアルタイムクロックなどを利用して情報を取得することができます。

最終更新日: April 12, 2020

何もしないで一定時間待つには、delay()delayMicroseconds()のどちらかを使うことで実現できます。delay()ではミリ秒、delayMicroseconds()は指定したマイクロ秒を待つことができます。

1
2
delay(100); // 100ミリ秒待つ
delayMicroseconds(100); // 100マイクロ秒待つ

delay()delayMicroseconds()は簡単に利用できますが、この関数で待っている間は、他の処理は何もできなくなることに注意してください。

もう一つの方法は、millis()を利用する方法です。millis()は、Arduinoが起動してからの経過時間をミリ秒単位で保持しています。これを利用して、ある時点の時刻を保持しておき、その後、現在時刻と比較して、一定時間が経過していたら処理を行います。具体的な方法は、実行タイミングの指定を参照してください。Arduinoのサンプルプログラムの一つの、BlinkWithoutDelayも参照してください。

millis()は、約49.7日でオーバーフローしてしまいます。絶対値を利用する場合は、オーバーフローを意識する必要がありますが、前回の時刻との差分をとる場合は、オーバーフローを気にする必要はありません。こちらについては、millis()のオーバーフローの実験を参照してください。もちろん、約49.7日日以上待つことはできません。

最終更新日: April 12, 2020

strtok()やstrtok_r()あるいはsscanf()を利用することができます。

strtok()、strtok_r()

C言語の標準ライブラリに、strtok()とstrtok_r()という関数が用意されています。この関数を使うと、特定の区切り文字で区切られた文字列を切り出すことができます。strtok()は、スレッドセーフではないので、複数のスレッドから同時に呼び出すような場合には利用できませんが、Arduino Unoは(今のところ)マルチスレッドではないのでどちらを使っても問題はないと思います。

strtok()とstrtok_r()の書式は以下のようになっています。

1
2
char *strtok(char *s, const char *delim);
char *strtok_r (char *s, const char *delim, char **last);

sは解析対象の文字列、delimは区切り文字列(文字列なので区切り文字を複数指定することができます)、lastはスレッドセーフにするために、次回の呼び出しのための情報を(ユーザプログラム側でに)保存しておく変数です。また、戻り値は、切り出した文字列へのポインタです。切り出した文字列がなくなるとNULLが返ります。

strtok()は、strtok_r()を呼び出すことで実現されています。具体的には、以下のようになっています。

1
2
3
4
5
6
7
static char *p;
 
char *
strtok(char *s, const char *delim)
{
    return strtok_r(s, delim, &p);
}

strtok()とstrtok_r()では、1回目の呼び出しには解析対象文字列を指定しますが、(同一文字列を継続して解析する場合)2回目以降の呼び出しは解析対象の文字列は指定せずNULLポインタを指定します。以下に例を示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void setup() {
  char str[80];
  char *lexeme;
   
  Serial.begin(9600);
   
  strcpy(str, "abc:def:ghi");
   
  Serial.println(str);
  for(lexeme = strtok(str, ":"); lexeme; lexeme = strtok(NULL, ":")) { // 1回目はstrを指定。2回目以降はNULLを渡す。
    Serial.println(lexeme);
  }
  Serial.println(str); // もとのstrは破壊されている。
}
 
void loop() {
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
void setup() {
  char str[80];
  char *lexeme;
  char *last;
   
  Serial.begin(9600);
   
  strcpy(str, "abc:def:ghi");
   
  Serial.println(str);
  for(lexeme = strtok_r(str, ":", &last); lexeme; lexeme = strtok_r(NULL, ":", &last)) { // 1回目はstrを指定。2回目以降はNULLを渡す。
 
    Serial.println(lexeme);
  }
  Serial.println(str); // もとのstrは破壊されている。
 
}
 
void loop() {
}

strtok()とstrtok_r()は、解析対象の文字列を変更してしまうので注意が必要です。このため、文字列定数を指定することはできません。

sscanf()

文字列を解析する別の方法にsscanf()を使う方法もあります。sscanf()の形式は以下の通りです。

int sscanf(const char *s, const char *fmt, …)

文字列や数値など複数の形式の値を一度の呼び出しで得ることができます。いろいろな使い方ができるので調べてみてください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
void setup() {
  char s1[10], s2[10];
  int i;
 
  Serial.begin(9600);
   
  sscanf("abc:def:100", "%*s:%*s:%d", s1, s2, &i);
   
  Serial.println(s1);
  Serial.println(s2);
  Serial.println(i);
}
 
void loop() {
}

最終更新日: April 12, 2020

整数を文字列に変換するときには、sprintf()を使うことができます。sprintf()の形式は以下の通りです。

1
int sprintf(char *s, const char *fmt, ...)

数値だけではなく、他の文字列などもまとめて変換できるので便利です。こちらもいろいろな使い方ができるので調べてみてください。

1
2
3
4
5
	
int i = 10;
char s[16];
 
sprintf(s, "i = %d", i);

ただし、Arduino(というかavr-libc)のsprintf()は、浮動小数点数を扱うことはできません。そのかわり、avr-libcでは、dtostre()/dtostrf()という関数が用意されています。次のエントリも合わせてご覧ください。

最終更新日: April 12, 2020

Arduino Uno(というかavr-libc)のsprintf()は、浮動小数点数を扱うことはできません。一方、Arduino Dueのsprintf()は、浮動小数点を扱うことができます。

avr-libcでは浮動小数点数を文字列に変換するために、dtostre()/dtostrf()という関数が用意されています。dtostre()は指数表示、dtostrf()は小数表示です。よりよく使うと思われるdtostrf()の説明をリファレンス形式で示します。

名称

dtostrf()

説明

浮動小数点数を文字列に変換する。

書式

1
char *dtostrf(double val, signed char width, unsigned char prec, char *s)

引数

val 変換対象の数値。
width 小数点や符号を含んだ、最小の表示幅(表示文字数)。負の数を指定すると左詰めとなる。
prec小数点以下の表示幅(表示文字数)。
s変換後の文字列を格納するメモリ領域(格納するのに必要な十分な領域を用意する必要がある)。

戻り値

変換後の文字列を格納する領域(引数で与えたsが返ってくる)。

使用例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void setup() {
  Serial.begin(9600);
   
  char s[16];
  char t[16];
  double val = -12.345678;
   
  dtostrf(val, 5, 1, s);
  Serial.println(s); 
   
  val = 12.345678;
  dtostrf(val, 5, 1, s);
  Serial.println(s); 
   
  sprintf(t, "Val = %s", dtostrf(val, 5, 10, s));
  Serial.println(t);
   
  dtostre(val, s, 3, DTOSTR_ALWAYS_SIGN|DTOSTR_PLUS_SIGN);
  Serial.println(s);
}
 
void loop() {
}

注意

変換後の文字列を格納する領域は呼び出し側で十分な領域を確保する必要がある。

バージョン

Arduino 1.8.9

最終更新日: April 12, 2020

文字列を数値に変換するには以下のような関数が用意されています。

変換後の数値の形式関数名備考
intatoi()strtol()を呼び出して実現している。
longatol()strtol()を呼び出して実現している。
longstrtol()
unsigned longstrtoul()
doubleatof()strtod()を呼び出して実現している。
doublestrtod()

最終更新日: April 12, 2020

Arduino(というよりは、avr-libcの)sprintf()では、浮動小数点を利用することはできません。代わりに、dtostre()/dtostrf()という関数が用意されているのでそちらを使ってください。sprintf()と組み合わせて利用することもできます。詳細は「小数(浮動小数点数)を文字列に変換する」を見てください。

avr-libcのマニュアルを読むと使えるような記述がありますが、残念ながら、Arduino Unoのsprintf()では、%fを使うことができないようです。avr-libcのvfprintf()の中に以下のような処理が入っていました。Arduino Dueでは利用可能です。

1
2
3
4
5
6
	
if (c && strchr_P (PSTR("EFGefg"), c)) {
    (void) va_arg (ap, double);
    putc ('?', stream);
    continue;
}

このため、float型を文字列には変換できないので注意してください(使っても’?‘が表示されるだけです)。

最終更新日: April 12, 2020

avr-libcのマニュアルを呼んでいたら fdev_setup_stream() という関数がありました。ネットをいろいろ調べてみるとprintf()を使ってシリアルコンソールに出力することができることがわかりました。参考サイトはこちら。ただし、スケッチのサイズが大きくなるので注意してください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
 
static FILE uartout;
 
static int uart_putchar (char c, FILE *stream) {
    if (Serial.write(c) > 0) {
      return 0;
    } else {
      return -1;
    }
}
 
void setup(void) {
  Serial.begin(9600);
  fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
  stdout = &uartout;
 
  int i = 10;
  char s[] = "abcd";
  printf("i = %d, s = %s\n", i, s);
}
 
void loop(void) {
}

最終更新日: April 12, 2020

Arduino Unoでは、デジタルの2番ピン(割り込み番号0)と3番ピン(割り込み番号1)の状態の変化に応じて、割り込みを処理することができます。Arduino Megaでは、さらに、21番ピン(割り込み番号2)、20番ピン(割り込み番号3)、19番ピン(割り込み番号4)、18番ピン(割り込み番号5)を使うことができます。

検出できる状態の変化には、以下の4通りがあります。

状態の変化 attachInterrupt()の第3引数
1 ピンがLOWのとき LOW
2 ピンの値が変わったとき CHANGE
3 ピンがLOWからHIGHに変わったとき RISING
4 ピンがHIGHからLOWに変わったとき FALLING

attachInterrupt()という関数を用いて、割り込み時に起動する関数を登録します。登録できる関数は、戻り値も引数も持つことはできません。使い方は、リファレンスを参照してください。

割り込み処理を行っている間(登録した関数が実行されている間)は、さらなる割り込み処理が禁止されるため、割り込み処理をもとに動作しているdelay()millis()は動作しません(delay()の場合は、実際には指定した値より多く遅延が発生します。millis()で返される値は増えません)。また、登録した関数内で大域変数を操作するときは、その変数をvolatileと宣言しておかないと、コンパイラの最適化により意図した動作をしない可能性があります。

最終更新日: April 12, 2020

Arduino Unoに搭載されているメモリ(SRAM) は、2キロバイトと少ないため、特に、大きな配列を利用したりすると、メモリが足らなくなる場合があります。

SRAMの使用量を削減するための、いくつかの方法を示します(他にもたくさんあると思います)。

変数の型を精査する

例えば、整数を扱う場合、byte(符号なし8ビット)、short/int(16ビット)、long(32ビット)などの種類があります。利用する最大値を精査したうえで、必要な大きさの変数を利用することで、メモリ使用量を削減することができます。

単独の変数では効果が限られますが、配列での利用であれば、効果が出る場合もあります。

フラッシュメモリを利用する

データをSRAMではなく、フラッシュメモリに配置する方法もあります。フラッシュメモリの利用方法はこちらを参照してください。

フラッシュメモリは32キロバイトの領域があります。ただし、スケッチもフラッシュメモリに配置されるので、すべてを利用できるわけではありません。

最終更新日: April 12, 2020

ArduinoとSDカードの物理的な接続には、シールド(SDカードシールド、Ethernetシールドなど)や変換基盤を利用するのが簡単だと思います。

SDカードを利用するためのSDカードライブラリが用意されています。このライブラリでは、以下の制約があります。

  • SDカード・SDHCカードに対応
  • FAT16・FAT32フォーマットに対応
  • ファイル名にはショートネーム(8.3形式)を利用

通信には、SPIを利用しますが、シールドによっては、チップセレクトピン(CSPIN)の番号が異なる場合があるようなので、注意が必要です。

最終更新日: April 12, 2020

Arduinoリファレンスを見ると通常のC言語実行系で利用できる関数があまり載っていません。しかし、Arduino Unoには、avr-libcがリンクされるため、avr-libcで提供されている関数が利用できます。日本語訳を公開しているページはこちら。AVR用に追加されている関数もあります。

Arduino DueやESP-WROOM-32では、利用するコンパイラやライブラリが違うので、利用できる関数も異なります。

最終更新日: April 12, 2020

C言語での関数の構造は以下のようになっています。

1
2
3
4
	
返却値の型 関数名 (仮引数の型 仮引数, ) {
 /* 関数の実体 */
}

返却値の型は、配列型以外のオブジェクトかvoid型です。仮引数の型と仮引数の組は、その関数に必要な数だけ書きます(0個以上です)。

プログラム内で同じような処理がたくさんあるときや、定番の処理を関数として定義しておくと便利です。例えば、アナログピンの電圧を返却する関数は以下のように書くことができます。参照電圧が5Vのときに、analogRead()の出力をミリボルト単位に変換します。

1
2
3
4
	
int analogReadMillivolt(int pin) { /* この関数は int型を返し、名前はanalogReadMillivolt、int型のpinという仮引数をを一つだけ取る。
    return map(analogRead(pin), 0, 1024, 0, 5000);  /* analogRead()で読み取った値を、ミリボルトに変換した値を返却する。 */
}

関数内の仮引数は、関数内で用意された領域に、その関数の呼び出し元で指定した実引数がコピーされたものです。呼び出された関数内で仮引数を変更しても呼び出した側の変数には影響を与えません。返却値が呼び出し側の関数に戻るだけです。ただし、ポインタを使うと間接的に値を変更することができます。

最終更新日: April 12, 2020

配列の要素数をあとから変える可能性があるときには、配列の要素数を動的に取得できると便利です。sizeof演算子を利用することで配列の要素数を取得することができます。

1
2
3
int array[] = { 1, 2, 3 };
 
int array_size = sizeof(array) / sizeof(array[0]);

sizeof(array)で、arrayが占めている総バイト数を得ることができます。また、sizeof(array[0])は、配列の要素1個分の大きさです。よって、総バイト数を要素1個当たりの大きさで割ると、配列の大きさ(要素数)を取得することができます。

最終更新日: April 12, 2020

C言語では多次元配列を利用することができます。例えばキャラクタ液晶画面などに表示する文字列をそのまま保持することができます。

以下は、16x2の配列を宣言する例です。

1
2
3
4
5
6
char display[2][16];
for(int i = 0; i < 2; i++) {
  for(int j = 0; j < 16; j++) {
    display[i][j] = 'a';
  }
}

イメージは以下の通りです。C言語では、配列の添え字は0から始まることに注意してください。

display[0][0] display[0][1] display[0][2] display[0][15]
display[1][0] display[1][1] display[1][2] display[1][15]

メモリ上は以下のように展開されます。行が優先されて展開されます。

1 display[0][0]
2 display[0][1]
3 display[0][2]
15 display[0][15]
16 display[1][0]
17 display[1][1]
18 display[1][2]
31 display[1][15]

最終更新日: April 12, 2020

変数内の特定のビットを1にする

ビット単位のOR演算子(|)を使うことで特定のビットを1にすることができます。

ビット単位のOR演算子は、オペランドのどちらかが1のとき、1になる演算子です。つまり、以下のようになります。

    0 | 0  0
    0 | 1  1
    1 | 0  1
    1 | 1  1

つまり、1ともとのビットとORをとると、そのビットを1にすることができます。一方で、変数は複数のビットから構成されているため、変数内の特定のビットを1にするということは、他のビットは元の値を保持しておく必要があります。上記の演算の左辺をもとの変数と考えると、0とORをとっている1行目と3行目は元の値となっていることがわかります。よって、変数内の特定のビットを1にするには、特定のビットだけを1にし、その他のビットは0の変数とORをとればいいことがわかります。

例えば、変数の第3ビット(右から4番目)を1にするには、変数が8ビットのときは、0b00001000 とORをとればいいということになります。0b00001000は、0b00000001を左に3個シフトした値なので、変数の第nビットを1にするには、1を左にn個シフトした、1«n とORをとるということになります。

まとめると、変数valの第nビットを1にするには、以下のようにします。

1
val |= (1 << n);

Arduinoでは、bitSet()というマクロが以下のように定義されており、利用することが可能です。

1
#define bitSet(value, bit) ((value) |= (1UL << (bit)))

変数内の特定のビットを0にする

ビット単位のAND演算子(&)を使うことで特定のビットを0にすることができます。

ビット単位のAND演算子は、オペランドの両方が1のとき、1になる演算子です。つまり、以下のようになります。

    0 | 0  0
    0 | 1  0
    1 | 0  0
    1 | 1  1

つまり、0ともとのビットとANDをとると、そのビットを0にすることができます。一方で、変数は複数のビットから構成されているため、変数内の特定のビットを0にするということは、他のビットは元の値を保持しておく必要があります。上記の演算の左辺をもとの変数と考えると、1とANDをとっている2行目と4行目は元の値となっていることがわかります。よって、変数内の特定のビットを0にするには、特定のビットだけを0にし、その他のビットは1の変数とANDをとればいいことがわかります。

例えば、変数の第3ビット(右から4番目)を0にするには、変数が8ビットのときは、0b11110111 とANDをとればいいということになります。0b11110111は、0b00000001を左に3個シフトして全体を反転させた値なので、変数の第nビットを0にするには、1を左にn個シフトして反転させた、~(1«n) とANDをとるということになります。

まとめると、変数valの第nビットを0にするには、以下のようにします。

1
val &= ~(1 << n);

Arduinoでは、bitClear()というマクロが以下のように定義されており、利用することが可能です。

1
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))

変数内の特定のビットを反転する

ビット単位の排他OR演算子(^)を使うことで特定のビットを反転することができます。

ビット単位の排他OR演算子は、オペランドの両方のビットが異なるときに1になる演算子です。つまり以下のようになります。

    0 | 0  0
    0 | 1  1
    1 | 0  1
    1 | 1  0

つまり、1ともとのビットと排他ORをとると、そのビットを反転することができます。一方で、変数は複数のビットから構成されているため、変数内の特定のビットを反転するということは、他のビットは元の値を保持しておく必要があります。上記の演算の左辺をもとの変数と考えると、0と排他ORをとっている1行目と3行目は元の値となっていることがわかります。よって、変数内の特定のビットを反転するには、特定のビットだけを1にし、その他のビットは0の変数と排他ORをとればいいことがわかります。

例えば、変数の第3ビット(右から4番目)を反転するには、変数が8ビットのときは、0b00001000 と排他ORをとればいいということになります。0b00001000は、0b00000001を左に3個シフトした値なので、変数の第nビットを反転するには、1を左にn個シフトした、1«n と排他ORをとるということになります。

まとめると、変数valの第nビットを反転するには、以下のようにします。

1
val ^= (1 << n);

Arduinoでは、bitSet()bitClear()とは違い、上記を実現するマクロは定義されていないようです。

最終更新日: April 12, 2020

Arduinoの公式リファレンスには、以下の関数が記載されています。

上記以外にも、AVR Libcが提供する数学ライブラリ(日本語訳)を使うことができます。

例えば、以下のような関数も利用可能です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(log(M_E));   // log(e)      -> 1
  Serial.println(log10(100)); // log10(100)  -> 2
  Serial.println(asin(1.0));  // arcsin(1.0) -> PI/2
  Serial.println(acos(1.0));  // arcsin(1.0) -> 0
  Serial.println(atan(1.0));  // arctan(0.0) -> PI/4
}

void loop() {
  // put your main code here, to run repeatedly:

}

math.hはArduino.hからインクルードされており、Arduino.hは自動でインクルードされるので、math.hをインクルードする必要はありません(インクルードしても問題ありません)。数学ライブラリも自動でリンクされるので、気にする必要はありません。

最終更新日: May 10, 2020

Arduino core for the ESP32のインストールのページを参照してください。

最終更新日: April 12, 2020

WiFi接続とNTPクライアントの実験(ESP-WROOM-32)WiFiClientのスケッチ例を参照してください。

最終更新日: April 12, 2020

WiFi接続とNTPクライアントの実験(ESP-WROOM-32)を参照してください。

最終更新日: April 12, 2020

現時点(2019/06/01)では、Arduino core for the ESP32に、analogWrite()は実装されていません。ただし、いくつか、PWMを生成する機能は存在します。

以下のページを参照してください。

最終更新日: April 12, 2020

HTTPクライアントになるには、例えば、以下の方法があります。

  • WiFiライブラリに含まれる、WiFiClientクラスを利用する。
    この方法は、TCPクライアントとなるだけなので、HTTPプロトコルを自分で実装する必要があります。WiFiClientに実装例があります。

  • HTTPClientライブラリを利用する。
    この方法は、ライブラリがHTTPプロトコルを実装しているので、比較的簡単に利用できます。BasicHttpClientに実装例があります。

最終更新日: May 10, 2020

HTTPSクライアントになるには、例えば、以下の方法があります。

上記どちらの方法でも、ルート証明書の信頼性は、自分で確認・担保する必要があります。

最終更新日: May 10, 2020

inserted by FC2 system