内臓A/Dコンバーターの使い方
R8C/Mxx は、サンプルホールド付き、10ビットA/Dコンバーターを内蔵しています。
変換時間も2.2マイクロ秒と高速で、最大6チャネルのアナログ入力をサポートしています。
今回は、このデバイスの基本的な使い方を説明します。
※低価格マイコンで、サンプルホールド付10ビットA/Dがあるのは珍しいと思います。
サポートクラス common/adc_io.hpp
R8C/C++ フレームワークでは、A/D 変換を簡単に扱う為、サポートクラスを提供しています。
このクラスを使う事で、簡単にアナログ電圧を変換する事が出来ます。
このクラスは、割り込みに対応していますが、今回は割り込みを使わない方法を示します。
割り込みを使えば、変換時間を有効に使う事が出来ますが、1つのアナログ入力に対して2.2マイクロ秒だと、20MHz で動作する R8C では、44サイクル分です。
このくらいのコストなら、割り込みで変換通知を受け取らなくても、そんなに大きなハンデとならないと思います。
変換を開始してから、何か簡単な処理を行い、変換結果を得るようにすれば、変換に掛かるコストを相殺出来ます。
多数のアナログ入力を連続して変換するような場合には、割り込みを使い連続して変換し、結果を格納すればパフォーマンスが上がります。
ハードウェアー(準備)

- 実験では、2個のボリュームをアナログ入力端子に接続します。
定義
// 電源電圧を10倍した整数を設定
// constexpr int16_t VCC = 50; ///< 5.0V (1.25)
constexpr int16_t VCC = 33; ///< 3.3V (0.825)
typedef device::adc_io<utils::null_task> ADC;
ADC adc_;
※電圧表示用に、マイコンの駆動電圧を設定します。(この例では3.3V)
※今回、割り込みを使わないので、割り込みから呼ばれる変換型には「utils::null_task」を選択しています。
開始
この例では、P1_0(CH0)、P1_1(CH1) をアナログ入力として使います。
// ADC の設定
{
utils::PORT_MAP(utils::port_map::P10::AN0);
utils::PORT_MAP(utils::port_map::P11::AN1);
adc_.start(ADC::CH_TYPE::CH0_CH1, ADC::CH_GROUP::AN0_AN1, true);
}
結果取得と表示
adc_.scan();
adc_.sync();
// 「%3.2:8y」は小数点以下 8 ビットの固定小数点を 3 桁、小数点以下 2 桁表示
// 5V の場合 1.25 倍して、小数点以下 8 ビットで、1023 で 5V 表示となる。
// 3.3V の場合 0.825 倍して、小数点以下 8 ビットで、1023 で 3.3V 表示となる。
{
auto v = adc_.get_value(0);
utils::format("(%5d) CH0: %3.2:8y[V], %d\n")
% nnn
% static_cast<uint16_t>(((v + 1) * VCC) / (1024 * 10 / 256))
% v;
}
{
auto v = adc_.get_value(1);
utils::format(" CH1: %3.2:8y[V], %d\n")
% static_cast<uint16_t>(((v + 1) * VCC) / (1024 * 10 / 256))
% v;
}
++nnn;
「scan()」で A/D 変換をスタートして、「sync()」で変換終了を待ちます。
void sync() const {
while(!get_state()) sleep_();
}
「sync()」関数の実装は上記のようになっているので、何か別の処理をしながら、変換が終了するまで待つ事も出来ます。
「utils::format」は、固定小数点表示をサポートしており、電圧の表示などに便利です。
※浮動小数点を使う事も出来ますが、オブジェクトが大きくなります。
上記の例では、設定した電源電圧のパラメーターを使い、変換された電圧をX.XXで表示します。
「%3.2:8y」は、format 独自の固定小数点フォームで、小数点以下8ビットとして整数を扱います。
- 5Vの場合、A/D 変換後のデータに1を加えて、1.25倍しています。
- 3.3Vの場合、A/D 返還後のデータを0.825倍しています。
ターミナル出力:
CH1: 1.61[V], 500
( 310) CH0: 2.28[V], 708
CH1: 1.61[V], 500
( 311) CH0: 2.28[V], 709
CH1: 1.61[V], 500
( 312) CH0: 2.28[V], 709
CH1: 1.61[V], 500
( 313) CH0: 2.28[V], 707
CH1: 1.62[V], 501
( 314) CH0: 2.28[V], 708
CH1: 1.61[V], 500
( 315) CH0: 2.28[V], 708
CH1: 1.61[V], 500
( 316) CH0: 2.28[V], 708
CH1: 1.61[V], 500
( 317) CH0: 2.28[V], 708
CH1: 1.61[V], 500
( 318) CH0: 2.28[V], 709
CH1: 1.61[V], 500
( 319) CH0: 2.29[V], 710
CH1: 1.61[V], 500
( 320) CH0: 2.28[V], 708
CH1: 1.61[V], 500
サーミスターテンプレートクラスを使った温度測定
サーミスターは、安価で、簡易的に温度を測定するには最適なデバイスです。
但し、直線性が悪く、補正が必要です。
R8C/C++ フレームワークでは、サーミスター用テンプレートクラスを用意してあり、非直線性を補正した温度を取得する事が出来ます。
※対数計算が含まれていて、浮動小数点を扱うので、実行バイナリーはそれなりに大きくなります。
定義
サーミスターは、品種により直線性が異なり、対数計算のパラメーターを選ぶ必要があります。
このテンプレートクラスでは、現在3つの品種を扱えるようにしてあります。
※他の品種を使いたい場合、パラーメーターを追加して下さい、ソースコードを観れば、比較的簡単に品種を増やす事が出来ると思います。
標準で用意されている品種:
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief サーミスタ型
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
enum class thermistor {
NT103_34G, ///< THB:3435, TR25:10K
NT103_41G, ///< THB:4126, TR25:10K
HX103_3380, ///< THB:3380, TR25:10K (25C to 50C)
};
3つのサーミスター型のうち適切な型を選択して、typedef します。
又、分圧抵抗(通常10キロオーム)を直列に接続し、サーミスターを電源のどちらかに接続します。
- VCC側、又は、GND側
- A/D 変換の分解能は10ビットで、0~1023の値が返るので、1023 (1024-1) を指定しています。
- 「TH_OUT」は AN0/P1_0(20) に接続します。
// サーミスタ定義:
// A/D: 10 bits (1023), HX103_3380, 分圧抵抗: 10K (10000) オーム、サーミスタ: VCC側
typedef chip::NTCTH<1023, chip::thermistor::HX103_3380, 10000, true> THMISTER;
THMISTER thmister_;
開始
サーミスターを利用する A/D 変換ポートに接続し、A/D 変換を開始します。
※この例では、P1_0 に接続しています。
// ADC の設定
{
utils::PORT_MAP(utils::port_map::P10::AN0);
adc_.start(ADC::CH_TYPE::CH0, ADC::CH_GROUP::AN0_AN1, true);
}
結果表示
A/D 変換された値をサーミスターテンプレートに入れて、補正された温度を取得します。
※温度は、float 型で返ります。
adc_.scan();
adc_.sync();
{
auto v = adc_.get_value(0);
utils::format("(%5d) CH0: %3.2:8y[V], %d\n")
% nnn
% static_cast<uint16_t>(((v + 1) * VCC) / (1024 * 10 / 256))
% v;
utils::format("温度: %5.2f [度]\n") % thmister_(v);
}
テンプレートクラスを使うと簡単に扱えます。
ターミナル出力:
Start R8C THERMISTOR sample
( 0) CH0: 2.53[V], 517
温度: 25.57 [度]
( 1) CH0: 2.53[V], 517
温度: 25.57 [度]
( 2) CH0: 2.53[V], 517
温度: 25.57 [度]
( 3) CH0: 2.52[V], 516
温度: 25.46 [度]
( 4) CH0: 2.52[V], 515
温度: 25.36 [度]
( 5) CH0: 2.51[V], 514
温度: 25.26 [度]
( 6) CH0: 2.53[V], 517
温度: 25.57 [度]
( 7) CH0: 2.56[V], 523
温度: 26.19 [度]
( 8) CH0: 2.56[V], 523
温度: 26.19 [度]
( 9) CH0: 2.55[V], 522
温度: 26.08 [度]
( 10) CH0: 2.55[V], 522
温度: 26.08 [度]
( 11) CH0: 2.57[V], 525
温度: 26.40 [度]
( 12) CH0: 2.58[V], 528
温度: 26.71 [度]
( 13) CH0: 2.57[V], 525
温度: 26.40 [度]
( 14) CH0: 2.57[V], 526
温度: 26.50 [度]
( 15) CH0: 2.57[V], 526
温度: 26.50 [度]
( 16) CH0: 2.58[V], 527
温度: 26.60 [度]
( 17) CH0: 2.59[V], 530
温度: 26.92 [度]
( 18) CH0: 2.59[V], 530
温度: 26.92 [度]
( 19) CH0: 2.60[V], 532
温度: 27.12 [度]
( 20) CH0: 2.58[V], 528
温度: 26.71 [度]
( 21) CH0: 2.60[V], 531
温度: 27.02 [度]
( 22) CH0: 2.60[V], 532
温度: 27.12 [度]
( 23) CH0: 2.58[V], 528
温度: 26.71 [度]
( 24) CH0: 2.57[V], 526
温度: 26.50 [度]
( 25) CH0: 2.57[V], 525
温度: 26.40 [度]
( 26) CH0: 2.56[V], 524
温度: 26.29 [度]
( 27) CH0: 2.55[V], 522
温度: 26.08 [度]
( 28) CH0: 2.55[V], 522
温度: 26.08 [度]
( 29) CH0: 2.55[V], 522
温度: 26.08 [度]
( 30) CH0: 2.55[V], 521
温度: 25.98 [度]
( 31) CH0: 2.54[V], 520
温度: 25.88 [度]
まとめ
A/D 変換の場合、アナログ電圧を扱うので、ノイズや、A/D 変換に係る色々な事象が発生し、実用的に利用するには、色々なノウハウがあります。
R8C/Mxx の場合、マイコンの電源と、A/D 変換で使われるリファレンス電圧が共通になっているので、マイコン側のノイズが変換結果に影響を与えます。
精密な変換を行いたい場合、色々な工夫が必要と思いますが、R8C/Mxx の内蔵 A/D 変換は、ノイズも少なく、かなり良く出来ています。
サンプルホールドがあり、変換時間が短く、分解能も10ビットあるので、応用次第で、色々なアプリケーションに活用できるものと思えます。
参考リンク
次の記事:
前の記事:
開発環境の構築など:
format テンプレートクラス: