8bitPICシリーズ⑧コンテキスト切り替え機能付きADC(ADCCC)モジュールの使い方

8BitPICシリーズ

概要

PICシリーズのマイコンには、古くからさまざまなバリエーションでADCモジュールが搭載されてきました。

今回紹介する PIC18F26/46/56Q71 シリーズに搭載されているADCは、以下のような特徴を備えており、非常に高機能なのが特長です。
特にコンテキスト切り替えブロックは、最大4つのアナログ入力をサンプリング、変換し、計算機能を自動的に実行できるようにし、各入力ごとにADCレジスタを再設定する必要をなくします。

PIC18F26/46/56Q71シリーズのの特徴

1. Capacitive Voltage Divider (CVD) サポート機能

  • プリチャージタイマ(Precharge timer)
  • 調整可能なサンプル&ホールド用コンデンサアレイ
  • ガードリングのデジタル出力ドライブ

2.自動リピート・シーケンス機能

  • CVD用の自動ダブルサンプル変換
  • 2セットの結果レジスタ(現在の結果 / 前の結果)
  • 自動変換トリガ
  • 内部リトリガ

3. チャネルグルーピング

  • 複数の入力チャネルを1つのチャネルとしてグループ化可能

4. 計算機能

  • 平均化およびローパスフィルタ
  • 基準電圧との比較
  • 2レベルしきい値比較
  • 選択可能な割り込み

5. 自動チャネルスキャンとコンテキスト切替

  • 最大4つのユニークな構成をサポート
  • 各構成がコンテキストとして保存される
  • スキャン中にしきい値割り込みで停止可能
  • 各構成に対して個別のしきい値割り込みが設定可能

6. その他の特徴

  • 変換完了時およびしきい値比較時に割り込み生成可能(Sleepからのウェイクアップに利用可)
  • ADCの電圧リファレンスは内部生成または外部供給をソフトウェアで選択可能

更新履歴

公開/変更日更新内容
2025.04.27初版公開

関連リンク

内部リンク

記事リンク
第1回8bitPICシリーズ①
PRGモジュールの使い方
8bitPICシリーズ①PRGモジュールの使い方 – ぴくおの電子工作的な何かWP
第2回8bitPICシリーズ②
PWMモジュールの使い方
8bitPICシリーズ②PWMモジュールの使い方 – ぴくおの電子工作的な何かWP
第3回8bitPICシリーズ③
SMTモジュールの使い方
8bitPICシリーズ③SMTモジュールの使い方 – ぴくおの電子工作的な何かWP
第4回8bitPICシリーズ④
Timerモジュールの使い方
8bitPICシリーズ④Timerモジュールの使い方 – ぴくおの電子工作的な何かWP
第5回8bitPICシリーズ⑤
Angular Timer モジュールの使い方
8bitPICシリーズ⑤Angular Timer モジュールの使い方 – ぴくおの電子工作的な何かWP
第6回8bitPICシリーズ⑥
CLB(Configurable Logic Block)モジュールの使い方
8bitPICシリーズ⑥CLB(Configurable Logic Block)モジュールの使い方 – ぴくおの電子工作的な何かWP
第7回8bitPICシリーズ⑦
オペアンプモジュールの使い方
8bitPICシリーズ⑦オペアンプモジュールの使い方 – ぴくおの電子工作的な何かWP
第8回8bitPICシリーズ⑧コンテキスト切り替え機能付きADCモジュールの使い方
第9回
第10回
内部リンク

外部リンク

サイトリンク先
PIC18F56Q71データシートPIC18F56Q71 | Microchip Technology
フィルタ&コンテキスト切り替えBasic Configurations of ADC with Computation and Context Switching
計算およびコンテキスト切り替えを使用したADC(DMAを使用)ADC with Computation and Context Switching Using DMA
計算およびコンテキスト切り替えモジュールを使用したADCによるチャネルシーケンシングとコンテキスト保存TB3267 – Channel Sequencing and Context Saving Using the ADC with Computation and Context Switching
差動型およびシングルエンド型ADCDifferential and Single-Ended ADC

ハードウェアブロック図

1.全体ブロック図

以下にADCモジュールの全体ブロック図を示します。

(fig.x)PIC18F26/46/56Q71 28/40/44/48-Pin, Low-Power, High-Performance Microcontroller with XLP Technology Data Sheet p.776より抜粋

レジスタ名ビット名機能初期値
ADCON0ONADC有効化
1 = 有効
0 = 無効
0
ADCON0CSADCクロック選択
1 = クロックはADCRC専用オシレーターから供給されます
0 = クロックはFOSCから供給され、ADCLKレジスタに従って分周されます
0
ADCON0GOADC変換ステータス
1 = ADC変換サイクルが進行中。このビットを設定するとADC変換サイクルが開始されます。ビットは、CONTビットによって決定されるようにハードウェアによってクリアされます
0 = ADC変換が完了している/進行中ではない
ADSTATSTATADCモジュール サイクル マルチステージステータスビット
7 = ADCモジュールは2回目の変換ステージにあります
6 = ADCモジュールは2回目の取得ステージにあります
5 = ADCモジュールは2回目のプリチャージステージにあります
4 = ADC計算は1回目と2回目のサンプル間で一時停止しています。 計算結果は不完全で、2回目のサンプルからのデータを待っています
3 = ADCモジュールは1回目の変換ステージにあります
2 = ADCモジュールは1回目の取得ステージにあります
1 = ADCモジュールは1回目のプリチャージステージにあります
0 = ADCモジュールは変換を行っていません
0
ADCLKCSADCクロック分周レジスタ
ADCクロック周波数 = FOSC / (2 * (n + 1))
0
ADREFNREFADC負の電圧リファレンス選択
1 = VREF- は外部の VREF に接続されます
0 = VREF- は AVSS に接続されます
0
ADREFPREFADC正の電圧リファレンス選択
3 = VREF+ は内部固定電圧リファレンス(FVR)モジュールに接続されます
2 = VREF+ は外部 VREF+ に接続されます
1 = 予約済み
0 = VREF+ は VDD に接続されます
0
ADACQACQADCサンプリング時間制御レジスタ
8191 = FOSC ×8191 もしくは ADCRC × 8191

2 = FOSC ×2 もしくは ADCRC × 2
1 = FOSC ×1 もしくは ADCRC × 1
0 = データ変換サイクルには含まれません
0
ADRESRESADCサンプル結果0
ADPREVPREV前回のADC結果
PSIS = 1 の場合:n は現在のADC変換開始時点の ADFLTR の値
PSIS = 0 の場合:n は現在のADC変換開始時点の ADRES の値
0
ADCPCPONチャージポンプ有効化
1 = 有効0= 無効
0
ADCPCPRDYチャージポンプ準備ステータス
1 = チャージポンプは準備完了
0 = チャージポンプは未準備(または開始されていない)
0

2.入力チャンネルブロック図

以下に入力チャンネルブロック図を示します。
ADPCHとADNCHは独立して入力チャネルを設定可能で、シングルエンド、もしくは差動モードで取得が可能です。

シングルエンドモードでは、VSSを基準に、ADPCHで指定されたピンに接続された電圧を計測します。
一方、差動モードでは、ADPCHとADNCHの2つのピン間の電圧差を計測します。

(fig.x)PIC18F26/46/56Q71 28/40/44/48-Pin, Low-Power, High-Performance Microcontroller with XLP Technology Data Sheet p.777より抜粋
レジスタ名ビット名機能初期値
ADCON0ICADC入力設定

1 = 差動入力
0 = シングルエンド入力
1
ADPCHPCHADC正の入力チャンネル選択0
ADNCHNCHADC負の入力チャンネル選択0

3.計算機能部ブロック図

以下に計算機能部ブロック図を示します。

(fig.x)PIC18F26/46/56Q71 28/40/44/48-Pin, Low-Power, High-Performance Microcontroller with XLP Technology Data Sheet p.789より抜粋

1.変換モード

モードMD機能要約
Basic0Basicモード(MD = ‘b000)では、加算やデジタルフィルタ機能などの計算機能は無効になりますが、しきい値エラー比較、ダブルサンプリング、連続モード、およびCVD機能は引き続き利用可能です。
Accumulate1Accumulateモード(MD = ‘b001)では、各変換結果がADACCレジスタに加算され、CRSビットの値で右シフトされた結果がADFLTRレジスタに格納されます。各サンプルごとにADCNTが増加し、ADFLTRに対してしきい値比較が行われ、条件により割り込みが発生します。
Average2Averageモード(MD = ‘b010)では、Accumulateモードと同様にADACCに加算しつつ、ADCNTでサンプル数をカウントします。CRSビットに応じて右シフトされた値がADFLTRに格納され、ADCNTがADRPT以上になると、平均値に対してしきい値比較が行われます(ADRPT = 2^CRSで正確な平均値)。
Burst Average3Burst Averageモード(MD = ‘b011)はAverageモードとほぼ同じですが、Continuous Samplingモードを使わなくても、CNTがRPTに達するまで自動的にサンプリングを繰り返します。これにより、短時間のバースト平均に対してしきい値比較が可能になります。
Low-pass Filter4Low-Pass Filterモード(MD = ‘b100)はAverageモードと同様に複数のサンプルを蓄積し、CNTがRPT以上になるとしきい値比較を行いますが、単純平均ではなくローパスフィルタ処理を行うことで高周波ノイズを低減します。CRSビットはフィルタのカットオフ周波数を決定します。

2.スレッシュ機能

ADCのしきい値比較は、ADUTHおよびADLTHレジスタと比較して、エラー値に基づくステータスビット(UTHR / LTHR)を設定します。TMDビットでしきい値判定のロジックを選択でき、条件には「常に割り込みなし」「下限未満」「下限以上」「範囲内」「範囲外」「上限以下」「上限超え」「常に割り込み」などがあります。条件を満たすとADCHxIF割り込みフラグがセットされます。

レジスタ名ビット名機能初期値
ADCON2PSISADC前回サンプル入力選択
ADCON2CRSアキュムレータ右シフトモード
ADCON2ACLRアキュムレータクリアビット
ADCON2MD変換モード
ADRPTRPTADCリピート設定レジスタ
ADCが一定回数トリガーされるとエラーしきい値をチェックする。計算モードがローパスフィルタ、バースト平均、または平均のときに使われる。
0
ADCNTCNTADCリピートカウンタレジスタ
ADCが一定回数トリガーされた後にしきい値チェックを行う。回数はRPTで設定され、計算モードがローパスフィルタ、バースト平均、または通常平均のときに使われる。
0
ADFLTRFLTRADCフィルタレジスタ
Accumulate、Average、および Burst Average モードでは、これは ACC を CRS ビット数だけ右シフトした値に等しいです。
LPF モードでは、これはローパスフィルタの出力となります。
注記:このマルチバイトレジスタの各バイトには、以下のレジスタ名でアクセスできます。
・ADFLTRH:上位バイト ADFLTR[15:8] にアクセス
・ADFLTRL:下位バイト ADFLTR[7:0] にアクセス
0
ADACCACCADCアキュムレータ - 符号付き2の補数形式
このレジスタは GO = 0 のときのみ書き込み可能です。
このマルチバイトレジスタの各バイトには、該当する場合、以下のレジスタ名でアクセスできます。
 なお、このレジスタのサイズはデバイスファミリによって異なる場合があります。
 実際に実装されているビット幅についてはレジスタサマリーを参照してください。
 ・ADACCU:上位バイト ADACC[17:16] にアクセス
 ・ADACCH:中位バイト ADACC[15:8] にアクセス
 ・ADACCL:下位バイト ADACC[7:0] にアクセス
ADSTPTSTPTADCしきい値セットポイント - 符号付き2の補数形式
注記:このマルチバイトレジスタの各バイトには、以下のレジスタ名でアクセスできます。
・ADSTPTH:上位バイト ADSTPT[15:8] にアクセス
・ADSTPTL:下位バイト ADSTPT[7:0] にアクセス
0
ADERRERRADCセットポイント誤差 - 符号付き2の補数形式
注記:このマルチバイトレジスタの各バイトには、以下のレジスタ名でアクセスできます。
・ADERRH:上位バイト ADERR[15:8] にアクセス
・ADERRL:下位バイト ADERR[7:0] にアクセス
x
ADLTHLTHADC下限しきい値 - 符号付き2の補数形式
注記:このマルチバイトレジスタの各バイトには、以下のレジスタ名でアクセスできます。
・ADLTHH:上位バイト ADLTH[15:8] にアクセス
・ADLTHL:下位バイト ADLTH[7:0] にアクセス
0
ADUTHUTHADC上限しきい値レジスタ
ADLTH と ADUTH は ADERR と比較され、UTHR および LTHR ビットが設定されます。
TMD ビットの設定に応じて、この比較結果により割り込みがトリガーされる場合があります
ADC上限しきい値 - 符号付き2の補数形式
注記:このマルチバイトレジスタの各バイトには、以下のレジスタ名でアクセスできます。
・ADUTHH:上位バイト ADUTH[15:8] にアクセス
・ADUTHL:下位バイト ADUTH[7:0] にアクセス。
0
ADCON3CALCADC誤差計算モード選択
5 = 平均/フィルタ後の値とセットポイントの比較
ADFLTR – ADSTPT
4 = フィルタ後の値の1次導関数(負方向)
ADPREV – ADFLTR
2 = 実測値と平均/フィルタ後の値の比較
DSEN = 0: ADRES – ADFLTR
DSEN = 1 :(ADRES – ADPREV) – ADFLTR
1 = 実測値とセットポイントの比較
DSEN = 0: ADRES – ADSTPT
DSEN = 1 :(ADRES – ADPREV) – ADSTPT
0 = 単一測定値の1次導関数、実際のCVD結果
ADRES – ADPREV
0
ADCON3TMDしきい値割り込みモード選択
7 = しきい値テスト結果に関係なく割り込みが発生
6 = ADERR > ADUTH の場合に割り込み
5 = ADERR ≤ ADUTH の場合に割り込み
4 = ADERR < ADLTH または ADERR > ADUTH の場合に割り込み
3 = ADERR > ADLTH かつ ADERR < ADUTH の場合に割り込み
2 = ADERR ≥ ADLTH の場合に割り込み
1 = ADERR < ADLTH の場合に割り込み
0 = 割り込みは発生しない
0
ADSTATAOVADCアキュムレータオーバーフロービット
1 = ADACC、ADFLTR、または ADERR レジスタがオーバーフローした
0 = ADACC、ADFLTR、ADERR レジスタはオーバーフローしていない
0
ADSTATUTHRADCモジュール 上限しきい値超過フラグ
1 = ADERR > ADUTH
0 = ADERR≤ ADUTH
0
ADSTATLTHRADCモジュール 下限しきい値未満フラグ
1 = ADERR < ADLTH
0 = ADERR ≥ ADLTH
0
ADSTATMATHADCモジュール計算ステータス
1 = DACC、ADFLTR、ADUTH、ADLTH レジスタおよび AOV ビットが更新中またはすでに更新されている
0 = 関連するレジスタ/ビットは、このビットが最後にクリアされてから変更されていない
0

4.サンプリング

Continuous Sampling Mode(連続サンプリングモード)

  • CONTビットをセットすると、ADACC更新後に自動で変換が再トリガされ、GOビットが維持されます。
  • ただし、SOI = 1のときは、しきい値割り込みが発生するとGOビットがクリアされ、変換が停止します。

Double Sample Conversion(ダブルサンプル変換)

  • DSENビットをセットすると、2回の変換後にしきい値誤差が計算されます。
  • CONT = 0では2回分のトリガが必要、CONT = 1では1回のトリガで自動実行。
  • 1回目の変換でMATHビットがセットされ、ADACCが更新されるがADERRやADCHnIFは発生しない。
  • 2回目の変換でADPREVとADRESが更新され、しきい値評価が行われる。
レジスタ名ビット名機能初期値
ADCON0CONTADC連続動作有効化
1 = 各変換トリガの完了後、GOが再トリガされます。ADCHIFが設定されるまで(SOIが設定されている場合)またはGOがクリアされるまで(SOIの値に関係なく)続きます
0 = 各変換トリガの完了後、ADCはクリアされます
0
ADCON3
SOIADC割り込み停止ビット
■CONT = 0
このビットは使用されません

■CONT = 1
1 = しきい値条件が満たされるとGOがクリアされます。それ以外の場合、変換は再トリガされます
0 = ハードウェアではGOはクリアされません。再トリガを停止するにはソフトウェアでクリアする必要があります
0
ADACTACTADC自動変換トリガソース選択レジスタ0

5.静電容量変換

ADCモジュールは、内部のサンプル&ホールド用コンデンサを基準として、各ADCチャネルで相対的な容量測定が可能です。これにより、静電容量式のタッチや近接センシングを実現できます。

レジスタ名ビット名機能初期値
ADCON1PPOLプリチャージ極性
1回目のプリチャージ段階における動作

■ADPRE = 0
このビットは効果を持たない

■ADPRE > 0

1 = 外部アナログI/OピンがVDDに接続され、内部ADサンプリングキャパシタ(CHOLD)がVSSに接続される
0 = 外部アナログI/OピンがVSSに接続され、内部ADサンプリングキャパシタ(CHOLD)がVDDに接続される
0
ADCON1IPENA/D反転プリチャージ有効化

■DSEN = 0
このビットは効果を持たない

■DSEN = 1
1 = 2回目の変換サイクルでは、プリチャージおよびガード信号が1回目のサイクルとは逆極性になる
0 = 両方の変換サイクルで、PPOLおよびGPOLで指定されたプリチャージとガードを使用する
0
ADCON1GPOLガードリング極性選択
1 = プリチャージ段階でADCガードリング出力がデジタルHighで開始される
0 = プリチャージ段階でADCガードリング出力がデジタルLowで開始される
0
ADCON1PCSCサンプルキャパシタのみプリチャージ
1 = プリチャージは内部サンプリングキャパシタのみに適用される
0 = プリチャージは内部サンプリングキャパシタと外部I/Oピンの両方に適用される
0
ADCON1DSEN2回の変換がペアとして処理されます。
1 = 選択された演算は2回目の変換の後に実行されます。
0 = 選択された演算は毎回の変換後に実行されます。
0
ADPREPREADCプリチャージ時間制御レジスタ

8191 = FOSC ×8191 もしくは ADCRC × 8191

2 = FOSC ×2 もしくは ADCRC × 2
1 = FOSC ×1 もしくは ADCRC × 1
0 = データ変換サイクルには含まれません
0
ADCAPCAPADC追加サンプルキャパシタ選択レジスタ
15 ~ 1 = 追加キャパシタンスの値(pF)
0 = 無効
0

6.コンテキスト切り替え

レジスタ名ビット名機能初期値
ADCON0CSENADCコンテキストスキャン有効化
1 = 自動コンテキストスキャンが有効
0 = 自動コンテキストスキャンが無効
0
ADCTXCTXSW ADCコンテキスト選択レジスタ
1 = スキャナの現在のコンテキスト番号は、CTXビットに表示されます。CTXビットは読み取り専用です。
0 = ユーザーの現在のコンテキスト番号は、CTXビットに表示されます。CTXビットは読み書き可能です。
0
ADCTXCTXチャネルコンテキスト選択
■CTXSW = 1
スキャナの現在のチャネルコンテキスト番号
■CTXSW = 0
ユーザーの現在のチャネルコンテキスト番号
0

7.スキャン入力

レジスタ名ビット名機能初期値
ADCSELxCHEN ADスキャン有効化ビット0
ADCSELxSSI割り込み時AD停止設定ビット0
ADCGxACGAADCチャネルグループ選択 ポートA0
ADCGxBCGBADCチャネルグループ選択 ポートB0
ADCGxCCGCADCチャネルグループ選択 ポートC0
ADCGxDCGDADCチャネルグループ選択 ポートD0
ADCGxECGEADCチャネルグループ選択 ポートE0

共通ソースコード

今回の記事すべてに共通するソースコードを示します。

#pragma config FEXTOSC = ECH     // External Oscillator Selection->EC (external clock) above 8 MHz
#pragma config RSTOSC = HFINTOSC_64MHZ     // Reset Oscillator Selection->HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

//CONFIG2
#pragma config CLKOUTEN = OFF     // Clock out Enable bit->CLKOUT function is disabled
#pragma config PR1WAY = ON     // PRLOCKED One-Way Set Enable bit->PRLOCKED bit can be cleared and set only once
#pragma config BBEN = OFF     // Boot Block enable bit->Boot block disabled
#pragma config CSWEN = ON     // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = ON     // Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor enabled
#pragma config FCMENP = ON     // Fail-Safe Clock Monitor - Primary XTAL Enable bit->Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failure.
#pragma config FCMENS = ON     // Fail-Safe Clock Monitor - Secondary XTAL Enable bit->Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on SOSC failure.

//CONFIG3
#pragma config MCLRE = EXTMCLR     // MCLR Enable bit->If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR 
#pragma config PWRTS = PWRT_OFF     // Power-up timer selection bits->PWRT is disabled
#pragma config MVECEN = OFF     // Multi-vector enable bit->Interrupt contoller does not use vector table to prioritze interrupts
#pragma config IVT1WAY = ON     // IVTLOCK bit One-way set enable bit->IVTLOCKED bit can be cleared and set only once
#pragma config LPBOREN = OFF     // Low Power BOR Enable bit->Low-Power BOR disabled
#pragma config BOREN = SBORDIS     // Brown-out Reset Enable bits->Brown-out Reset enabled , SBOREN bit is ignored

//CONFIG4
#pragma config BORV = VBOR_1P9     // Brown-out Reset Voltage Selection bits->Brown-out Reset Voltage (VBOR) set to 1.9V
#pragma config ZCD = OFF     // ZCD Disable bit->ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
#pragma config PPS1WAY = ON     // PPSLOCK bit One-Way Set Enable bit->PPSLOCKED bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
#pragma config STVREN = ON     // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset
#pragma config LVP = ON     // Low Voltage Programming Enable bit->Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored
#pragma config XINST = OFF     // Extended Instruction Set Enable bit->Extended Instruction Set and Indexed Addressing Mode disabled

//CONFIG5
#pragma config WDTCPS = WDTCPS_31     // WDT Period selection bits->Divider ratio 1:65536; software control of WDTPS
#pragma config WDTE = OFF     // WDT operating mode->WDT Disabled; SWDTEN is ignored

//CONFIG6
#pragma config WDTCWS = WDTCWS_7     // WDT Window Select bits->window always open (100%); software control; keyed access not required
#pragma config WDTCCS = SC     // WDT input clock selector->Software Control

//CONFIG7
#pragma config BBSIZE = BBSIZE_16384     // Boot Block Size Selection bits->Boot Block size is 16384 words

//CONFIG8
#pragma config SAFSZ = SAFSZ_NONE     // SAF Block Size Selection bits->NONE

//CONFIG9
#pragma config WRTB = OFF     // Boot Block Write Protection bit->Boot Block not Write protected
#pragma config WRTC = OFF     // Configuration Register Write Protection bit->Configuration registers not Write protected
#pragma config WRTD = OFF     // Data EEPROM Write Protection bit->Data EEPROM not Write protected
#pragma config WRTSAF = OFF     // SAF Write protection bit->SAF not Write Protected
#pragma config WRTAPP = OFF     // Application Block write protection bit->Application Block not write protected

//CONFIG10
#pragma config CPD = OFF     // Data EEPROM Code Protection bit->Data EEPROM code protection disabled

//CONFIG11
#pragma config CP = OFF     // PFM Code Protection bit->PFM code protection disabled


void Clock_Init(void)
{
    // Set the CLOCK CONTROL module to the options selected in the user interface.
    OSCCON1 = (0 << _OSCCON1_NDIV_POSN)   // NDIV 1
        | (6 << _OSCCON1_NOSC_POSN);  // NOSC HFINTOSC
    OSCCON3 = (0 << _OSCCON3_SOSCPWR_POSN)   // SOSCPWR Low power
        | (0 << _OSCCON3_CSWHOLD_POSN);  // CSWHOLD may proceed
    OSCEN = (0 << _OSCEN_EXTOEN_POSN)   // EXTOEN disabled
        | (0 << _OSCEN_HFOEN_POSN)   // HFOEN disabled
        | (0 << _OSCEN_MFOEN_POSN)   // MFOEN disabled
        | (0 << _OSCEN_LFOEN_POSN)   // LFOEN disabled
        | (0 << _OSCEN_SOSCEN_POSN)   // SOSCEN disabled
        | (0 << _OSCEN_ADOEN_POSN)   // ADOEN disabled
        | (0 << _OSCEN_PLLEN_POSN);  // PLLEN disabled
    OSCFRQ = (8 << _OSCFRQ_HFFRQ_POSN);  // HFFRQ 64_MHz
    OSCTUNE = (0 << _OSCTUNE_TUN_POSN);  // TUN 0x0
    ACTCON = (0 << _ACTCON_ACTEN_POSN)   // ACTEN disabled
        | (0 << _ACTCON_ACTUD_POSN);  // ACTUD enabled
    FSCMCON = (0 << _FSCMCON_FSCMFEV_POSN)   // FSCMFEV detected
        | (0 << _FSCMCON_FSCMFFI_POSN)   // FSCMFFI enabled
        | (0 << _FSCMCON_FSCMPEV_POSN)   // FSCMPEV detected
        | (0 << _FSCMCON_FSCMPFI_POSN)   // FSCMPFI enabled
        | (0 << _FSCMCON_FSCMSEV_POSN)   // FSCMSEV detected
        | (0 << _FSCMCON_FSCMSFI_POSN);  // FSCMSFI enabled
}

設定例1) シングルエンド変換

以下の設定でシングルエンド変換を行います。

ブロック図

設定値

項目
正リファレンス電源+VREF
負リファレンス電源-VREF
正入力AN2ピン,1V ± 1V/10kHz
負入力DAC2 , 32 = 0.625V相当
出力フォーマット右詰め
計算機能無し
変換トリガ無し
スキャン機能無し
コンテキスト切り替え無し
静電容量検出無し

ソースコード

int main(void)
{
    	INTERRUPT_GlobalInterruptDisable(); 
      Clock_Init();
    
	ANSELAbits.ANSELA1 = 1;	//OPA1OUT
	ANSELAbits.ANSELA2 = 1; //OPA1IN0+

    ADACT = (0 << _ADACT_ADACT_POSITION);	/* ADACT TMR1(3) */
    ADCLK = (1 << _ADCLK_ADCS_POSITION);	/* ADCS FOSC/64(31) */
    ADPCH = (2 << _ADPCH_PCH_POSITION);	/* PCH ANA1(1) */
    ADNCH = (59 << _ADNCH_ADNCH_POSITION);	/* ADNCH VSS(59) */
    ADACQL = (10 << _ADACQL_ADACQ_POSITION);	/* ADACQ 0x0(0) */
    ADACQH = (0 << _ADACQH_ADACQ_POSITION);	/* ADACQ 0x0(0) */

    ADCON0bits.ADCONT = 0;
    ADCON1 = 0x00;
    ADCON2 = 0x00;
    ADCON3 = 0x00;
    ADSTAT = 0x00;
    ADREF = 0x00;
    ADCSEL1 = 0x00;

    ADCON0 = (0 << _ADCON0_ADGO_POSITION)	/* ADGO stop(0) */
	|(0 << _ADCON0_ADIC_POSITION)	/* ADIC single ended mode(0) */
	|(1 << _ADCON0_FM_POSITION)	/* FM right justified(1) */
	|(0 << _ADCON0_ADCS_POSITION)	/* ADCS FOSC(0) */
	|(0 << _ADCON0_CSEN_POSITION)	/* CSEN disabled(0) */
	|(0 << _ADCON0_ADCONT_POSITION)	/* ADCONT disabled(0) */
	|(1 << _ADCON0_ADON_POSITION);	/* ADON enabled(1) */;

    while(1)
    {
	ADCON0bits.GO = 1;
	while (ADCON0bits.GO);
	
	Result[cnt ++] = (((signed int)ADRESH ) << 8)  + ADRESL;
	cnt &= 0x7f;
    }       
}

3.結果

リングバッファ(Result[])の内容をCSV形式で出力した結果を示します。正弦波が正しく計測できていることが確認できました。


設定例2) 差動入力変換

以下の設定で差動入力変換を行います。

ブロック図

設定値

項目
正リファレンス電源+VREF
負リファレンス電源-VREF
正入力AN2ピン,1V ± 1V/10kHz
負入力DAC2 , 32 = 0.625V相当
出力フォーマット右詰め
計算機能無し
変換トリガ無し
スキャン機能無し
コンテキスト切り替え無し
静電容量検出無し

ソースコード


unsigned char resH,resL;
signed int Result[64];
unsigned char cnt;

int16_t read_adc_result(uint8_t adresl, uint8_t adresh) ;
int main(void)
{
	INTERRUPT_GlobalInterruptDisable(); 
    Clock_Init();
    OSCENbits.LFOEN = 1u;
	
  ANSELAbits.ANSELA1 = 1;	//OPA1OUT
  ANSELAbits.ANSELA2 = 1; //OPA1IN0+
  ANSELAbits.ANSELA4 = 1; //OPA1IN1-
	
  ADCON0bits.ADON = 0;    
    ADACT = 0x00;	/* ADACT TMR1(3) */
    ADCLK = 0x01;	/* ADCS FOSC/64(31) */

    ADCTX = 0x0;
    ADPCH = 2 ;	/* PCH ANA1(1) */
    ADNCH = 57 ;	/* ADNCH DACOUT2(57) */
    ADACQL = 0x0A;	/* ADACQ 0x0(0) */
    ADACQH = 0x00;	/* ADACQ 0x0(0) */

    ADCON0 = 0x00u;
	ADCON0bits.CONT = 0u;
	ADCON0bits.CSEN = 0u;
	ADCON0bits.CS = 0u;
	ADCON0bits.FM = 3u;
	ADCON0bits.IC = 1u;
	ADCON0bits.ON = 1u;
    ADCON1 = 0x00u;
    ADCON2 = 0x00u;
    ADCON3 = 0x00u;
    ADREF = 0x00u;
    ADCSEL1 = 0x00u;
			
	
    DAC2CONbits.EN = 0;	
	DAC2DAT = 32;
	DAC2CONbits.EN = 1;		

    while(1)
    {
	ADCON0bits.GO = 1;
	while (ADCON0bits.GO);
	Result[cnt ++] = read_adc_result(ADRESL ,ADRESH );
	cnt &= 0x7f;
    }    
}


int16_t read_adc_result(uint8_t adresl, uint8_t adresh) {
    // 12ビットデータを合成
	int16_t adc_raw;
	
	if (ADCON0bits.IC == 0)
	{
	 if (ADCON0bits.FM0 == 0)
	 {
		adc_raw = ((int16_t)adresh << 4) | (adresl >> 4);
		}
	 else
	 {
		adc_raw = (((signed int)ADRESH ) << 8)  + ADRESL;
	 }
	}
	else
	{
	 if (ADCON0bits.FM == 0)
	 {
		adc_raw = ((int16_t)adresh << 4) | (adresl >> 4);
		// 12ビットの2の補数として符号拡張
		if (adc_raw & 0x0800) { // ビット11が1なら負数
			adc_raw |= 0xF000;  // 上位ビットを1で埋める
		}
	}
	else if (ADCON0bits.FM == 1)
	{
		adc_raw = (((signed int)ADRESH ) << 8)  + ADRESL;
		// 12ビットの2の補数として符号拡張
		if (adc_raw & 0x0800) { // ビット11が1なら負数
			adc_raw |= 0xF000;  // 上位ビットを1で埋める
		}
	}
	else if (ADCON0bits.FM == 2)
	{
		adc_raw = ((int16_t)adresh << 4) | (adresl >> 4);

		// 12ビットの2の補数として符号拡張
		if (adc_raw & 0x0800) { // ビット11が1なら負数
			adc_raw = -(adc_raw & 0x7FF);
		}

	}
	else
	{
		adc_raw = (((signed int)ADRESH ) << 8)  + ADRESL;
		if (adc_raw & 0x0800) { // ビット11が1なら負数
			adc_raw = -(adc_raw & 0x7FF);
		}
	}
  }

    return adc_raw;
}

結果

入力信号とDAC2出力との差分が取得できることが確認できました。


設定例3) シングルエンド入力/積算機能

ADCモジュールには、デジタルフィルタリング、平均化、しきい値比較などの後処理機能が備わっています。これらの計算結果に基づき、追加のサンプルを取得したり、変換を停止したり、割り込みを発生させたりするようにモジュールを設定できます。

Accumulateモード(MD=1)では、各AD変換後に変換結果がADACCレジスタに加算されます。
その後、ADACCをCRSビット分だけ右シフトした値がADFLTRレジスタにコピーされます。
フォーマットモードはADACCやADFLTRの右寄せには影響しません。
サンプルごとにADCNTがインクリメントされ、ADFLTR値に対してしきい値比較が行われ、条件を満たすとADCHxIF割り込みが発生します。

ここで右シフト処理を行う理由は、右シフトにより小さなノイズ成分が除去され、ADFLTRレジスタにはより滑らかなデータが積算されるようになります。またADFLTRレジスタは16bitのため飽和を防ぐといった事でも使われます。

今回はシングルエンド変換の結果を用い動作を確認します。

ブロック図

設定値

項目
正リファレンス電源+VREF
負リファレンス電源-VREF
正入力AN2ピン,3V
負入力GND
出力フォーマット右詰め
計算機能Accumulate
変換トリガ無し
スキャン機能無し
コンテキスト切り替え無し
静電容量検出無し

ソースコード

signed long Result[64];
signed int Result2[64];

unsigned char cnt;

int16_t read_adc_result(uint8_t adresl, uint8_t adresh) ;
int main(void)
{
    INTERRUPT_GlobalInterruptDisable(); 
    Clock_Init();
    OSCENbits.LFOEN = 1u;
	
	ANSELAbits.ANSELA1 = 1;	//OPA1OUT
	ANSELAbits.ANSELA2 = 1; //OPA1IN0+
	ANSELAbits.ANSELA4 = 1; //OPA1IN1-
	
	ADCON0bits.ADON = 0;    
    ADACT = 0x00;	/* ADACT TMR1(3) */
    ADCLK = 0x01;	/* ADCS FOSC/64(31) */

    ADCTX = 0x0;
    ADPCH = 2 ;	/* PCH ANA1(1) */
    ADNCH = 0 ;	/* ADNCH DACOUT2(57) */
    ADACQL = 0x0A;	/* ADACQ 0x0(0) */
    ADACQH = 0x00;	/* ADACQ 0x0(0) */

    ADCON0 = 0x00u;
	 ADCON0bits.CONT = 0u;
	 ADCON0bits.CSEN = 0u;
	 ADCON0bits.CS = 0u;
	 ADCON0bits.FM = 1u;
	 ADCON0bits.IC = 0u;
	 ADCON0bits.ON = 1u;
    ADCON1 = 0x00u;
    ADCON2 = 0x00u;
	 ADCON2bits.CRS = 2u;
	 ADCON2bits.MD = 1u;
    ADCON3 = 0x00u;
    ADREF = 0x00u;
    ADCSEL1 = 0x00u;
			
	
    DAC2CONbits.EN = 0;	
    DAC2DAT = 200;
    DAC2CONbits.EN = 1;		

    while(1)
    {
	 ADCON0bits.GO = 1;
	 while (ADCON0bits.GO);
	 Result[cnt] = ADACC;
	 Result2[cnt ++] = ADFLTR;
	 cnt &= 0x7f;
    }    
}

結果


記事についての注意点

本記事は慎重に内容を検討し正確さに努めておりますが、内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。記事内容をそのまま無断転載することはお断りいたします。


コメント

タイトルとURLをコピーしました