電子工作に役立つ情報公開サイト



















Arduinoではじめる電子工作超入門改訂第2版 [ 福田和宏 ]

価格:2,678円
(2017/1/27 13:51時点)
感想(0件)




Arduinoをはじめよう 互換キット UNO R3対応互換ボード 初心者専用実験キット 基本部品セット20 in 1 Arduino sidekick basic kit

価格:5,536円
(2017/1/27 13:39時点)
感想(0件)

アルティメイト UNO R3 スターター キット for Arduino 1602 LCD Servo モーター LED リレー RTC EK8004 (海外取寄せ品)

価格:10,089円
(2017/1/27 19:02時点)
感想(0件)

Gikfun アルティメイト スターター learning キット for Arduino UNO R3 LCD1602 Servo モーター Diy EK8450 (海外取寄せ品)

価格:12,409円
(2017/1/27 13:46時点)
感想(0件)

Arduino MEGA用UCTRONICS Ultimateスターター学習キット

価格:8,905円
(2019/8/20 19:12時点)
感想(0件)




SainSmart 24 In 1 モジュール Sensor スターター キット For Arduino (海外取寄せ品)

価格:8,646円
(2017/1/27 19:04時点)
感想(0件)

SainSmart 20 Sensor モジュール UNO R3 エデュケーション スターター キット with 1 リレー モジュール HC-SR04 Distance Sensor PDF Tutorial Instruction for Arduino UNO MEGA2560 R3 Duemilanove 2013 Robot (海外取寄せ品)

価格:11,137円
(2017/1/27 19:05時点)
感想(0件)




[EMS便無料]メガarduino 2560 r 3のための互換性を3 atmega2560-16auボードusbケーブル[楽天海外直送]

価格:1,738円
(2019/8/20 19:11時点)
感想(0件)

STM32 ARM Arduino Mini マイクロコントローラ

価格:583円
(2019/8/20 19:08時点)
感想(0件)

Arduino Due 32 bit ARM マイクロコントローラ

価格:5,702円
(2019/8/20 19:15時点)
感想(0件)




電子工作キット(ARDUINO用イーサネットシールド)KA04

価格:3,672円
(2017/1/27 19:25時点)
感想(0件)

Arduino モーターシールド Rev3

価格:3,510円
(2017/1/27 19:26時点)
感想(0件)

【サンハヤト Sunhayato】Arduino用ユニバーサル基板 UB-ARD01

価格:510円
(2017/1/31 20:08時点)
感想(0件)




デジタル・マイクロサーボ SG90 (5個) SG90-D-5

価格:3,176円
(2017/1/27 19:09時点)
感想(0件)

日本ニューティーシー ステッピングモータ(1.7kgクラス) 【SE-SM243】

価格:4,229円
(2017/1/29 10:06時点)
感想(0件)

ステッピングモーター12V/330mA

価格:4,536円
(2017/1/29 10:12時点)
感想(0件)

【イーケイジャパン エレキット】コード付超高輝度LED(白色・5mm)LK-5WH-C50

価格:340円
(2017/1/27 19:30時点)
感想(0件)

高輝度 LEDルームランプ FLUX 18LED仕様 ホワイト ledルームランプ 汎用 車ledルームランプ 車内ledルームランプ 汎用タイプledルームランプ ledルームランプ

価格:380円
(2017/1/27 19:21時点)
感想(1件)

<ゼロプレッシャーICソケット通販・販売>ゼロプレッシャーICソケット(ZIF)<28ピン><1co-011>

価格:583円
(2017/1/28 13:27時点)
感想(0件)

送料無料!!【ホーザン HOZAN】X-Yテーブル K-50 【smtb-u】

価格:12,910円
(2017/1/29 22:34時点)
感想(0件)

PROXXON(プロクソン) [27100] マイクロ・クロステーブル 27100【送料無料】 02P03Dec16

価格:8,213円
(2017/1/29 22:49時点)
感想(3件)

【プロクソン PROXXON】クロステーブル No.27150

価格:12,800円
(2017/1/29 22:50時点)
感想(0件)




Arduino ArduinoUno用交換チップ(ブートローダ書き込み済み) 【SSCI-ATMEGA328P OPTIBOOT】

価格:504円
(2017/1/29 10:23時点)
感想(0件)




espressif ESP-WROOM-02 Wi-Fiモジュール

価格:864円
(2017/1/28 13:16時点)
感想(0件)

espressif ESP-WROOM-02ピッチ変換済みモジュール(フル) Wi-Fiモジュール

価格:909円
(2017/1/28 13:18時点)
感想(0件)




<圧電ブザー通販・販売><圧電ブザーC>2個<con-271>

価格:83円
(2017/1/27 14:10時点)
感想(0件)

>Kaito7576(10個) 5mm CdSセル(光可変抵抗器) GL5516

価格:250円
(2017/2/23 02:07時点)
感想(1件)




>DSO203 ポケット デジタルオシロスコープ ミニキット 72MHz 4-CH STM32 メタルシェル

価格:22,850円
(2017/2/11 23:05時点)
感想(1件)

avr(arduino)
pic
python
java
engineering work

avr(arduino)


IDE(Integrated Development Environment)統合開発環境の準備

・IDEはインストーラータイプとそうでないものがあり、 インストーラータイプでないものを利用すれば異なるバージョンを共存させられる。(インストーラータイプは旧バージョンのアンインストールを求められる。)ファイルはarduinoのサイトからダウンロードできるが、上位互換ということでもないので必ずしも最新版にする必要はない。
・IDEを起動したらメニューのツールからボード(Arduino/Genuin Uno等)を選択。
・同じくツールからシリアルポートを選択。(arduinoをUSB接続するとデバイスマネージャーからポート番号を確認できる。)

スケッチの書き方(基本)

(前置き)
arduino言語の文法等はC言語とC++言語がベースとなっている。 スケッチ(プログラム)は未経験者や専門知識を持たない者でも描けるようにというコンセプトで色々と簡略化、自動化されている。必要な場合はそれらに頼らずに書くこともできる。 スケッチの基本は最初に1度だけ実行したい初期設定等の内容をsetupの中に書き、繰り返し実行させたい内容をloopの中に書くこと。初めのうちは大抵のことはこれだけで事足りる。 (※変数の種類とスコープ(有効範囲)という概念を理解していればとりあえず問題ない。)C言語ではコンパイラーが関数等をチェックするために冒頭にプロトタイプと呼ばれるものを記述することになっているが、arduinoではこれも自動化されているため通常は不要となっている。

・必要なライブラリのインクルード
・グローバル変数やローカル変数の定義
・プログラムの記述(setupとloopの何れかという書き方も可)
・左上メニュー直下のチェックマークボタンでスケッチを検証
・その右横のボタンで検証とマイコンボードに書き込み
※利用可能な関数等については「arduino日本語リファレンス」等の参考になるサイトがある。
※メニューのツールにある自動整形は体裁を整えるのに便利。

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

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

void function( ) {
 // put your function code here:
}
 
緊急地震速報のサンプルスケッチ
const byte soundpin = 10;

void setup( ) {
  pinMode(soundpin,OUTPUT);
}

void loop( ) {
  com = 70;

  tone(soundpin,392,com);
  delay(com + 1);
  tone(soundpin,523,com);
  delay(com + 1);
  tone(soundpin,659,com);
  delay(com + 1);
  tone(soundpin,932,com);
  delay(com + 1);
  tone(soundpin,1244,com);
  delay(com + 100);

  tone(soundpin,415,com);
  delay(com + 1);
  tone(soundpin,554,com);
  delay(com + 1);
  tone(soundpin,698,com);
  delay(com + 1);
  tone(soundpin,987,com);
  delay(com + 1);
  tone(soundpin,1318,com);
  delay(com + 600);
}

 

シリアルモニタの活用

arduinoのIDEにはシリアルモニタやシリアル通信に必要な関数が標準で用意されていて、PCとarduinoの間で直ぐにシリアル通信ができるようになっている。そのためとりわけ表示器を設けなくてもプログラムの実行結果をシリアルモニタで確認したり、外部入力を設けなくてもシリアルモニタからarduinoにデータを送って指示を与えるといったことが簡単にできるようになっている。シリアルモニタはIDEの右上にある虫眼鏡のようなマークを押せば開く。(一部のarduinoを除き、シリアルモニタを開く度にプログラムがリセットされる)使う時には予め用意されている定型の関数をスケッチにも記述しておく必要がある。
※通信速度はスケッチで指定した速度(数値)とシリアルモニタの速度(シリアルモニタの右下の設定)を同じ値に設定しなければ通信できないので注意。
PCからarduinoにデータを送る際はバッファには64バイトまでストックされるが読み込みは1バイトずつなので、処理も1バイトずつ行うようにプログラムしなければならない。文字をやり取りする場合はデータの中身としてはアスキーコード(例 "A" = 0x41)になっていることも念頭に置いておくと良い。engineering workにあるLCD制御のarduino用のプログラムに<こちら>を追加(sample部分と置き換え)すればシリアルモニタから送った文字をLCDに表示させることができる。

 

構文(syntax)等について(備忘録)

・条件分岐にはif文とswitch文があり何れもお互いに書き換え可能だが、一般に多分岐の場合はswitch文の方が処理速度が速いとされている。switch文はcaseの定数式の値がコンパイル時に確定していないとエラーになるので変数(#define等で定義された定数は使用可)は使えない。caseの評価はbreakしなければ一通り行われる。
・whileやforなどのループから途中で抜け出すにはbreakやgotoを使う。但し、gotoを使いたくなったら一度プログラムを見直すように心掛けた方が良い。
・比較演算子は型が決まっているので、例えば、>= や <= を => や =< とすると気が付きにくいエラーになるので順序に注意。= は常に右側にくると覚えよう。
・配列変数は確保する要素数と指定する要素とは数値が一致しないことに注意。例えば、一次元の配列の要素を10確保する場合は
 Array[10]
となるが、使う場合は
 Array[0から9を指定] となる。また、初期化の際の要素数は
 Array[]
のように省略することもできるので要素数が不確定の場合は省略する。多次元配列の場合は
 Array[][2]
 Array[][2][3]
のように大本の要素のみ省略できることになっている。配列を関数等に間接的に渡す時は
 *Array
のように受け取り時の配列変数の前に「*」を付けてポインター(配列の先頭アドレスが渡る)を使用する。
・変数の修飾子であるconstとvolatileは効果が対照的と覚えると分かり易い。何れも確実を期すために用いられる。(arduinoでvolatileの既述の必要がある場合は割り込み時に使用する変数のみ(アセンブリを除く))
・関数の引数としてデフォルト引数を指定する場合はプロトタイプで宣言する。
 例 function(int arg = 1);

 

外部ライブラリのインクルード

ダウンロード等したライブラリはメニューのスケッチにあるInclude Libraryでzip形式のものもそのまま取り込むことができる。 手動で行う場合はarduinoホームのlibraryフォルダに追加したいライブラリのフォルダ(圧縮でないもので、その直ぐ下の階層にヘッダファイル等があるもの。)を置く。 但し、手動の場合はIDEの再起動が必要。


マイライブラリを作ろう

よく使う定数等はヘッダファイル(.h)に定義しておくと便利。
keywords.txtに色分け(強調)や桁チェックのための単語等を登録しておくと便利。

作り方(概要)

・IDEの右上にある▼から新規タブを選び任意の名前と属性(.h又は.cpp)を付ける。
・ヘッダファイル(.h)には作成するクラスや関数、ソースファイル(.cpp)で使用する変数等を定義。
・ソースファイル(.cpp)には関数の具体的な実行内容を記述。(ヘッダファイル(.h)にまとめて書くことも可。)
・スケッチの保存先にヘッダファイルとソースファイルが生成される。
・keywords.txtを作る場合はヘッダファイルとソースファイルのあるフォルダに置く。
※ヘッダファイルとソースファイルを単体で開いて編集等する場合は対応したエディタが必要。
※一度読み込まれたライブラリはファイルを変更してもIDEを再起動するまで有効なので注意。


 サンプルライブラリ(配列の要素をシャッフル)
//ヘッダファイル
#ifndef Array_Shuffle_H//必須
#define Array_Shuffle_H//必須

class Array_Shuffle{//クラス定義(オブジェクト定義)、クラス名=ライブラリ名

 public:
  Array_Shuffle(void);//コンストラクタ定義、コンストラクタ=クラス名
  void Act(uint8_t *Ary, uint8_t Elements, uint8_t Times, uint8_t UnusePin);
  //関数名定義

 private:
  uint8_t i, y, j, t;//ソースファイルで使用するグローバル変数を定義(この場合はグローバルでなくてもよい)
};

#endif//必須
 
//ソースファイル
#include "arduino.h"//標準関数等用
#include "Array_Shuffle.h"

Array_Shuffle::Array_Shuffle(void) {//クラス名とコンストラクタ
}//ヘッダファイルで定義した変数の初期化等は必要に応じてここで行う

void Array_Shuffle::Act(uint8_t *Ary, uint8_t Elements, uint8_t Times, uint8_t UnusePin) {//関数の具体的な実行内容

 randomSeed((analogRead(UnusePin) + analogRead(UnusePin)) / 2);
 //randomSeedの引数はunsigned int

 for ( y = 0; y < Times; y++) {
  for ( i = 0; i < Elements; i++) {//fisher yates shuffle algorism
   j = random(Elements);
   t = Ary[i];
   Ary[i] = Ary[j];
   Ary[j] = t;
  }
 }
}
 
//使用例
Array_Shuffle AS;

byte list[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

AS.Act(list, sizeof(list), 10, A5);
 
 上のソースファイルをヘッダファイルにまとめて書く場合
//ヘッダファイル
#ifndef Array_Shuffle_H//必須
#define Array_Shuffle_H//必須

class Array_Shuffle{//クラス定義(オブジェクト定義)、クラス名=ライブラリ名

 public:
  Array_Shuffle(void){//コンストラクタ定義、コンストラクタ=クラス名
  };//定義した変数の初期化等は必要に応じてここで行う

  void Act(uint8_t *Ary, uint8_t Elements, uint8_t Times, uint8_t UnusePin){
  //関数名と実行内容定義

   randomSeed((analogRead(UnusePin) + analogRead(UnusePin)) / 2);
   //randomSeedの引数はunsigned int

   for ( y = 0; y < Times; y++) {
    for ( i = 0; i < Elements; i++) {//fisher yates shuffle algorism
     j = random(Elements);
     t = Ary[i];
     Ary[i] = Ary[j];
     Ary[j] = t;
    }
  };

 private:
  uint8_t i, y, j, t;//クラス内で使用するグローバル変数を定義
};

#endif//必須
※カッコ内の v o i d は省略可
※スケッチはコピペすると全角スペースが入っているためエラーになる


 
 定数等定義用サンプルヘッダファイル(.h)
#ifndef private_define_H
#define private_define_H


typedef unsigned char uchar;//0~255 = byte = uint8_t
typedef unsigned int uint;//0~65,535 = uint16_t
typedef unsigned long ulong;//0~4,294,967,295 = uint32_t

#define High (1)
#define Low (0)
#define Inv (2)//Invert
#define On (1)
#define Off (0)
#define F5v10b (4.8875855)//float 5v/1023(10bit)
#define F3v10b (3.2258064)//float 3.3v/1023(10bit)
#define Pi (3.1415926)//float f(PI) = 3.14

#endif
 
 サンプルキーワードファイル(keywords.txt)
private_define <Tab> KEYWORD1

Pi <Tab> KEYWORD2

00000000 <Tab> LITERAL1
 

IDEをカスタマイズしよう

libフォルダにあるpreference.txtの各項目を編集することで、IDEの環境設定をより細かく設定できる。 例えば、起動時のエディタサイズ等を指定。
他に、example-01.BasicフォルダにあるBareMinimum.inoというスケッチを編集しておけば既定の記述を設定できる。
※古いIDEは未対応

 
 カスタマイズしたIDE(起動時の初期画面)
 

プリプロセッサ(コンパイラに対する命令)を使おう

プリプロセッサにデバイス指定しておくとエラー防止になる。

 
 arduino uno 等のATmega328Pのチップを搭載の場合
#ifndef __AVR_ATmega328P__//Preprocessor
#error "Device Error"//エラーメッセージ
#endif
 

デジタルポート(Read,Write)の高速化※アナログポートもデジタルポートとして使用可

プログラム内計測で標準関数を使用した場合が8uSの時、ポートレジスタを操作すると0uS。 これを関数化しても同等のパフォーマンスを得られる(0uS)が、ライブラリ化すると4uSに下がる。 但し、ヘッダファイルにまとめて書いた場合のライブラリ化は関数化と同等だと思われる。

 
 digitalWriteのFunction関数化サンプルスケッチ
//ATmega328~pinMode(#, OUTPUT)
//digitalWrite(0 to 19)

void port(byte p_num, byte sw) {
 if (p_num < 8){
  if (sw == 1) {PORTD |= _BV(p_num);}
  if (sw == 0) {PORTD &= ~_BV(p_num);}
 }else if (p_num < 14){
  if (sw == 1) {PORTB |= _BV(p_num - 8);}
  if (sw == 0) {PORTB &= ~_BV(p_num - 8);}
 }else if (p_num < 20){
  if (sw == 1) {PORTC |= _BV(p_num - 14);}
  if (sw == 0) {PORTC &= ~_BV(p_num - 14);}
 }else{
  return;
 }
}
 
 ポートレジスタ単位での一括操作のFunction関数化サンプルスケッチ
void multi_port(byte p_reg, byte sw, byte bin){
 if (p_reg == 0){
  if (sw == 1) {PORTD |= bin;}//sw(1)=on(only '1' bit turn on)
  if (sw == 0) {PORTD &= bin;}//sw(0)=off(exept '1(&1)' bit turn off)
  if (sw == 2) {PORTD ^= bin;}//sw(2)=invert(only '1' bit invert)
 }else if (p_reg == 1){
  if (sw == 1) {PORTB |= bin;}
  if (sw == 0) {PORTB &= bin;}
  if (sw == 2) {PORTB ^= bin;}
 }else if (p_reg == 2){
  if (sw == 1) {PORTC |= bin;}
  if (sw == 0) {PORTC &= bin;}
  if (sw == 2) {PORTC ^= bin;}
 }else{
  return;
 }
}
 
 digitalReadのFunction関数化サンプルスケッチ
//ATmega328~pinMode(#, INPUT)
//digitalRead(0 to 19)

byte d_read(byte p_num){
 boolean state;
 if (p_num < 8){
  state = PIND & _BV(p_num);
 }else if (p_num < 14){
  state = PINB & _BV(p_num - 8);
 }else if (p_num < 20){
  state = PINC & _BV(p_num - 14);
 }else{
  return 0;
 }
 return state;
}
 
//使用例
#include <private_define.h>

multi_port(2, Inv, B00100000);//A5, HIGH

multi_port(2, Inv, B00100000);//A5, LOW
 

外部割込みを使ってみよう

arduinoには標準関数から利用できるINTピンとPCINTピンの2種類の外部割込みが設定されていて、ATmega328チップ等の場合は前者が2ピンで後者が23ピン(前者の2ピンはPCINTピンとしても機能)用意されている。INTピンは割り込みベクタ(要因番号)がそれぞれ独立していて、割り込みを生じさせるタイミングもそれぞれ4種類設定できるようになっている。PCINTピンは全てのI/Oピンと数は多いが割り込みベクタがI/Oポート単位になっていてタイミングもロジックレベルの変化時に限られている。割り込みハンドラーは割り込みベクタ単位での実行となる。

外部割込みはマイコンの状態にかかわらず何らかの信号のタイミングや一定周期で何かをさせたりスリープ状態から復帰させたりする時に有効な手段である。しかし、外部割込みピンがたくさんあっても外部割込みが必要な場合は大抵2つのINTピンがあれば事足りてしまう。PCINTはおまけみたいなものだが、例えば、あるピン固有の機能と併用したい場合等は非常に便利である。

使用することはそうそう滅多にあるものではないが、PCINTを用いる場合で同一I/Oポートで複数ピンの割り込みを設定した時の判定方法のスケッチの一例

#include <avr/io.h>//IOライブラリのインクルード

volatile byte PCI0FR = 0;//PCI1FR, PCI2FR

void setup( ) {
 PCICR = (1 << PCIE0);
 PCMSK0 = 0x03;//PCINT0, PCINT1
 sei( );
}

ISR(PCINT0_vect){//PCINT1_vect, PCINT2_vect
 cli( );
 PCI0FR = PCMSK0 & PINB;//Low to High
 PCI0FR = (PCMSK0 ^ PINB) & PCMSK0;//High to Low
 //Some Description
 sei( );
}

これは単にフラグを立てるだけの記述なのでハンドラーのISR(InterruptServiceRoutine)内で処理を済ませる場合は処理方法は様々。

 

ソフトウェアでリセットが必要な場合(本来の使い方以外で)はwdtを利用しよう

例えば、wdtを条件分岐で真の時に有効、偽の時に無効にすれば任意のタイミングでリセットできる。※スリープ状態からの復帰にも利用可能。

ウォッチドッグタイマーに必要な記述

#include <avr/wdt.h>//ウォッチドッグタイマー用インクルード

wdt_enable(WDTO_15MS);//有効
//WDTO_=15MS,30MS,60MS,120MS,250MS,500MS,1S,2S,4S,8S

wdt_reset();//リセット

wdt_disable();//無効

PWM(Pulse Width Modulation)を使ってみよう

arduinoで簡単にPWMを使うには

analogWrite(pin, value);//OFF:value = 0 又は digitalWrite(pin, LOW);

という関数を利用する(利用できるIOピンがATmega328であれば3,5,6,9,10,11ピンと決まっている)方法がある。この関数は使い勝手はよいが周波数が固定(490Hz,一部のIOピンで980Hz)されているのでLEDの明るさを変えるといったデューティー比(0-255)を変化させるだけでよい場合に使える。この関数だけを使う場合はピンモードの初期設定は不要。反対にデューティーが50%の固定で周波数を自由に変えるには

tone(pin, frequency, duration);//OFF:noTone(pin);

という関数を利用するとよい。(こちらはピンモードの設定が必要)何れも変えたいという場合はレジスタを直接操作する必要がある。PWMのモードは4つあり、そのうちのPWM Phase and Frequency Correct Mode((Mode8 or Mode9)9pin,10pin)を使えば任意の周波数とデューティー比のPWM出力を得られる。PWMはモード等を設定すると、指定したピンから常時出力されているので、ON/OFFはデューティーの設定を変えることで行える。(指定ピンをPWMモード以外で使用する場合はTCCR1A = 0にしてPWMモードを解除する)周波数の計算は
   focnxpfcpwm = fclk_io / 2・N・TOP
   (Nはプリスケーラ―の値,TOPはOCR1A又はICR1の値(16bit))
の式で算出。使用方法は次のとおり。

#include<avr/io.h>

void setup( ) {
 pinMode(pin, OUTPUT);//pinは 9 又は 10
 TCCR1B = B00010010;//prescale * 8
 ICR1 = 1912;//523Hz
 OCR1B = 956;//Duty50%
 TCCR1A = B00100000;//PFCPWM Non-Inverted
}

PWMは設定と同時に出力されるので実際は関数化して必要な時に呼び出すなどした方が実用的。

(設定のイメージ)

tone関数とPWM Phase and Frequency Correct Mode(Mode8)を併用した和音の演奏


PROGMEMを使ってみよう

arduinoはATmega328であればデータメモリ用のRAMの容量が2Kバイトとそれ程大きくないなので、少し大きめの定数データ等を扱う場合はPROGMEMを使えばプログラムエリアに格納しておくことが可能で必要に応じてRAMに展開できる。データが文字列の場合は文字列を使用する際にF( )マクロを利用すれば簡単に同じ効果が得られる。PROGMEMの場合はライブラリー<avr/pgmspace.h>のインクルードが必要で、扱えるデータの型や読み込み方法が決まっているのでそれらに従って行う。


EEPROMを使ってみよう

arduinoにはプログラムを書き込むためのFlashROMとEEPROMという設定やデータを保存するための電源を切っても消えない不揮発性のROM(Read Only Memory)、データメモリ用の揮発性のRAM(Random Access Memory)が入っている。EEPROMを使うために標準で予め用意されている関数は

EEPROM.read(address);

EEPROM.write(address, value);

で、初期化メソッドはない。ROMのデータ保持期間は常温で100年、消去、書き込みの耐久性はFlashが1万回でEEPROMが10万回となっている。EEPROMへの書き込みは耐久性を考えると利用する場合は工夫した方がよい。決まった設定やデータ等はスケッチを変更したりプログラムが実行される度に書き込む必要はないので、EEPROMを書き込むためだけのスケッチを用意したり利用するプログラムを工夫しなければならない。EEPROMを初めて使う場合の簡単な工夫の例は

if(EEPROM.read(0) == 0xFF){
   EEPROM.write(address, value);//address(0 to 1023),value(0 to 255)
又は
   for(int i = 0; i < sizeof(value); i++){//Array
     EEPROM.write(i, value[i]);
   }
}

等。EEPROMの容量はATmega328であれば1kバイトなので、初期値はその全てに「1」が書き込まれていて、1バイト(8ビット)毎の仕切りなのでどのアドレスのデータも「FF」となっている。

 

内蔵基準電圧を利用してみよう

arduinoは電圧を計測するための標準電池のような参照用の基準電圧を内部に持っていて、analogRead関数を実行するとその基準電圧と比較した結果がデジタル値として得られるようになっている。基準電圧の参照はDEFAULTで電源電圧(AVCC(5V))となっているが、電源電圧は不安定なのでより高い精度で微小な電圧変化を計測するには信頼性のある外部電源を用意するか内蔵の基準電圧(ATmega328等は1.1V)を用いる。ADC(Analog-to-Digital Converter)の精度は10ビット(1024段階)で±2 LSB(最下位ビット)となっているので、基準となる電圧さえ安定した信頼できるものであれば高精度であることがわかる。基準電圧の選択は

analogReference(DEFAULT);

analogReference(INTERNAL);

analogReference(EXTERNAL);

で行え、プログラム中で切り替えて使うこともできる。外部の基準電圧を参照するにはAREFに基準となる電圧を入力するようになっているが、ADCの入力範囲がVCCまでとなっているので超高精度の電源を利用するにしてもADCの温度補正のことも考慮すれば通常の使用に於いてはEXTERNALを利用するメリットは今のところあまり感じられない。analogReadで読み取った電圧値は

DEFAULTの場合は 5 ÷ 1023 ≒ 4.9mV

INTERNALの場合は 1.1 ÷ 1023 ≒ 1.1mV


なので、

デジタル値 × 4.9又は1.1mV

という計算になる。内部基準電圧を利用した電圧、電流の計測の例はengineering workにあります。

 

内蔵温度センサーを利用してみよう

arduino(ATmega328)には実は温度センサーが内蔵されているのだが、普通の使い方では利用できない。チップの仕様書を見ると温度センサーはADCの温度補正のために内蔵されているようなのだがそれもどうやらそのままでは眠ったままのようだ。ADCはDIPタイプで6チャンネル、FPタイプで8チャンネル利用できることになっているが、実は9チャンネル目があって、それが温度センサー専用となっている。DIPタイプも温度センサーの値を読み取るのに9チャンネルにアクセスするということは7、8チャンネルも内部的には存在しているものと思われる。 9チャンネルにアクセスして温度センサーの値を読み取るには0x7C番地にあるADMUXと0x7A番地にあるADCSRAという2つのレジスタの操作が必要で、これはanalogRead()という標準関数を利用した時にも同じように操作されているらしいのだが、この関数では何故か扱えない仕様になっている。ADMUXのレジスタは参照する基準電圧と読み取るチャンネル指定の設定、ADCSRAのレジスタは読み取り変換開始の設定となっている。温度センサーは内蔵の1.1Vを基準電圧として計測され10ビットのデジタル値に変換される。仕様書には温度と温度センサーから出力される電圧の代表的な相関関係表があるがより精度を求めるならEEPROMなどに書き込まれているチップ毎のキャリブレーションをいじらなければならないようなのであまり参考にはならない。 1mV/℃という相関は概ね正しい。温度の計算は仕様書には

T = { [ ( ADCH << 8 ) | ADCL ] - Tos } / k

となっていて、ADCHはADCの上位バイトでADCLは下位バイト。Tosは温度センサーのオフセット値でkは係数。このオフセット値がEEPROMなどにありkも分からないのでどうにもならない。更に仕様書には温度センサーの精度が±10℃と書かれているが、それは恐らく工場出荷時にその程度のキャリブレーションを行っているという意味なのだと思われる。上の式のとおり温度を求めるのに電圧はなくても良いので、キャリブレーションはそういうことなのかも知れない。実際に計測してみると、デジタル値は温度とリニアに相関があり、温度センサー自体は実用に耐え得る精度がある。但し、計測された温度は水銀温度計と比較すると、マイコンに通電した直後は±1℃以内とほぼ同じ値を示すがデジタル値で直ぐに+2、5分以内に+3、10分後を最後に最大+4の上昇がみられる。実際に水銀温度計をマイコンに密着させると確かに温度上昇が見られ温度センサーの誤差も±1℃程度以内となっている。 そのため、内蔵温度センサーは環境測定用としては不向きで、例えば、構築したシステムやマイコン周辺の温度の測定用とすれば特にソフトウェア的に補正しなくとも直ぐに使える。温度センサーの値の取得は

ADMUX = 0xC8;//(REFS1,REFS0,MUX3 set)

ADCSRA |= 0x40;//(ADSC set)

と設定すれば、ADCHとADCLのレジスタに10bitのデジタル値が格納される。但し、内蔵温度センサーの測定範囲が判らないので、仕様書の相関関係表にある最低温度と最高温度を採用することにして、チップ毎に誤差があるにしてもその範囲のデジタル値はADCLの値だけで事足りるが、仕様書によれば、ADCLを読んだ場合は、ADCHが読まれるまでADCLが更新されないと書かれているので、ADCHも事務的に読む必要があり読む順序も自ずと決まってくる。ADCSRAレジスタのADSCビットは変換が完了すると自動でクリアされるので読み出したい時にセットすれば良い。温度の計算はチップ毎にオフセット等が異なるので参考までに示せば

byte Lbyte = ADCL;
byte Hbyte = ADCH;

T = map(Lbyte, 16, 146, -45, 85);//-45℃~85℃

で行える。但し、実装する場合は、初めて変換が行われる際にADCの初期化のために誤差がでるので数回ダミー計測するなどの工夫が必要なのと、計測にはそれなりに時間がかかることに注意。

 
 ADCの9チャンネルにもアクセスできるanalogReadのFunction関数化サンプルスケッチ
//ATmega328
//analogRead(0 to 8) //ref(0=EXTERNAL, 1=DEFAULT, 3=INTERNAL)

word a_read(byte p_num, byte ref){
 byte state;
 if (p_num >= 0 && p_num < 9 && ref < 4 && ref != 2){
  ADMUX = ((ref << 6) | p_num);
  ADCSRA |= 0x40;
  while (bit_is_set(ADCSRA, ADSC));
  byte Lbyte = ADCL;
  byte Hbyte = ADCH;
 }else{
  return (Hbyte << 8 | Lbyte);
 }
 return 0;
}
 

arduinoのライターシールドを作ろう

arduinoのIDEにはATmega328P等の外部白チップにブートローダー等を書き込む機能がある。 配線数は多くないのでブレッドボード等を使っても良いが、繰り返し使いたい場合は専用シールドとして 製作しておいた方が良い。作り方を公開しているサイトもあるので製作手順はそちらを参照。 ゼロプレッシャーICソケットとフラットパッケージ用ソケット(TQFP32 to 28)を組み合わせればフラット パッケージチップへの書き込みもDIPタイプと同じようにできる。参考までに、クリスタルはクロック周波数を変えられるように、見づらいが画像にあるようにピンフレームなどを用いて固定しないように設計した方がよい。

 

アセンブリ言語を使ってみよう

真に高速化が必要な場合はマシン語の一歩手前のアセンブリ言語をインラインで用いると良い。アセンブリはCPUの一挙手一投足の動作を記述しなければならないのでいわゆるarduino言語と比較すれば記述が非常に長くなり見た目では高速化を実感できないが、Arduinoなどのavrマイコンの場合は一つの命令を実行するのに必要なサイクル(1フェッチ)の殆どが1クロックとなっていてる(CPI=1と表す、picマイコンはCPI=4)ので相当な高速化が見込める。 アセンブリはマシン語を人間がより分かり易いようにニーモニックという命令を表す記号とその対象となるオペランドという被演算子(レジスタや即値等)を記述することになっている。また、インラインで記述する場合(arduinoIDEの場合はインラインのみ)は、経験的に、一関数内での記述に行数制限があるようだ。

アセンブリは8bitマイコンの場合は基本的に8bitの任意或いは特定のレジスタ(記憶装置)を操作するという作業になる。ニーモニックは種類や数がマイコンの種類によって異なっていて、avrの場合は130命令程定義されているので、記述の際はその一覧表を参照しながら行うことになる。(特定のレジスタ等についてはマイコン毎に異なるのでマイコン毎の仕様書を参照しなければならない)また、それらの命令によって影響を受けて変化するステータスレジスタというものもあり、そのレジスタにはある条件下でのみ変化する数種類のフラグという便利なものが設定されているので、記述の際はその変化を意識しながら設計することも合理性の面で重要となってくる。

アセンブリをインラインで記述する場合はその宣言も必要となり、任意の関数内に

asm volatile( );

と記述してその( )内にアセンブリコードを記述する。コードは1命令1行で記述(しないと分かりづらい)し、1行毎に" "で囲って改行コードも末尾に挿入しなければならない。

例)
asm volatile(
"nop \n"
"nop \n"
);


この例は1行に1クロックが費やされるので、合わせて2クロックが費やされる。arduino unoの場合はクロック周波数が16MHzなので、1クロックが0.0625uS(=62.5nS)で0.125uS費やされるというように計算する。この場合はオペランドはなく、nopは無操作の命令を表すニーモニック。インラインアセンブリの仕様はアセンブリから通常の関数を呼び出したり方法は一通りではないが変数を共有(データ空間の変数と汎用レジスタの共有)したりも出来るようになっている。アセンブリは慣れてこないと8bitの制約の中での計算(一部16bitでの加減算可)や変数の扱いには戸惑うことになるが、非常に高速且つ正確に動作しているので一つ一つを厳格に設計しなければならずコンパイラが何とか解釈してくれるということもないので誤魔化しが利かない。なのでそういった高速性や厳格性が求められる場面で使用すると良い。

参考までにオペランドのあるものとしてアセンブリでの四則演算のうち符号なしの加算と減算について簡単な例を示すと次のようになる。

加算(16bit + 16 bit 又は 16bit + 8bit)

a(r16, r17) + b(r18, r19)

add r16, r18
adc r17, r19



減算(16bit - 16 bit 又は 16bit - 8bit)

a(r16, r17) - b(r18, r19)

sub r16, r18
sbc r17, r19


※8bitの場合はr19を値が0のダミーレジスタに設定すれば良い。

細かい解説は割愛するが、このaddやadc、sub、sbcがニーモニックでr**がオペランドになる。

 
DTI WiMAX 2+ ギガ放題プラン

付録

モールス信号生成スケッチ(要圧電ブザー) コードの表示

Cdsセルを使ったLEDの自動調光スケッチ コードの表示 ① ② 回路図

ステッピングモーターのテスト調整用スケッチ コードの表示 ユニポーラ

和音スケッチ コードの表示

違うアルゴリズムによる和音スケッチ(スピーカー用) コードの表示 接続図

 
※当サイトは手書きです。
 
inserted by FC2 system