セクションの複数ページをまとめています。 印刷またはPDF形式で保存...

もとのページに戻る

2024-05-17 現在

クラスオブジェクト

ネットワークやペリフェラルを操作するために定義されたオブジェクト

クラスオブジェクトは、MWXライブラリであらかじめ定義されたオブジェクトで、TWENETを取り扱うthe_twelite、ペリフェラルの利用のためのオブジェクトが定義されています。

各オブジェクトは.setup(), .begin()メソッドの呼び出しを行って初期化する必要があります。

(UART0を利用するSerialオブジェクトのみ初期化は必要ありません)

1 - the_twelite

TWENET 利用の中核クラス (mwx::twenet)
the_tweliteオブジェクトは、TWENETの利用手続きをまとめたもので、無線の基本設定やスリープ等の手続きなど無線マイコンを操作するための手続きが含まれます。

概要

the_twelitesetup()関数内で設定と開始the_twelite.begin()を行います。setup()以外では設定は行えません。

void setup() {
  ...
 	the_twelite
		<< TWENET::appid(APP_ID)
		<< TWENET::channel(CHANNEL)
		<< TWENET::rx_when_idle();
  ...
  the_twelite.begin();
}

上記の例では、アプリケーションIDの設定、通信チャネルの設定、受信回路の設定を行っています。

様々な手続きが含まれます。

// シリアル番号を得る
uint32_t u32hwser = the_twelite.get_hw_serial();

// チャネルを 11 に設定する
the_twelite.change_channel(11);

// 1秒のスリープを行う
the_twelite.sleep(1000);

// リセットを行う
the_twelite.reset_system();

また無線ネットワークを取り扱うクラスやボード対応をまとめたクラス、ユーザ記述のイベントドリブン処理を行うクラスを登録できるようになっています。このクラスを登録することにより、専用化した機能を手軽に利用できるようになります。これらのクラスを本解説中では「ビヘイビア」と呼称します。

void setup() {
	/*** SETUP section */
	// use PAL_AMB board support.
	auto&& brd = the_twelite.board.use<PAL_AMB>();

	...

	// Register Network
	auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
	nwk << NWK_SIMPLE::logical_id(u8ID);

上記の例では環境センサーパル<PAL_AMB>と、シンプル中継ネットワーク<NWK_SIMPLE>の2種類を登録しています。これらを登録することにより環境センサーパル上のセンサーなどハードウェアを簡易に取り扱うことが出来ます。また煩雑な無線パケットの取り扱いについて中継の処理や重複で届いたパケットの自動破棄などの機能を暗黙に持たせることが出来ます。

メソッド

<<演算子 (設定)

オブジェクトthe_tweliteの初期設定を行うために<<演算子を用います。

以下に挙げる設定用のクラスオブジェクトを入力とし、設定をしなければデフォルト値が適用されます。

TWENET::appid(uint32_t id)

パラメータidに指定したアプリケーションIDを設定します。これは必須指定です。

設定の読み出しは uint32_t the_twelite.get_appid() で行います。

TWENET::channel(uint8_t ch)

パラメータchに指定したチャネル番号(11..26)を設定します。

設定の読み出しはuint8_t the_twelite.get_channel()で行います。

TWENET::tx\_power(uint8\_t pw)

パラメータpwに指定した出力設定を(0..3)を設定します。デフォルトは(3:出力減衰無し)です。

設定値の読み出しはuint8_t the_twelite.get_tx_power()で行います。

TWENET::rx_when_idle(uint8_t bEnable)

パラメータbEnable1であれば常に受信回路を動作させ、他からの無線パケットを受信できるようになります。デフォルトは0で、もっぱら送信専用となります。

設定値の読み出しはuint8_t the_twelite.get_rx_when_idle()で行います。

TWENET::chmgr(uint8\_t ch1 = 18, uint8\_t ch2 = 0, uint8\_t ch3 = 0)

チャネルマネージャを有効にします。チャネルを複数指定すると複数チャネルでの送受信を行います。ch2,ch3に0を指定すると、その指定は無効になります。

STG_STD

インタラクティブモードの設定値を反映します。

auto&& set = the_twelite.settings.use<STG_STD>();
...
set.reload();       // 設定値をロード
the_twelite << set; // インタラクティブモードの設定値を反映

反映される項目は以下です。

  • app_id
  • channel
  • tx_power
  • MAC ack 使用時の再送回数

begin()

void begin()

事前に設定(<<演算子参照)や、ビヘイビアの登録を済ませた後に実行します。通常はsetup()関数内の一番最後に記述します。

  • the_twelite 設定完了
  • ビヘイビアの初期化

void setup() {
	// use PAL_AMB board support.
	auto&& brd = the_twelite.board.use<PAL_AMB>();

	// settings
 	the_twelite
		<< TWENET::appid(APP_ID)
		<< TWENET::channel(CHANNEL)
		<< TWENET::rx_when_idle();

	// Register Network
	auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
	nwk << NWK_SIMPLE::logical_id(u8ID);

	// somo others

	// begin the TWENET!
	the_twelite.begin();
}

change_channel()

inline bool change_channel(uint8_t u8Channel)

チャネル設定を変更します。失敗時にはチャネルは変更されずfalseを戻します。

get_channel_phys()

uint8_t get_channel_phys()

現在設定中のチャネル番号(11..26)を取得する。MAC層のAPIより取得します。

get_hw_serial()

inline uint32_t get_hw_serial()

モジュールのシリアル番号を取得します。

sleep()

inline void sleep(
        uint32_t u32Periodms,
        bool_t bPeriodic = true,
        bool_t bRamOff = false,
        uint8_t u8Device = TWENET::SLEEP_WAKETIMER_PRIMARY)

モジュールをスリープさせる。

パラメータ解説
u32Periodmsスリープ時間[ms]
bPeriodic前回の起床時間をもとに次の起床時間を再計算する。
※次の起床タイミングが迫っているなどの理由で、現在のタイミングからになる場合もあります。
bRamofftrueに設定すると、RAMを保持しないスリープになる(起床後はwakeup()ではなくsetup()から再初期化する必要がある)
u8Deviceスリープに用いるウェイクアップタイマーの指定。TWENET::SLEEP_WAKETIMER_PRIMARYまたは TWENET::SLEEP_WAKETIMER_SECONDARYを指定する。

is_wokeup_by_dio()

bool is_wokeup_by_dio(uint8_t port)

スリープからの復帰要因が指定したディジタルピンである場合にtrueを返します。

is_wokeup_by_wktimer()

bool is_wokeup_by_wktimer()

スリープからの復帰要因がウェイクアップタイマーである場合にtrueを返します。

reset_system()

inline void reset_system()

システムをリセットします。リセット後はsetup()からの処理となります。

stop_watchdog()

inline void stop_watchdog()

ウォッチドッグタイマーを停止します。長時間のポーリング待ちを行うような場合はタイマーを停止します。

restart_watchdog()

inline void restart_watchdog()

ウォッチドッグタイマーを再開します。

ビヘイビア

twe_tweliteには3つのビヘイビアを登録でき、これらを格納する以下のクラスオブジェクトを定義されています。

  • network : ネットワークを実装するビヘイビアです。通常は<NWK_SIMPLE>を登録します。
  • network2 : ネットワークを実装するビヘイビアです。最初に networkでペイロードのデータ構造などの判定により受理しなかったパケットを、別のネットワーク ビヘイビアで処理させたい場合に使用します。(参考: NWK_LAYERED と NWK_SIMPLEの併用)
  • board: ボード対応のビヘイビアです。ボード上の各デバイス利用手続きが付加されます。
  • app: ユーザアプリケーションを記述したビヘイビアです。割り込みやイベント記述、ステートマシンによる状態遷移によるふるまいの記述が可能です。また複数のアプリケーション記述を定義しておいて、起動時に全く振る舞いの違うアプリケーションを選択する記述が容易に行えます。
  • settings: 設定(インタラクティブモード)を実行するためのビヘイビアです。<SET_STD>を登録します。

use<B>()

// 例
auto&& brd = the_twelite.board.use<PAL_AMB>();

ビヘイビア<B>を登録します。登録はsetup()内で行います。戻り値は登録したビヘイビアに対応するオブジェクトの参照です。

登録後は登録時と同じ書式でオブジェクトの取得を行います。

クラスオブジェクト

the_tweliteには上述のboard, network, appの3つのクラスオブジェクトが定義されていますが他に以下が定義されています。

tx_status

送信完了状態を通知する。

is_complete()

bool is_complete(uint8_t cbid)

指定したIDのパケットが送信完了したときにtrueを返す。

is_success()

bool is_success(uint8_t cbid)

指定したIDのパケットが送信完了し、かつ送信成功したときにtrueを返す。

receiver

受信パケットを取得する。

available()

bool available()

まだ読み出していない受信パケットが存在する場合にtrueを返す。

read()

packet_rx& read()

パケットを読み出します。

2 - Analogue

ADC (mwx::periph_analogue.hpp)
Analogueは、ADCの実行と値の取得を行います。一度に複数のチャネルを連続取得でき、またこれをタイマーなどの周期に合わせて逐次実行可能です。

定数

ピンの定義

定数種別標準アプリでのピン名
uint8_t PIN_ANALOGUE::A1 = 0ADC1ピンAI1
uint8_t PIN_ANALOGUE::A2 = 1ADC2ピンAI3
uint8_t PIN_ANALOGUE::A3 = 2``uint8_t PIN_ANALOGUE::D0 = 2ADC3ピン (DIO0) *1AI2
uint8_t PIN_ANALOGUE::A4 = 3``uint8_t PIN_ANALOGUE::D1 = 3ADC4ピン (DIO1) *1AI4
uint8_t PIN_ANALOGUE::VCC = 4Vcc 電源電圧

メソッド

setup()

void setup(
        bool bWaitInit = false,
        uint8_t kick_ev = E_AHI_DEVICE_TICK_TIMER,
        void (*fp_on_finish)() = nullptr)

ADCの初期化を行います。setup()では、半導体内部のレギュレータの始動、周期実行するためのタイマーデバイスの指定、指定チャネルすべてのADCが終了したときに呼び出されるコールバック関数の指定します。

パラメータ解説
bWaitInittrueを指定すると、半導体内部のレギュレータの初期化を待つ。
kick_ev周期実行に指定するタイマーデバイスを指定する。指定可能なデバイスは、以下の5種類で、初回以外は割り込みハンドラ内でADが開始される。E_AHI_DEVICE_TICK_TIMER (TickTimer)``E_AHI_DEVICE_TIMER0 .. 4 (Timer0 .. 4)
fp_on_finish指定されたポートすべてのADCが終了後に、割り込みハンドラ内から呼び出されるコールバック関数。ADC計測値をFIFOキューなどに別途格納したい場合に利用する。

begin()

void begin(uint8_t bmPorts, uint8_t capt_tick = 1)

1番目のパラメータにはADCを行いたいポートを指定します。ポートの指定はピンの定義で述べたポート番号に対応するビットをセットしたビットマップになります。例えば PIN_ANALOGUE::A2PIN_ANALOGUE::VCCの2つのピンの値を得たい場合は (1 <<PIN_ANALOGUE::A1 | 1<<PIN_ANALOGUE::VCC )を指定します。pack_bitsを用いpack_bits(PIN_ANALOGUE::A1,PIN_ANALOGUE::VCC)のように記述することもできます。

begin()の呼び出し後、速やかに最初のADC処理が開始され、その終了割り込から次のピンの処理を開始します。すべての処理が終われば(指定されている場合)コールバック関数が呼び出されます。次のタイマー割り込みが発生まで待ってから新たなADC処理を開始します。

2番目のパラメータは、ACを開始するまでのタイマー割り込みの回数を指定します。例えばTickTimerは1msごとに呼び出されますが、パラメータに16を指定すれば 16msごとの処理になります。

void begin()

デフォルトのADCピン(PIN_ANALOGUE::A1,PIN_ANALOGUE::A2)を指定してADC処理を開始します。end()では中断したADC処理を再開します。

end()

void end()

ADC処理を終了し、半導体内部のレギュレータを停止します。

available()

inline bool available()

ADCの値が取得後にtrueになります。本関数により確認した後は次のADC完了まではfalseです。

read(), read_raw()

inline int16_t read(uint8_t s)
inline int16_t read_raw(uint8_t s)

ADC値を読み出します。パラメータには読み出したいADCピンを指定します。read()はmVに変換した読み値、read_raw()はADCの値(0..1023)を戻します。

ADC割り込みハンドラ

ADCの割り込みハンドラはsetup()の呼び出し時にperiph_analogue::ADC_handler()に設定されます。

半導体のペリフェラルライブラリで別途ハンドラを指定すると正常に動作しなくなります。

スリープ時の振る舞い

ADCがbegin()により周期実行状態であれば、スリープ復帰後もADC処理を再開します。

3 - Buttons

デジタル入力管理クラス (mwx::periph_buttons)
デジタル入力の変化を検出します。このクラスは、同じ検出値が複数回得られたときに変化を検出します。メカ式のボタンのチャタリングの影響を小さくするのに有効です。

メソッド

setup()

void setup(uint8_t max_history);

パラメータのmax_historyは、begin()で設定可能な参照回数の最大値です。ここではメモリーの確保と初期化を行います。

begin()

void begin(uint32_t bmPortMask,
				   uint8_t u8HistoryCount,
				   uint16_t tick_delta);

Buttonsの動作を開始します。1番目のパラメータbmPortMaskは監視対象のデジタル入力のビットマップを指定します。bit 0がDIO 0, … , bit N がDIO Nに対応します。複数指定することができます。2番目のu8HistoryCountは値の確定をするのに必要な回数です。3番目のtick_deltaは値の確認を行う間隔をmsで指定します。

値の確定にはu8HistoryCount*tick_delta[ms]かかることになります。例えばu8HistoryCount=5, tick_delta=4の場合は、状態の確定に最低約20msかかります。

確認はTickTimerのイベントハンドラで行っています。割り込みハンドラではないので、処理等の遅延の影響を受けますが、メカ式ボタン等のチャタリング抑制には十分です。

end()

void end()

Buttonsの動作を終了します。

available()

inline bool available()

変化が検出されたときにtrueを返します。read()を実行するとクリアされます。

read()

bool read(uint32_t& u32port, uint32_t& u32changed)

availableになったとき呼び出します。u32portは現在の入力DIOのビットマップ、u32changedは変化が検出されたDIOのビットマップです。

Buttonsが動作していない場合はfalseを返します。

動作について

初回の値確定

Buttonsが動作を開始した時点では、DIOの入力状態は未確定です。値が確定した時点でavailableになります。このときread()で読み出すビットマップのMSB(bit31)が1にセットされます。

動作確定を要するため、入力値が定常的に変化するポートを監視する目的では利用できません。

スリープ

スリープ前にButtonsが稼働状態であれば、復帰後に再開します。再開後、初回確定を行います。

4 - EEPROM

内蔵EEPROMに対して読み書きを実行

TWELITE 無線マイコンの内蔵EEPROMに対して読み書きを実行します。

内蔵EEPROMはアドレス0x000~0xEFFまでの3480バイトが利用可能です。

先頭部分は設定(インタラクティブモード)に利用されるため、併用する場合は後半のアドレスの利用を推奨します。設定(インタラクティブモード)でどの程度の領域を消費するかは、その実装に依存します。最小限度の設定であっても先頭から256バイトまでは利用されるため、それ以降の利用を推奨します。

メソッド

read()

uint8_t read(uint16_t address)

EEPROMからaddressに対応するデータを読み出します。

write()

void write(uint16_t address, uint8_t value)

EEPROMからaddressに対してvalueを書き込みます。

update()

void update(uint16_t address, uint8_t value)

write()と同じく書き込みを行いますが、先にaddressにあるデータを読み出してvalueと違う場合のみ、書き込みを行います。EEPROMの書き換え寿命を考慮し、書換回数を減らしたいときに用います。

get_stream_helper()

auto&& get_stream_helper()
// 戻り値型は長くなるためauto&&と省略しています。

後述のmwx::streamを用いた読み書きを行うために、ヘルパーオブジェクトを取得します。

mwx::streamインタフェースを用いた入出力

stream_helper ヘルパーオブジェクトを経由して、mwx::streamによる演算子やメソッドを用います。mwx::streamを用いるとuint16_tuint32_t型といった整数型の読み書き、uint8_tの固定長配列型の読み書き、format()オブジェクトによる書式整形などが可能になります。

auto&& strm = EEPROM.get_stream_helper();
// ヘルパーオブジェクトの型名は長くなるためauto&&により解決しています。

このオブジェクトに対して<<演算子などmwx::streamで定義されたインタフェースを利用できます。

strm.seek(1024); // 1024バイト目に移動

strm << format("%08x", 12345678); // 12345678を16進数の8文字で記録
strm << uint32_t(0x12ab34cd);     // 0x12ab34cd の4バイトを記録
uint8_t msg_hello[16] = "HELLO WORLD!";
strm << msg_hello;                // バイト列 "HELLO WORLD!" を記録(終端なし)

// 結果
// 0400: 30 30 62 63 36 31 34 65 12 ab 34 cd 48 45 4c 4c
//        0  0  b  c  6  1  4  e  0x12ab34cd  H  E  L  L
// 0410: 4f 20 57 4f 52 4c 44 21 00 00 00 00 ff ff ff ff
//        O SP  W  O  R  L  D  !

.seek()を用いてEEPROMのアドレスを1024に移動しています。

上記では8バイト文字列(00bc614e)、4バイト整数(0x12ab34cd)、16バイトバイト列(HELLO WORLD!...)、1バイト終端文字を書き込んでいます。

strm.seek(1024);

uint8_t msg1[8];
strm >> msg1;
Serial << crlf << "MSG1=" << msg1;
// MSG1=00bc614e

uint32_t var1;
strm >> var1;
Serial << crlf << "VAR1=" << format("%08x", var1);
// VAR1=12ab34cd

uint8_t msg2[16]; // "HELLO WORLD!"の文字数
strm >> msg2;
Serial << crlf << "MSG2=" << msg2;
// MSG2=HELLO WORLD!

.seek()を用いてEEPROMのアドレスを1024に移動しています。

先ほど書き出したデータ列を読み出します。順番に8バイト文字、4バイト整数、16バイト文字列を>>演算子を用いて読み出します。

5 - PulseCounter

パルスカウンタ (mwx::periph_pulse_counter)
パルスカウンタは、マイコンのCPUが稼働していない時もパルスを読み取り計数する回路です。

パルスカウンターは2系統あります。PC0はPulseCounter0, PC1はPulseCounter1に割り当てられます。また**PulseCounterPulseCounter1**の別名です。

メソッド

begin()

void begin(uint16_t refct = 0,
           E_PIN_INT_MODE edge = PIN_INT_MODE::FALLING,
           uint8_t debounce = 0)

オブジェクトを初期化し、計数を開始します。1番目のパラメータrefctは割り込みやavailable判定の基準となるカウント数です。この数を超えたときにアプリケーションに報告されます。またrefctには0を指定することもできます。この場合は、スリープ起床要因にはなりません。

2番目のパラメータedgeは割り込みが立ち会がり(PIN_INT_MODE::RISING)か立下り(PIN_INT_MODE::FALLING)を指定します。

3番目のdebounceは、0,1,2,3の値をとります。1,2,3の設定はノイズの影響を小さくするため値の変化の検出に連続した同じ値を要する設定です。

設定連続サンプル数最大検出周波数
0-100Khz
123.7Khz
242.2Khz
381.2Khz

end()

void end()

検出を中止します。

available()

inline bool available()

指定カウント数(begin()refct)が0の場合は、カウントが1以上でtrueを返します。

指定カウント数(begin()refct)が1以上の場合は、検出回数が指定カウント数を超えた場合にtrueとなります。

read()

uint16_t read()

カウント値を読み出します。読み出し後にカウント値を0にリセットします。

6 - Serial

UART0 ポート (mwx::serial_jen)
mwx::stream を実装し TWELITE の UART0 で入出力します。
  • Serialオブジェクトはシステム起動時に UART0, 115200 bps で初期化され、ライブラリ内で初期化処理が行われます。ユーザコード上は、setup()から利用できます。
  • Serial1オブジェクトは、ライブラリ内で用意されていますが、初期化処理は行っていません。UART1を有効化するためには、必要な初期化手続き Serial1.setup(), Serial1.begin() を行ってください。

setup()

void setup(uint16_t buf_tx, uint16_t buf_rx)

オブジェクトの初期化を行う。

  • TX/RX用のFIFOバッファのメモリ確保
  • TWE_tsFILE 構造体のメモリ確保
パラメータ解説
buf_txTX用のFIFOバッファサイズ
buf_rxRX用のFIFOバッファサイズ

begin()

void begin(unsigned long speed = 115200, uint8_t config = 0x06)

ハードウェアの初期化を行う。

パラメータ解説
speedUART のボーレートを指定する。
configserial_jen::E_CONF::PORT_ALTビットを指定したときは、UART1をDIO14,15で初期化します。指定しない場合はDIO11(TxD),9(RxD)で初期化します。

end()

(未実装)ハードウェアの使用を停止する。

get_tsFile()

TWE_tsFILE* get_tsFile();

Cライブラリで利用する TWE_tsFILE* 形式での構造体を得る。

7 - SerialParser

シリアルポート用書式入力 (mwx::serial_parser)
この組み込みクラスはシリアルポートでの書式入力に利用することを想定して組み込みオブジェクトとして定義しています。

初期化時(begin())にヒープから内部で使用するバッファ領域を確保するmwx::serial_parser<mwx::alloc_heap<uint8_t>>型として定義されています。

詳細はクラス serparser を参照してください。

8 - SPI

SPIバス (Controller) の読み書き
SPIバス (Controller) の読み書きを行います。

注意事項

定数

定数意味
const uint8_t
SPI_CONF::MSBFIRST
MSB を先頭ビットにする
const uint8_t
SPI_CONF::LSBFIRST
LSB を先頭ビットにする
const uint8_t
SPI_CONF::SPI_MODE0
SPI MODE 0 に設定する
const uint8_t
SPI_CONF::SPI_MODE1
SPI MODE 1 に設定する
const uint8_t
SPI_CONF::SPI_MODE2
SPI MODE 2 に設定する
const uint8_t
SPI_CONF::SPI_MODE3
SPI MODE 3 に設定する

初期化と終了

SPIバスの利用手続きはbegin()メソッドによります。

begin()

void begin(uint8_t slave_select, SPISettings settings)
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)

ハードウェアの初期化を行います。

パラメータ解説
slave_select使用するSPIスレーブのセレクトピンを指定する。0 : DIO19``1 : DIO0 (DIO 19 は予約されます)``2 : DIO1 (DIO 0,19 は予約されます)
settingsSPIのバス設定を指定します。

clock[hz]でSPIバスの周波数を指定します。指定した周波数に近いディバイザが選択されます。16Mhzまたは16Mhzを偶数で割った値になります。
bitOrderSPI_CONF::MSBFIRSTSPI_CONF::LSBFIRSTを指定します。
dataModeSPI_CONF::SPIMODE0..3を指定します。

void setup() {
  ...
  SPI.begin(0, SPISettings(2000000, SPI_CONF::MSBFIRST, SPI_CONF::SPI_MODE3));
  ...
}

void wakeip() {
  ...
  SPI.begin(0, SPISettings(2000000, SPI_CONF::MSBFIRST, SPI_CONF::SPI_MODE3));
  ...
}

end()

void end()

SPIのハードウェアの利用を終了します。

読み書き

読み書きの手続きは、以下の2種類あります。いずれかを選択して利用します。

8.1 - SPI (メンバ関数版)

SPI (メンバ関数を使用する方法)
begin()メソッドによりハードウェアの初期化を行った後、beginTransaction()によりバスの読み書きができるようになります。beginTransaction()を実行するとSPIのセレクトピンが選択されます。読み書きはtransfer()関数を用います。SPIは読み出しと書き込みを同時に実行します。

beginTransaction()

void beginTransaction()
void beginTransaction(SPISettings settings)

バスの利用開始を行います。SPIのセレクトピンをセットします。

settingsパラメータを与えて呼び出した場合は、バスの設定を行います。

endTransaction()

void endTransaction()

バスの利用を終了します。SPIのセレクトピンを解除します。

transfer(), transfer16(), transfer32()

inline uint8_t transfer(uint8_t data)
inline uint16_t transfer16(uint16_t data)
inline uint32_t transfer32(uint32_t data)

バスの読み書きを行います。trasnfer()は8bit、transfer16()は16bit、transfer32()は32bitの転送を行います。

8.2 - SPI (ヘルパークラス版)

SPI (ヘルパークラスを使用する方法)
ヘルパークラス版はより抽象度が高い実装です。読み書きを行うオブジェクト transceiver を生成することが、バスの利用開始となり、オブジェクトを破棄するとバス利用の終了手続きを行います。

if文の判定式内でオブジェクトの生成を行うことで、オブジェクトの有効期間はif節内のスコープに限定され、if節を抜けた時点でオブジェクトは破棄され、その時点でバスの利用終了の手続きを行います。

uint8_t c;
if (auto&& trs = SPI.get_rwer()) { // オブジェクトの生成とデバイスの通信判定
   // このスコープ(波かっこ)内が trs の有効期間。
   trs << 0x00; // 0x00 を mwx::stream インタフェースで書き出し
   trs >> c;    // 読み出したデータをcに格納。
}
// if 節を抜けるところで wrt は破棄され、バスの利用終了

また、読み書きオブジェクトは、mwx::streamインタフェースを実装しているため<<演算子などを利用することができます。

  • バスの利用開始と終了をオブジェクトの有効期間と一致させることで、ソースコードの見通しを良くし、また終了手続きの記述漏れなどを防ぎます
  • mwx::streamインタフェースによる読み書き手続きを統一します

読み書き

読み込み処理とその終了手続きをスコープ内 if() { ... } で行うためのヘルパークラスを用いた読み込み方法。

inline uint8_t _spi_single_op(uint8_t cmd, uint8_t arg) {
    uint8_t d0, d1;
    if (auto&& x = SPI.get_rwer()) {
        d0 = x.transfer(cmd); (void)d0;
        d1 = x.transfer(arg);
        // (x << (cmd)) >> d0;
        // (x << (arg)) >> d1;
    }

    return d1;
}

上記では get_rwer() メソッドにより生成された x オブジェクトを用いて1バイトずつ読み書きを行っています。

  1. if(...) 内で x オブジェクトを生成します。同時にSPIバスのセレクトピンをセットします。(型は、型推論によるユニバーサル参照 auto&& で解決しています。)
  2. 生成した x オブジェクトには operator bool () が定義されており、判定式の評価として利用される。SPIバスの場合は常に true となる。
  3. x オブジェクトには uint8_t transfer(uint8_t) メソッドが定義されていて、これを呼び出すことでSPIに対して8bitの読み書き転送を行。
  4. if() { ... } スコープの末尾で x のデストラクタが呼び出され、SPIバスのセレクトピンを解除します。

get_rwer()

periph_spi::transceiver get_rwer()

SPIバスの読み書きに用いるワーカーオブジェクトを取得します。

ワーカーオブジェクト

transfer(), transfer16(), transfer32()

uint8_t transfer(uint8_t val)
uint16_t transfer16(uint16_t val)
uint32_t transfer32(uint32_t val)

それぞれ8bit,16bit,32bitの転送を行い、読み取り結果を書き込んだデータ幅と同じデータ幅で返す。

<<演算子

operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)

int型,uint8_t型は8bitの転送を行います。

uint16_t型、uint32_t型は、それぞれ16bitの転送、32bitの転送を行います。

転送結果は最大16バイトの内部FIFOキューに格納され >> 演算子により読み出します。バッファが大きくないので、転送都度読み出すことを想定します。

>>演算子

operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)

null_stream(size_t i = 1)
operator >> (null_stream&& p)

直前の転送と同じデータ幅の変数を指定します。

読み出した結果が不要の場合はnull_stream()オブジェクトを使用します。iで指定したデータバイト分だけ読み飛ばします。

9 - TickTimer

システムタイマー (mwx::periph_ticktimer)
TickTimerはTWENETの内部制御用に利用され、暗黙に実行されています。タイマーの周期は1msです。loop()中でTickTimerイベントにより1msごとの処理を記述する目的でavailable()メソッドのみを定義しています。

メソッド

available()

inline bool available()

TickTimer割り込み発生後にセットされ、その直後のloop()trueになります。loop()終了後にクリアされます。

10 - Timer0 .. 4

タイマー, PWM (mwx::periph_timer)
タイマーでは、指定周期でのソフトウェア割り込みを発生させる目的、指定周期でPWM出力を行う2つの機能があります。TWELITE無線モジュールには0..4まで合計5つのタイマーが利用可能です。

組み込みオブジェクト名は Timer0..4 ですが、このページでは TimerXと記載します。

メソッド

setup()

void setup()

タイマーを初期化します。この呼び出しにより必要なメモリ領域の確保を行います。

begin()

void begin(uint16_t u16Hz, bool b_sw_int = true, bool b_pwm_out = false)

タイマーを開始します。1番目のパラメータは、タイマーの周期でHzで指定します。2番目のパラメータをtrueにするとソフトウェア割り込みが有効になります。3番目のパラメータをtrueにするとPWM出力を有効にします。

end()

void end()

タイマーの動作を停止します。

available()

inline bool available()

タイマー割り込みが発生した直後のloop()trueになり、loop()が終了すればfalseになります。

change_duty()

void change_duty(uint16_t duty, uint16_t duty_max = 1024)

デューティー比の設定です。1番目のパラメータにデューティ比を指定します(小さい値を指定すると波形の平均はGNDレベルに近づき、大きい値を指定するとVccレベルに近づく)。2番目のパラメータはデューティ比の最大値を指定します。

change_hz()

void change_hz(uint16_t hz, uint16_t mil = 0)

タイマーの周波数を設定します。2番目のパラメータは周波数の小数点3桁分の値を整数で指定します。例えば 10.4 Hz としたい場合は hz=10, mil=400 と指定します。

11 - Wire

2線シリアル (I2C) master (controller) としての読み書き (mwx::periph_wire)
2線シリアル(I2C) master (controller) としての読み書きを行います。

定義

別名定義

using TwoWire = mwx::periph_twowire<MWX_TWOWIRE_RCVBUFF>;

mwx::periph_wire<MWX_TWOWIRE_RCVBUFF>TwoWireとして参照可能です。

型定義

以下の定義型で引数や戻り値の型を記載します。

typedef uint8_t size_type;
typedef uint8_t value_type;

注意事項

初期化と終了

Wire インスタンスの生成

ライブラリ内でインスタンスの生成と必要な初期化は行われます。ユーザコードでは Wire.begin() を呼び出すことで利用可能となります。

requestFrom() メソッドを用いる場合、データを一時保管するための FIFO キューのサイズを指定できます。コンパイル時にマクロMWX_TWOWIRE_BUFF に必要なバイト数を指定してコンパイルする。デフォルトは 32 バイトです。

例: -DMWX_TWOWIRE_BUFF=16

begin()

void begin(
    const size_type u8mode = WIRE_100KHZ,
    bool b_portalt = false)

ハードウェアの初期化を行います。

パラメータ解説
u8modeバス周波数を指定する。デフォルトは100Khz(WIRE_CONF::WIRE_100KHZ)
周波数はWIRE_CONF::WIRE_??KHZで指定し??には50,66,80,100,133,160,200,266,320,400を指定できる。
b_portaltハードウェアのピン割り当てを変更する。

void setup() {
    ...
    Wire.begin();
    ...
}

void wakeup() {
    ...
    Wire.begin();
    ...
}

読み書き

読み書きの手続きは、以下の2種類あります。いずれかを選択して利用します。

その他

プローブ(デバイスの存在判定)

bool probe(uint8_t address)

address で指定したデバイスが応答するかを確認します。デバイスが存在する場合は true が戻ります。

setClock()

void setClock(uint32_t speed)

本来はバス周波数を変更するための手続きですが、何も処理をしません。

11.1 - Wire (メンバ関数版)

Wire (メンバ関数を使用する方法)

メンバ関数を利用した方法は、抽象度が比較的低く、C言語ライブラリで提供されるような一般的なAPI体系に倣っています。二線シリアルバスの操作手続きがより直感的です。

ただしバスの利用の開始と終了を明示的に意識して記述する必要があります。

読み込み

requestFrom()

size_type requestFrom(
    uint8_t u8address,
    size_type length,
    bool b_send_stop = true)

指定バイト数分を一括で読み出します。読みだした結果はキューに保存されるため、直後にキューが空になるまで .read() メソッドを呼び出すようにしてください。

パラメータ解説
u8address読み出し対象のI2Cアドレス
length読み出しバイト数
b_send_stop=truetrue の時、読み込み終了時にSTOPビットを設定する。
戻り値型 size_type読み出したバイト数。 0 は読み出しの失敗。

コード例

int len = Wire.requestFrom(0x70, 6);
for (int i = 0; i < 6; i++) {
  if (Wire.available()) {
		  au8data[i] = Wire.read();
    Serial.print(buff[i], HEX);
  }
}
// skip the rest (just in case)
// while (Wire.available()) Wire.read(); // normally, not necessary.

書き出し

書き出し処理は、beginTransmission() を実行後、write() メソッドにより行います。一連の書き出しが終了したら endTranmission() を呼びます。

	#define DEV_ADDR (0x70)
	const uint8_t msg[2] =
	  {SHTC3_SOFT_RST_H, SHTC3_SOFT_RST_L};

	Wire.beginTransmission(DEV_ADDR);
	Wire.write(msg, sizeof(msg));
	Wire.endTransmission();

beginTransmission()

void beginTransmission(uint8_t address)

書き出しの転送を初期化する。書き出し処理終了後、速やかに endTransmission() を呼び出す。

パラメータ解説
u8address書き出し対象のI2Cアドレス

write(value)

size_type write(const value_type value)

1バイトの書き出しを行う。

パラメータ解説
value書き込むバイト
戻り値 size_type書き込んだバイト数。0はエラー。

write(*value, quantity)

size_type write(
  const value_type* value,
  size_type quantity)

バイト列の書き出しを行います。

パラメータ解説
*value書き込むバイト列
size_typeバイト数
戻り値 size_type書き込んだバイト数。0はエラー。

endTransmission()

uint8_t endTransmission(bool sendStop = true)

書き出しの終了処理を行います。

パラメータ解説
sendStop = trueSTOPビットを発行します。
戻り値 uint8_t0: 成功 4: 失敗

11.2 - Wire (ヘルパークラス版)

Wire (ヘルパークラスを使用する方法)
ヘルパークラス版はより抽象度が高い実装です。読み書きに対応するオブジェクト reader, writer を生成することがバスの利用開始となり、オブジェクトを破棄するとバス利用の終了手続きを行います。

if文の判定式内でオブジェクトの生成を行うことで、オブジェクトの有効期間はif節内のスコープに限定され、if節を抜けた時点でオブジェクトは破棄され、その時点でバスの利用終了の手続きを行います。

if (auto&& wrt = Wire.get_writer(...)) { // オブジェクトの生成とデバイスの通信判定
   // このスコープ(波かっこ)内が wrt の有効期間。
   wrt << 0x00; // 0x00 を mwx::stream インタフェースで書き出し
}
// if 節を抜けるところで wrt は破棄され、バスの利用終了

また読み書きオブジェクトはmwx::streamインタフェースを実装しているため<<演算子などを利用することができます。

  • バスの利用開始と終了をオブジェクトの有効期間と一致させることで、ソースコードの見通しを良くし、また終了手続きの記述漏れなどを防ぐ
  • mwx::streamインタフェースによる読み書き手続きの統一

読み込み

読み込み処理とその終了手続きをスコープ内 if() { ... } で行うためのヘルパークラスを用いた読み込み方法です。

const uint8_t DEV_ADDR = 0x70;
uint8_t au8data[6];
if (auto&& rdr = Wire.get_reader(DEV_ADDR, 6)) {
		for (auto&& c: au8data) {
			c = rdr();
		}
}

// same above
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(SHTC3_ADDRESS, 6)) {
		rdr >> u16temp;
		rdr >> u8temp_csum;
		rdr >> u16humd;
		rdr >> u8humd_csum;
}

上記では get_readr() メソッドにより生成された rdr オブジェクトを用いて1バイトずつ読み出しします。 メソッドのパラメータには読み込みたい二線シリアル ID を指定します。

  1. if(...) 内で rdr オブジェクトを生成。(型は、型推論によるユニバーサル参照 auto&& で解決しています。)
  2. 生成した rdr オブジェクトには operator bool () が定義されており、判定式の評価として利用される。指定された ID により通信が可能であれば true となる。
  3. rdr オブジェクトには int operator () (void) 演算子が定義されていて、これを呼び出すことで2線シリアルバスから1バイトのデータを読み出す。読み込みに失敗したときは -1 が戻り、成功した場合は読み込んだバイト値が戻る。
  4. if() { ... } スコープの末尾で rdr のデストラクタが呼び出され、二線シリアルバスの STOP を行う。

get_reader(addr, read_count=0)

periphe_wire::reader
get_reader(uint8_t addr, uint8_t read_count = 0)

I2C 読み出しに用いるワーカーオブジェクトを取得します。

パラメータ解説
addr読み込み用のI2Cアドレス
read_count読み出しバイト数(この値を指定すると最後の転送で STOP ビットを発行する)。0を指定した場合は STOP ビットなしとなる(デバイスによっては動作するものもあります)

書き出し (writer)

書き出し処理とその終了手続きをスコープ内 if() { ... } で行うためのヘルパークラスを用いた読み込み方法です。

const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
	wrt(SHTC3_TRIG_H);
	wrt(SHTC3_TRIG_L);
}

// same above
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
	wrt << SHTC3_TRIG_H; // int type is handled as uint8_t
	wrt << SHTC3_TRIG_L;
}

上記では get_writer() メソッドにより生成された wrt オブジェクトを用いて1バイトずつ書き出す。 メソッドのパラメータには読み出したい二線シリアル ID を指定します。

  1. if(...) 内で wrt オブジェクトを生成する。(型名は長くなるため auto で解決)
  2. 生成した wrt オブジェクトには operator bool () が定義されており、判定式の評価として利用される。指定された ID により通信が可能であれば true となる。
  3. wrt オブジェクトには int operator () (void) 演算子が定義されていて、これを呼び出すことで2線シリアルバスに1バイトのデータを書き出しす。失敗したときは -1 が戻り、成功した場合は書き込んだバイト値が戻る。
  4. if() { ... } スコープの末尾で wrt のデストラクタが呼び出され、二線シリアルバスの STOP を行う。

get_writer()

periph_wire::writer
get_writer(uint8_t addr)

I2C書き出しに用いるワーカーオブジェクトを取得します。

パラメータ解説
addr書き出し用のI2Cアドレス

ワーカーオブジェクト (writer)

<<演算子

operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)

int型,uint8_t型は8bitの転送を行います。データ並び順はビッグエンディアン形式(上位バイトが先に転送される)です。

()演算子

operator() (uint8_t val)
operator() (int val)

1バイト書き出す。

ワーカーオブジェクト (reader)

>>演算子

operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
operator >> (uint8_t(&c)[N]) // Nバイトの固定配列

それぞれのデータ型のサイズ分だけ読み出します。データ並び順はビッグエンディアン形式(先に転送されたほうが上位バイトに格納される)です。

()演算子

int operator() (bool b_stop = false)

//例
uint8_t dat[6];
if (auto&& rdr = Wire.get_reader(0x70)) {
  for(uint8_t& x : dat) {
    x = rdr();
  }
}

1バイト読み出します。エラーがある場合は-1を戻し、正常時は読み出したバイト値を戻します。

b_stoptrueにすると、その読み出しにおいてSTOPビットを発行します。

以下の例は、環境センサーパルの温湿度センサーSHTC3の計測例です。

Wire.begin();
// reset (may not necessary...)
if (auto&& wrt = Wire.get_writer(0x70)) {
	wrt << 0x80; // SHTC3_SOFT_RST_H
	wrt << 0x05; // SHTC3_SOFT_RST_L
}

delay(5); // wait some

// start read
if (auto&& wrt = Wire.get_writer(0x70)) {
	wrt << 0x60; // SHTC3_TRIG_H
	wrt << 0x9C; // SHTC3_TRIG_L
}

delay(10); // wait some

// read result
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(0x70, 6)) {
	rdr >> u16temp;
	rdr >> u8temp_csum;
	rdr >> u16humd;
	rdr >> u8humd_csum;
}

// checksum 0x31, init=0xFF
if (CRC8_u8CalcU16(u16temp, 0xff) != u8temp_csum) {
	Serial << format("{SHTC3 T CKSUM %x}", u8temp_csum); }
if (CRC8_u8CalcU16(u16humd, 0xff) != u8humd_csum) {
	Serial << format("{SHTC3 H CKSUM %x}", u8humd_csum); }

// calc temp/humid (degC x 100, % x 100)
int16_t i16Temp = (int16_t)(-4500 + ((17500 * int32_t(u16temp)) >> 16));
int16_t i16Humd = (int16_t)((int32_t(u16humd) * 10000) >> 16);

Serial << "temp=" << int(i16Temp)
	   << ",humid=" << int(i16Humd) << mwx::crlf;