やあみんな
カスタム PCB 上に NHS3152 が搭載されています。PCB は非常にシンプルで、MCU-Link Pro 用の SWD コネクタと、スクリーン印刷されたアンテナに接続するためのコネクタへのトレースがいくつか付いています。電力の安定性を確保するため、ピン 3 とピン 7 の両方に 2 つの 100nF コンデンサが並列に接続されています (合計 4 つのコンデンサ)。
抵抗測定に関して問題があります。抵抗測定用のチャネルが 2 つあります (チャネル 0 = ピン 0、1、チャネル 1 = ピン 4、5)。ボードがパッシブに実行されているとき (デバッガーから電源が供給されていないとき) に抵抗測定を実行すると、NFC スキャナー (Arduino Uno 用の Adafruit PN532 シールド) はデータを受信しません。ただし、NHS3152 がデバッガーから電力を受け取っている場合は、測定から正しいデータを受信します。
抵抗測定に関連するコードのセクションを無効にすると、NFC の内容を正常に読み取ることができるので、ADC が電力を消費しすぎているのではないかと思います。
これに関してご助力いただければ幸いです。
IDE: MCUXpresso v24.9.25
SDK: release_mra2_12_6_nhs3152
読み取り失敗時のスキャナーからの出力(パッシブ モードで実行中):
=================================================
タグが見つかりアクティブ化されました!データの読み取りを準備しています。
UIDの長さ: 7バイト
UID値: 0x04 0x8E 0xE6 0x00 0xA8 0x00 0x10
----------------------------------------
8~12ページからのデータの読み取り
8ページを読み取れませんでした
=================================================
タグが失われたか、通信に失敗しました。リセットしています...
=================================================
デバッガー経由でNHS3152に電源が投入されたときのスキャナーからの出力:
=================================================
タグが見つかりアクティブ化されました!データの読み取りを準備しています。
UIDの長さ: 7バイト
UID値: 0x04 0x8E 0xE6 0x00 0xA8 0x00 0x10
----------------------------------------
8~12ページからのデータの読み取り
ページ08: 6E 52 31 3A nR1:
ページ09: 34 2C 52 32 4,R2
ページ10: 3A 2D 31 FE :-1
ページ 11: 86 56 4D 3D VM=
ページ 12: 84 28 57 0C (W.
データの読み取りに成功しました。タグはまだ残っています。
----------------------------------------
メイン.c:
/*
* ジェームズ・ハロルド、2025年、サイオン
*
* このプログラムは2つの別々のアナログチャネルで抵抗を測定します
* 結果を NFC タグに書き込み、ワイヤレスで読み取ります。
*
*/
// 1. ライブラリのインポート
#include "board.h"
#include "ndeft2t/ndeft2t.h"
#include
#include "pmu_nss.h"
#include "gpio_nss.h"
#include
#include
#include
// 2. 定義
#define CHANNEL_0 0 // 容量性および抵抗性チャネル
#define CHANNEL_1 1 // 抵抗チャネル
#define NUM_CHANNELS 2 // 測定チャネルの総数
// 3. グローバル変数
// NDEFメッセージ作成用のバッファ(NFC用)
静的uint8_t g_ndeft2tInstanceBuffer[NDEFT2T_INSTANCE_SIZE] __attribute__ ((aligned (4)));
静的uint8_t g_nfcMessageBuffer[NFC_SHARED_MEM_BYTE_SIZE] __attribute__ ((aligned (4)));
// 各測定チャネルの結果を格納する配列
揮発性int32_t 測定抵抗[NUM_CHANNELS] = {0, 0};
// 4. NFCコールバック(ライブラリで必須だが未使用)
void NDEFT2T_FieldStatus_Cb (bool ステータス) { ( void )ステータス; }
void NDEFT2T_MsgAvailable_Cb ( void ) { /* 未使用 */ }
// 5. 関数プロトタイプ
voidセットアップ電力安定化( void );
voidセットアップ抵抗測定( intチャネル);
int32_t PerformAndCalculateResistance ( intチャネル);
void WriteMeasurementsToNFC (int32_t res1、int32_t res2);
void WriteHelloMessageToNFC ( void );
// 6. メインコード
int main ( void ) {
// ステップ1: 最小限のボードと電源のセットアップを実行する
ボード初期化();
SetupPowerStabilisation (); // NFCタグからのエネルギー収集のためには早めに実行する必要がある
// --- 使用するペリフェラルのクロックと電源を有効にする ---
Chip_Clock_Peripheral_EnableClock( CLOCK_PERIPHERAL_ADCDAC | CLOCK_PERIPHERAL_I2D );
Chip_SysCon_Peripheral_EnablePower( SYSCON_PERIPHERAL_POWER_ADCDAC | SYSCON_PERIPHERAL_POWER_I2D );
// 電源とクロックが安定するまでの小さな遅延
チップクロックシステムビジーウェイトus(100);
// --- 抵抗測定の初期化 ---
// ペリフェラルを初期化し、アナログピンを設定する
Chip_ADCDAC_Init(NSS_ADCDAC0);
Chip_I2D_Init(NSS_I2D);
// Configure チャネル0のアナログピンを設定する(ANA0_0、ANA0_1)
Chip_IOCON_SetPinConfig(NSS_IOCON、 IOCON_ANA0_0 、IOCON_FUNC_1);
Chip_IOCON_SetPinConfig(NSS_IOCON、 IOCON_ANA0_1 、IOCON_FUNC_1);
//チャネル1のアナログピン(ANA0_4、ANA0_5)を設定します
Chip_IOCON_SetPinConfig(NSS_IOCON、 IOCON_ANA0_4 、IOCON_FUNC_1);
Chip_IOCON_SetPinConfig(NSS_IOCON、 IOCON_ANA0_5 、IOCON_FUNC_1);
// ADCを狭い電圧範囲(1.0V)に設定します
Chip_ADCDAC_SetInputRangeADC(NSS_ADCDAC0、 ADCDAC_INPUTRANGE_NARROW );
// ステップ 2: NFC 通信を初期化する
Chip_NFC_Init(NSS_NFC);
NDEFT2T_Init();
// ステップ3: 抵抗測定を実行する
抵抗測定を設定します(CHANNEL_0);
測定抵抗[CHANNEL_0] = PerformAndCalculateResistance(CHANNEL_0);
抵抗測定を設定します(CHANNEL_1);
測定された抵抗[CHANNEL_1] = PerformAndCalculateResistance(CHANNEL_1);
// ステップ4: 測定値をNFCタグに書き込む
測定抵抗をNFCに書き込みます(測定抵抗[CHANNEL_0]、測定抵抗[CHANNEL_1])。
//HelloMessageをNFCに書き込みます();
// --- 使用後はペリフェラルの電源を切って電力を節約する ---
Chip_SysCon_Peripheral_DisablePower( SYSCON_PERIPHERAL_POWER_ADCDAC | SYSCON_PERIPHERAL_POWER_I2D );
Chip_Clock_Peripheral_DisableClock( CLOCK_PERIPHERAL_ADCDAC | CLOCK_PERIPHERAL_I2D );
// ステップ5: NFCペリフェラルの割り込みを待つ
(1) { {
__WFI();
}
return 0; // 決して到達してはならない
}
// 7. 関数宣言
/**
* @brief 特定のチャネルでの抵抗測定用にハードウェアを構成します。
* @param channel : 設定する測定チャネル(CHANNEL_0 または CHANNEL_1)
* @return 何も返さない
*/
voidセットアップ抵抗測定( intチャネル) {
ADCDAC_IO_T dac_pin;
I2D_INPUT_T i2d_ピン;
if (チャネル == CHANNEL_1) {
dac_pin = ADCDAC_IO_ANA0_4 ;
i2d_pin = I2D_INPUT_ANA0_5 ;
}
それ以外{
dac_pin = ADCDAC_IO_ANA0_0 ;
i2d_pin = I2D_INPUT_ANA0_1 ;
}
Chip_ADCDAC_SetMuxDAC(NSS_ADCDAC0、dac_pin);
Chip_ADCDAC_WriteOutputDAC(NSS_ADCDAC0, 0xFFF); // DAC出力電圧を下げるために0xFFFから0x800に変更しました
Chip_I2D_SetMuxInput(NSS_I2D、i2d_pin);
if (チャネル == CHANNEL_0) {
Chip_I2D_Setup(NSS_I2D, I2D_SINGLE_SHOT , I2D_SCALER_GAIN_100_1 , I2D_CONVERTER_GAIN_LOW , 10); // I2D変換周期を100から10に変更(省電力)
}
それ以外{
Chip_I2D_Setup(NSS_I2D, I2D_SINGLE_SHOT , I2D_SCALER_GAIN_100_1 , I2D_CONVERTER_GAIN_LOW , 10); // I2D変換周期を100から10に変更(省電力)
}
// 電圧と電流が安定するまでしばらく待ちます。
チップクロックシステムビジーウェイトms(1);
}
/**
* @brief 電力の安定性のためにコンデンサ バンクを有効にするために GPIO を初期化します。
* @return 何も返さない
* @note これはパッシブ操作にとって最も重要な初期化です。
*/
voidセットアップ電力安定化( void ) {
Chip_IOCON_Init(NSS_IOCON);
Chip_GPIO_Init(NSS_GPIO);
// --- フェーズ 1: プリチャージ ---
// 内部プルアップ抵抗を有効にしてピンを入力として設定します。
// これにより、電圧降下を引き起こすことなく、外部キャップをゆっくり充電できるようになります。
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_PIO0_3 , IOCON_FUNC_0 | IOCON_RMODE_PULLUP); // ピン3をGPIOとして設定し、プルアップを有効にする
Chip_GPIO_SetPinDIRInput(NSS_GPIO, 0, 3); // ピン3を入力として設定する
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_PIO0_7 , IOCON_FUNC_0 | IOCON_RMODE_PULLUP); // ピン7をGPIOとして設定し、プルアップを有効にする
Chip_GPIO_SetPinDIRInput(NSS_GPIO, 0, 7); // ピン7を入力として設定する
// コンデンサが充電されるまで少し待ちます。
Chip_Clock_System_BusyWait_ms(60); // 4つの時定数で約60ms(各ピンに200nFが接続されています)
// --- フェーズ2: エンゲージ ---
// キャップが充電されたので、安全に電源レールに接続CAN
// ピンを OUTPUT に設定し、HIGH に駆動します。
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_PIO0_3 , IOCON_FUNC_0 | IOCON_RMODE_INACT); // ピン3をGPIOとして設定し、プルアップを無効にします
Chip_GPIO_SetPinDIROutput(NSS_GPIO, 0, 3); // ピン3を出力として設定する
Chip_GPIO_SetPinOutHigh(NSS_GPIO, 0, 3); // ピン3をHighに設定してVDDレールに接続します
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_PIO0_7 , IOCON_FUNC_0 | IOCON_RMODE_INACT); // ピン7をGPIOとして設定し、プルアップを無効にします
Chip_GPIO_SetPinDIROutput(NSS_GPIO, 0, 7); // ピン7を出力として設定する
Chip_GPIO_SetPinOutHigh(NSS_GPIO, 0, 7); // ピン7をHighに設定してVDDレールに接続します
}
/**
* @brief 2 つの抵抗値を含む NDEF メッセージを作成し、メモリに書き込みます。
* @ param res1: 最初のチャネルからの生の抵抗値。
* @ param res2: 2 番目のチャネルからの生の抵抗値。
* @return 何も返さない
*/
void WriteMeasurementsToNFC (int32_t res1, int32_t res2) {
charペイロードテキスト[64];
NDEFT2T_CREATE_RECORD_INFO_Tレコード情報を作成します。
uint8_t ロケール[] = " en " ;
snprintf(payloadText, sizeof (payloadText), "R1: %ld,R2:% ld " , res1, res2);
NDEFT2T_CreateMessage(g_ndeft2tInstanceBuffer、g_nfcMessageBuffer、
NFC_SHARED_MEM_BYTE_SIZE、true);
createRecordInfo.shortRecord = 1 ;
createRecordInfo.pString = ロケール;
if (NDEFT2T_CreateTextRecord(g_ndeft2tInstanceBuffer, &createRecordInfo)) {
if (NDEFT2T_WriteRecordPayload(g_ndeft2tInstanceBuffer, (uint8_t*)payloadText,
strlen(ペイロードテキスト))) {
NDEFT2T_CommitRecord(g_ndeft2tInstanceBuffer);
}
}
NDEFT2T_CommitMessage(g_ndeft2tInstanceBuffer);
}
/**
* @brief シンプルな NDEF テキスト メッセージ「hello」を作成し、NFC メモリに書き込みます。
* @return 何も返さない
*/
void WriteHelloMessageToNFC ( void ) {
char payloadText[] = "バナナ" ;
NDEFT2T_CREATE_RECORD_INFO_Tレコード情報を作成します。
uint8_t ロケール[] = " en " ;
// 1. バッファ内に新しい NDEF メッセージの作成を開始します。
NDEFT2T_CreateMessage(g_ndeft2tInstanceBuffer、g_nfcMessageBuffer、
NFC_SHARED_MEM_BYTE_SIZE、true /* 最初のメッセージです */ );
// 2. 新しい NDEF テキスト レコードの情報を準備します。
createRecordInfo.shortRecord = 1 ;
createRecordInfo.pString = ロケール;
// 3. メッセージ内にテキスト レコード構造を作成します。
if (NDEFT2T_CreateTextRecord(g_ndeft2tInstanceBuffer, &createRecordInfo)) {
// 4. 実際の「hello」文字列をレコードのペイロードに書き込みます。
if (NDEFT2T_WriteRecordPayload(g_ndeft2tInstanceBuffer, (uint8_t*)payloadText,
strlen(ペイロードテキスト))) {
// 5. この特定のレコードを確定します。
NDEFT2T_CommitRecord(g_ndeft2tInstanceBuffer);
}
}
// 6.メッセージ全体を確定し、NFC ハードウェアで使用できるようにします。
NDEFT2T_CommitMessage(g_ndeft2tInstanceBuffer);
}
/**
* @brief ADC および I2D 変換を実行し、特定のチャネルの抵抗を計算します。
* @param channel : 測定する測定チャネル(CHANNEL_0 または CHANNEL_1)
* @return 生のスケーリングされた抵抗値、またはエラーが発生した場合は -1 (例: オープン サーキット)。
* @note 低電力の __WFE() を使用して変換を待機します。これはパッシブ モードに不可欠です。
*/
int32_t PerformAndCalculateResistance ( intチャネル) {
int32_t v_drive、v_sense、i2d_val、adc_diff、result;
ADCDAC_IO_Tドライブピンadc、センスピンadc;
/*
* 注意: ペリフェラルクロックと電源は main() で有効になっているものと想定されます。
* この関数が複数の場所から呼び出される場合は、有効/無効にすることができます
* 代わりにここに記載してください。このアプリケーションでは、main() で有効にする方が効率的です。
*/
if (チャネル == CHANNEL_1) {
ドライブピンadc = ADCDAC_IO_ANA0_4 ;
sense_pin_adc = ADCDAC_IO_ANA0_5 ;
}
それ以外{
ドライブピンadc = ADCDAC_IO_ANA0_0 ;
sense_pin_adc = ADCDAC_IO_ANA0_1 ;
}
// --- V_DRIVE ADC測定 ---
Chip_ADCDAC_SetMuxADC(NSS_ADCDAC0、ドライブピンadc);
Chip_ADCDAC_StartADC(NSS_ADCDAC0);
// 新しい低電力の方法: ADC 変換が完了するまでスリープします。
while (!(Chip_ADCDAC_ReadStatus(NSS_ADCDAC0) & ADCDAC_STATUS_ADC_DONE )) {
{ /* 待って */ }
}
v_drive = Chip_ADCDAC_GetValueADC(NSS_ADCDAC0);
// --- V_SENSE ADC測定 ---
Chip_ADCDAC_SetMuxADC(NSS_ADCDAC0、sense_pin_adc);
Chip_ADCDAC_StartADC(NSS_ADCDAC0);
// ADC 変換が完了するまでスリープします。
while (!(Chip_ADCDAC_ReadStatus(NSS_ADCDAC0) & ADCDAC_STATUS_ADC_DONE )) {
{ /* 待って */ }
}
v_sense = Chip_ADCDAC_GetValueADC(NSS_ADCDAC0);
// --- I2D測定 ---
Chip_I2D_Start(NSS_I2D);
// I2D 変換が完了するまでスリープします。
while (!(Chip_I2D_ReadStatus(NSS_I2D) & I2D_STATUS_CONVERSION_DONE )) {
{ /* wait */ } // イベント情報を待機 - ADC_DONE イベント情報で起動 --> __WFE() をビジー待機に置き換えました {}
}
i2d_val = Chip_I2D_GetValue(NSS_I2D);
/*
* 注意: 次の測定ではペリフェラルの電源はオンのままになります。
* main() の終了時に電源がオフになります。
*/
// --- 計算 ---
adc_diff = v_drive - v_sense;
(adc_diff < 1)の場合{
adc_diff = 1;
}
i2d_val > 0 の場合{
抵抗結果 = ((uint32_t)adc_diff * 10000) / i2d_val;
}
それ以外{
resistance_result = -1; // 断線またはエラーを示します
}
resistance_resultを返します。
}
ntag2xx_read.ino:
ご参考までに。
ボードがパッシブに動作している場合、ADC の動作に十分な電力が安定しない可能性があります。