-
Notifications
You must be signed in to change notification settings - Fork 0
ReadUART
最小フットプリントの、受信バッファ付き二線式準全二重UART通信ReadUART_Class
基本クラス。
Arduino互換APIの<HardwareSerial.h>
を代替する。
プロトコルは 8N1 専用。
送信方向は割込も計時器周辺機能もFIFOバッファも使用しないが、受信方向は割込を使用する。
従って全体割込禁止中でも、割込ハンドラの中からでもwrite
は使用できるが、readBytes
以外の受信動作は禁止される。
USART[n]
周辺機能に対して<api/HarfUART.h>
とは排他使用となる。
このクラスは複数のシリアルポートを同時並行使用する際の受信漏れを緩和する目的で使用される。 しかし割込を使うため高速高頻度通信には必ずしも適さない。(性能限界が低い)
reduceAVR は未対応
#include <ReadUART.h>
Settings_SerialR0A(ReadUART_BUFFSIZE);
#ifdef Serial
#undef Serial
#define Serial SerialR0A
#endif
void setup (void) {
Serial.begin(CONSOLE_BAUD); /* {build.console_baud} */
}
void loop (void) {
if (Serial.available()) Serial.write( Serial.read() );
}
送信方向はHarfUART
と同一の動作をする。すなわち 1文字分に限って全二重動作となる。
受信方向は受信割込を介して、指定量の緩衝バッファに蓄積される。
バッファ量指定は 1以上の任意値で与えることができ、2の冪乗である必要もない。省略はできない。
既定値はReadUART_BUFFSIZE
定数(一般に32
または64
)で与えられる。
割込禁止中の受信動作read
はできない。
行単位で着実に送信受信方向動作を切り替えるならreadBytes
を用いるハンドシェイク動作とするのが良い。
前述の用例よりこちらのほうが実用にはより適する。
ポーリングを行うため、全体割込禁止中でも動作する。
void setup (void) {
Serial.begin(CONSOLE_BAUD);
}
void loop (void) {
size_t length;
char buff[INTERNAL_SRAM_SIZE / 4]; // 適当な大きさの1行ぶんのバッファメモリ
length = Serial.readBytes(&buff, sizeof(buff), '\n'); // `\n` 受信で方向切替
if (length) Serial.write(&buff, length);
}
組込用途での UART利用はあらかたハンドシェイク動作なので全二重対応が必要な場面は少ない。
-
peek
、last
、find
メソッドが使用できる。 - 全体割込禁止中は受信動作
read
が行われない。(readBytes
は全体割り込み禁止中でも動作する) - 受信バッファはリング構造であるが、溢れた場合はその一周分を暗黙のうちに破棄する。(statusエラーは残さない)
- 割込許容上限を超える頻度での受信動作は、主動作を暗黙のうちに停止させる。
依存性:<avr/io.h>
<util/atomic.h>
<Portmux.h>
<peripheral.h>
<api/Print.h>
Settings_<インスタンス名>
宣言は選択中の MCUで使用可能なものだけが用意されている。
R
の付かない同名のHarfUART
インスタンス名とは排他使用となる。
端的には<peripheral.h>
で定義されるSerial[n][x]
をSerialR[n][x]
に変えたものが使用可能。
#include <ReadUART.h>
Settings_SerialR0A(ReadUART_BUFFSIZE);
Settings_SerialR1A(1024);
Settings_SerialR2A(1024);
// etc...
ただし、同一ポートグループ内では使用できるのは単一のインスタンスだけである。
Settings_SerialR0A(ReadUART_BUFFSIZE);
Settings_SerialR0B(ReadUART_BUFFSIZE); // ポートグループが重複するのでエラー
ソースコード全体ではただ一箇所でしか、同一インスタンス名は宣言できない。
異なる翻訳単位(ファイル)からはextern
でインポートする。
#include <ReadUART.h>
extern ReadUART_Class SerialR0A;
Serial[n]
エイリアスは通常、HarfUART
インタフェース名を指しているため、必要に応じて再定義しなければならない。
#ifdef Serial
#undef Serial
#define Serial SerialR0A
#endif
ポートグループはプライマリが
0
、以後追加ポート以降に1
2
... の識別子が付く。
PORTMUX の DEFAULT選択がA
、ALTERNATE_1がB
、以後C
D
... の接尾子が付く。
インスタンスが複数あっても同一周辺機能なら同時使用できないことに注意。(違うクラスであっても)
どの型番でどの周辺機能が使用できるかは [modernAVR 周辺機能比較一覧] を参照のこと。
UARTの使用を、任意のボーレート値で開始する。
自身のオブジェクトを返すので、メソッドチェーンを後続できる。
ボーレート値から実際に必要な設定値を計算してinitiate
を呼び出すため、
事前コンパイル済定数を与えないと除算ライブラリが結合されることに注意。
Serial.begin(CONSOLE_BAUD);
F_CPU
によって動作可能速度が定まるため、計算範囲外となる値では正常動作しない。
CPU主クロックは設定ボーレートの 8倍以上 8192倍未満でなければならない。
ただし限界付近ではマージンが不足するため安定しない。
特に受信方向は割込を経由するため、
HarfUART
よりも最大実用速度は低下する。
UARTの使用を、指定の定数ラベルで開始する。
自身のオブジェクトを返すので、メソッドチェーンを後続できる。
定数ラベルは<Portmux_private.h>
で事前計算され定義されている。
除算は使われない。
Serial.initiate(UART_115200);
/* etc */
Serial.initiate(UART_CONSOLE_BAUD);
F_CPU
によって動作可能速度は定まるため、計算範囲外となる定数ラベルは定義されない。
UART_CONSOLE_BAUD
は事前定義マクロCONSOLE_BAUD
を元に生成されるが、
OSC-ULP 動作時は最大 2400bps、1200bps、あるいは 300bps の設定で上書きされるだろう。
F_CPU
が 2400 未満では、Arduino IDE のシリアルモニター(下限300bps)とは通信できない。
UART装置の使用を停止し、専有していた外部端子を開放する。 受信割込も停止する。 RX線の内蔵プルアップも無効になる。
- 一般に、UART対向機器の電源が落ちている場合は TX線が Hi-Zか LOWになるだろう。
これを調べるには TX端子をデジタル入力許可に変えなければならない。
end
後はそれが可能な状態になる。
1キャラクタを出力する。 送信緩衝バッファが空いていなければ空くまで待つ。 常に1を返す。 全体割込が禁止されていても動作する。
指定のバッファから指定の量を書き出す。書けた量を返す。 全体割込が禁止されていても動作する。
受信バッファから1キャラクタを取り出して返す。 入力が空かフレームエラーがあれば -1 を返す。 全体割込が禁止されていると正しく動作しないため、受信キャラクタ落ちを経験するだろう。
指定の_buffer
に、最大_limit
文字数、
あるいは_terminate
指定キャラクタ出現までを取得する。取得されたキャラクタ数を返す。
_buffer
の最後に\0
は補完されないことに注意。
_terminate
指定キャラクタは取得内容に含まれる。しかし\0
は指定できない。
受信キャラクタが\0
であればそれは含まれる。
そしてBREAK と見做して受信待機を打ち切るだろう。
このメソッドが呼ばれると、少なくとも 20bit時間のあいだ通信線を監視して
IDLE 状態が続いたなら何も取得せずに終了し0
を返す。
つまりNOBLOCK動作であるから、必要に応じて繰り返し呼び出さなければならない。
逆に_buffer
に格納される最初の文字はその前に 約20bit長以上の IDLE 状態が検出されなければならない。
従って例えば シリアルGPSの NMEA出力は、概ね新たな行頭から採取されるだろう。
_swevent
が0
以外であるなら、それは事象システム EVSYS ストローブ指令と解釈され、
最初の受信キャラクタ検出の瞬間に以下の IOレジスタへ代入し、
任意の事象イベントを発火することが出来る。
tinyAVR-0/1 | megaAVR-0 | その他のmodernAVR |
---|---|---|
EVSYS_ASYNCSTROBE | EVSYS_STROBE | EVSYS_SWEVENTA |
各ビットが
EVSYS
チャネル番号[0-7]に対応。チャネル8番以上には対応していない。
発火イベントが割込を惹起する場合はそちらの実行が優先され、そして受信落ちを経験するだろう。 だが全体割込禁止中でもこのメソッドが機能することは留意されたい。
この機能は例えば 1PPS割込のない シリアルGPSで、秒タイミングを測るのに使える。
受信バッファに格納されているキャラクタ数を返す。
送信緩衝バッファが空いていれば(待たずにwrite可能なら)1を返す。 空いていなければ(前の送信実行中であれば)0を返す。 全体割込が禁止されていても動作する。
送信緩衝バッファが空でかつ送信完了になるのを待つ。 全体割込が禁止されていても動作する。
空ではない受信バッファに格納されている最初の文字を返す。
これは次にread
で読まれる文字である。
何も格納されていなければ -1 を返す。
最後に受信したUSARTn_DATAL
の値を返す。
一般にこれは空ではない受信バッファの最後尾にあるキャラクタに等しい。
空ではない受信バッファ内から指定キャラクタを探して見つかれば真を返す。
キャラクタ未指定時は'\n'
を探す。
走査中に受信バッファが溢れた場合の結果は信用できない。
指定キャラクタまでのバッファ文字列取得コピーは、readBytes
を使うと良い。
最後に更新されたUSARTn_DATAH
の値を返す。
print文とその派生メソッドは<api/Print.h>
を参照のこと。
....
この他の、特にタイムアウトを伴うストリーム読込系の機能は用意されていない。
Twitter(X): @askn37
BlueSky Social: @multix.jp
GitHub: https://github.com/askn37/
Product: https://askn37.github.io/
Copyright (c) 2022,2023 askn (K.Sato) multix.jp
Released under the MIT license
https://opensource.org/licenses/mit-license.php
https://www.oshwa.org/
multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)