OY が 2026年03月04日19時10分52秒 に編集
初版
タイトルの変更
STM32C011F4P6でNFCタグを読む(M5Stack Unit RFID2)
タグの変更
CubeIDE
CubeMX
Nucleo開発ボード
STM32
秋月電子
スイッチサイエンス
メイン画像の変更
記事種類の変更
セットアップや使用方法
ライセンスの変更
(CC0 1+) Creative Commons Public Domain Dedication version 1.0 or later
本文の変更
# はじめに [前回「STM32C011F4P6のLチカ(ST-LINK/V2, Nucleo開発ボードC031C6)」](https://elchika.com/article/78beeef0-7286-48ef-b663-8d8a5b7dc1e3/) の続きです。 今回は、STM32C011F4P6とM5Stack Unit RFID2を使って NTAG215の読み取り行います。 また電子工作初心者ですので、誤ったことを記載している可能性があります。 ご了承ください。 ## ブロック図  ## 部品, 備品類 ### 部品 AE-STM32C011F4P6-DIP(秋月電子キット) Nucleo Board STM32C031C6 ブレッドボード(BB-801を使っています) ジャンパーワイヤー オス-オス ジャンパーワイヤー オス-メス ピンヘッダ 2pcs USB A-マイクロB(2.0) (Nucleoボード接続用) M5Stack用WS1850S搭載 RFID 2ユニット, 型番:M5STACK-U031-B(スイッチサイエンス) NTAG215(AmazonのYFFSFDC NFCタグ NTAG215 30枚) ### 備品, ソフト パソコン(Windows11を使いました) はんだごて、はんだ STM32CubeMX STM32CubeIDE NFC Tools(iPhone版を使いました) # 準備 ## Nucleoボードのはんだづけ ジャンパワイヤー接続用のピンヘッダをはんだづけします。 1.(図の左上)UART通信用のTX, RXにピンヘッダをつけます。 2.(図の右上)JP2のジャンパーピンを外し、TX, RXにピンヘッダーを挿入します。 3.(図の中央左)小型のブレッドボードで固定し、基板を裏返します。 4.(図の中央右)TX, RXをはんだ付けします。 5.(図の左下)ブレッドボードを外したらはんだ付け完了です。  基板裏面のSB23ジャンパーチップを外していない場合、 [前回](https://elchika.com/article/78beeef0-7286-48ef-b663-8d8a5b7dc1e3/#h_Nucleo-64%E9%96%8B%E7%99%BA%E3%83%9C%E3%83%BC%E3%83%89%20ST-LINK%2FV2-1%E3%81%AE%E6%BA%96%E5%82%99) を確認して外してください。 ## NTAGの書き込み (NFC Tools) iPhoneでの操作です。 「書く」→「レコードを追加」→「テキスト」→  「001」を入力 →「✓」→「書き込み/10バイト」→「スキャンの準備ができました」 → スマートフォンにNTAG215を近づけて書き込み  必須ではありませんが余裕があれば、 同様に残り2枚のNTAGへ「002」, 「003」と書き込みます。 書き込んだNTAGは、「読む」をタップしてスキャンすることで、書き込んだ数字を確認できます。 ## Eclipse Terminalのインストール (STM32CubeIDEのシリアルモニター) STM32CubeIDEを起動。 上部メニューの「help」→「Eclipse Marketplace」→「find」に下記を入力し「enter」→「install」 https://marketplace.eclipse.org/content/tm-terminal  「confirm」→「finish」  「restart now」IDEが再起動する  STM32CubeIDE 上部メニューの「Window」 → 「Show View」 → 「Other」 検索窓に「terminal」と入力。 →「terminal」を選択後 →「open」  IDE右下にTerminalが表示  Terminal内のメニューより、「Open a Terminal」アイコン → 表示ウインドウの「Choose terminal:Serial Terminal」を選択。 「Serial port」よりデバッガのCOM番号を選択を選択してください。 「OK」クリックでデバッガの情報がTerminalへ表示可能となります。  Windows11でのCOM番号の調べ方は下記です。 「Windowsスタートボタン」を右クリック → 「デバイスマネージャー」→ 「ポート」のツリーを展開、デバッガのCOM番号をチェックしてください。 今回はCOM4です。  # 初期設定とプログラムのビルド ## ピン設定等の初期設定、コード生成 STM32CubeMXを起動します。 File → New Project をクリック。  ウインドウが表示されますので使用するマイコンを「Commercial Part Number」に入力します。(今回はSTM32C011F4P6) MCUs/MCUs Listから選択 → Start Project をクリック。  ピンの設定画面が表示されますので、ピン設定を行います。 PB7:I2C1_SCL PC14:I2C1_SDA PA0:USART1_TX PA1:USART1_RX  左メニューの「Connectivity」→「I2C1」→Modeを「I2C」へ変更します。  左メニューの「Connectivity」→「USART1」→Modeを「Asynchronous」へ変更します。  「Project Manager」タブを押し、 「Project Name」にファイル名を記入 「Project Location」にて保存場所を選択 「Toolchain /IDE」をSTM32CubeIDEを選択 「GENERATE CODE」を押し、コード生成 ※プロジェクトネームに"()"を使うと、ビルド時にエラーが発生するため使わないでください。 ※プロジェクトロケーションは「CubeMX」直下としてください。 「CubeMX\プロジェクトネーム」とした場合、CubeIDEでエラーが発生します。  ※画像は前回のものです。 コード生成後のウィンドウで、「Open Project」をクリックすると 自動でSTM32CubeIDEが起動し、インポートしてくれます。  ※画像は前回のものです。 ## コード入力、ビルド STMCubeIDEのインポートしたプロジェクト内「Core」 → 「Src」 → 「main.c」にコードを記入します。 コードは下記範囲内にコピペしてください。 /* USER CODE BEGIN Header */ コードのコピペ /* USER CODE END 3 */ ```C:NTAG215 テキスト(3桁数字) 読み取り /* USER CODE BEGIN Header */ /* * STM32 Port of M5Stack RFID2 / MFRC522_I2C functionality * * This code is released under the Creative Commons Public Domain Dedication * version 1.0 or later (CC0 1+). * To the extent possible under law, the author has waived all copyright * and related or neighboring rights to this work. * You may copy, modify, distribute and perform the work, even for commercial * purposes, all without asking permission. * * ------------------------------------------------------------------------- * Third-party components and licenses * ------------------------------------------------------------------------- * * MFRC522_I2C Library (arozcan) * - Public Domain * - https://github.com/arozcan/MFRC522-I2C-Library * * M5Unified (M5Stack) * - MIT License * - Copyright (c) M5Stack * - https://github.com/m5stack/M5Unified * * M5Stack Unit RFID / RFID2 documentation * - No explicit license noted in documentation * - Uses official M5Stack libraries (MIT License) * - https://docs.m5stack.com/ja/arduino/projects/unit/unit_rfid * * MIT License portions are used in accordance with their terms. * */ /** ****************************************************************************** * @file : main.c * @brief : NTAG215 テキスト(3桁数字) 読み取り * STM32C011F4P6 + M5Stack RFID2 Unit (WS1850S) * * 配線: * RFID2 SCL → PB7 (I2C1_SCL) * RFID2 SDA → PC14 (I2C1_SDA) * RFID2 VCC → 3.3V / GND → GND * ST-LINK → PA0(USART1_TX) / PA1(USART1_RX) ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* stdio.h / string.h 不使用 */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ typedef enum { MFRC_OK = 0, MFRC_ERROR = 1, MFRC_TIMEOUT = 2 } MFRC_Status; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* I2C アドレス (7bit=0x28 → HAL用8bit) */ #define RFID2_ADDR (0x28 << 1) /* ---- WS1850S (MFRC522互換) レジスタ ---- */ #define REG_CommandReg 0x01 #define REG_ComIrqReg 0x04 #define REG_ErrorReg 0x06 #define REG_FIFODataReg 0x09 #define REG_FIFOLevelReg 0x0A #define REG_BitFramingReg 0x0D #define REG_CollReg 0x0E #define REG_ModeReg 0x11 #define REG_TxControlReg 0x14 #define REG_TxASKReg 0x15 #define REG_RFCfgReg 0x26 #define REG_CRCResultRegH 0x21 #define REG_CRCResultRegL 0x22 #define REG_TModeReg 0x2A #define REG_TPrescalerReg 0x2B #define REG_TReloadRegH 0x2C #define REG_TReloadRegL 0x2D #define REG_VersionReg 0x37 /* ---- コマンド ---- */ #define CMD_Idle 0x00 #define CMD_CalcCRC 0x03 #define CMD_Transceive 0x0C #define CMD_SoftReset 0x0F /* ---- NFC コマンド ---- */ #define PICC_REQA 0x26 #define PICC_CT 0x88 /* Cascade Tag (7バイトUID用) */ #define PICC_SEL_CL1 0x93 /* Cascade Level 1 */ #define PICC_SEL_CL2 0x95 /* Cascade Level 2 (NTAG215必須) */ #define PICC_HLTA 0x50 #define NTAG_READ 0x30 /* ErrorReg マスク * CollErr(bit3)はAntiColl時に正常で立つため除外 * bit0=ProtocolErr / bit1=ParityErr / bit4=BufferOvfl のみ判定 */ #define ERR_MASK_STRICT 0x13 #define ERR_MASK_ANTICOLL 0x13 /* HAL_Delay 固定待機時間 (ms) * IRQポーリング廃止・待機中はI2C通信なし → WS1850SがNFCに専念 */ #define WAIT_MS_REQA 15u #define WAIT_MS_ANTICOLL 25u #define WAIT_MS_SELECT 30u #define WAIT_MS_READ 30u #define WAIT_MS_CRC 5u /* デバッグ出力切り替え * 0 = 本番モード: 結果のみ出力 (STM32C011F4P6 FLASH節約) * 1 = デバッグモード: v9相当の詳細ログ出力 */ #define RFID_DEBUG 0 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* デバッグ出力マクロ * RFID_DEBUG=0 のとき空文に展開されFLASHを消費しない */ #if RFID_DEBUG #define DBG_STR(s) uart_str(s) #define DBG_HEX8(v) uart_hex8(v) #define DBG_CRLF() uart_crlf() #else #define DBG_STR(s) ((void)0) #define DBG_HEX8(v) ((void)0) #define DBG_CRLF() ((void)0) #endif /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ I2C_HandleTypeDef hi2c1; UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ static void uart_str(const char *s); static void uart_hex8(uint8_t v); static void uart_crlf(void); static void mfrc_write(uint8_t reg, uint8_t val); static uint8_t mfrc_read(uint8_t reg); static void mfrc_read_burst(uint8_t reg, uint8_t *buf, uint8_t len); static void mfrc_set_bits(uint8_t reg, uint8_t mask); static void mfrc_clear_bits(uint8_t reg, uint8_t mask); static void mfrc_fifo_flush(void); static void mfrc_init(void); static MFRC_Status mfrc_transceive(uint8_t *tx, uint8_t txLen, uint8_t *rx, uint8_t *rxLen, uint8_t errMask, uint32_t waitMs); static MFRC_Status mfrc_calc_crc(uint8_t *data, uint8_t len, uint8_t *crcLow, uint8_t *crcHigh); static MFRC_Status ntag_request(void); static MFRC_Status ntag_select_7byte(uint8_t *uid7); static MFRC_Status ntag_read_page(uint8_t page, uint8_t *data16); static uint8_t extract_3digit(uint8_t *raw, uint8_t len, char *out3); static void rfid_task(void); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* ================================================================ * UARTユーティリティ (stdio.h不使用) * ================================================================ */ static void uart_str(const char *s) { while (*s) HAL_UART_Transmit(&huart1, (uint8_t *)s++, 1, 100); } static void uart_hex8(uint8_t v) { const char h[] = "0123456789ABCDEF"; uint8_t buf[2]; buf[0] = (uint8_t)h[(v >> 4) & 0x0F]; buf[1] = (uint8_t)h[v & 0x0F]; HAL_UART_Transmit(&huart1, buf, 2, 100); } static void uart_crlf(void) { uart_str("\r\n"); } /* ================================================================ * WS1850S I2Cドライバ * ================================================================ */ static void mfrc_write(uint8_t reg, uint8_t val) { uint8_t buf[2] = { reg, val }; HAL_I2C_Master_Transmit(&hi2c1, RFID2_ADDR, buf, 2, 100); } static uint8_t mfrc_read(uint8_t reg) { uint8_t val = 0; HAL_I2C_Master_Transmit(&hi2c1, RFID2_ADDR, ®, 1, 100); HAL_I2C_Master_Receive (&hi2c1, RFID2_ADDR, &val, 1, 100); return val; } static void mfrc_read_burst(uint8_t reg, uint8_t *buf, uint8_t len) { HAL_I2C_Master_Transmit(&hi2c1, RFID2_ADDR, ®, 1, 100); HAL_I2C_Master_Receive (&hi2c1, RFID2_ADDR, buf, len, 100); } static void mfrc_set_bits(uint8_t reg, uint8_t mask) { mfrc_write(reg, mfrc_read(reg) | mask); } static void mfrc_clear_bits(uint8_t reg, uint8_t mask) { mfrc_write(reg, mfrc_read(reg) & ~mask); } /* FIFOを確実にクリアする */ static void mfrc_fifo_flush(void) { mfrc_write(REG_FIFOLevelReg, 0x80); HAL_Delay(1); } static void mfrc_init(void) { mfrc_write(REG_CommandReg, CMD_SoftReset); HAL_Delay(100); mfrc_write(REG_TModeReg, 0x80); mfrc_write(REG_TPrescalerReg, 0xA9); mfrc_write(REG_TReloadRegH, 0x03); mfrc_write(REG_TReloadRegL, 0xE8); mfrc_write(REG_TxASKReg, 0x40); mfrc_write(REG_ModeReg, 0x3D); mfrc_set_bits(REG_RFCfgReg, 0x70); /* アンテナゲイン最大 */ mfrc_set_bits(REG_TxControlReg, 0x03); /* アンテナON */ mfrc_write(REG_BitFramingReg, 0x00); /* BitFraming初期化 */ } /* ================================================================ * mfrc_transceive() * 【重要】送信シーケンスの正しい順序 : * ① CommandReg = CMD_Transceive (先にコマンドをセット) * ② BitFramingReg = 0x80 (後からStartSendをセット) * この順序でないとWS1850SがFIFO内容を正しく送信しない * ================================================================ */ static MFRC_Status mfrc_transceive(uint8_t *tx, uint8_t txLen, uint8_t *rx, uint8_t *rxLen, uint8_t errMask, uint32_t waitMs) { uint8_t i, n, err, irq; mfrc_fifo_flush(); mfrc_write(REG_ComIrqReg, 0x7F); mfrc_write(REG_CommandReg, CMD_Idle); mfrc_write(REG_BitFramingReg, 0x00); for (i = 0; i < txLen; i++) mfrc_write(REG_FIFODataReg, tx[i]); mfrc_write(REG_CommandReg, CMD_Transceive); /* ①コマンド先 */ mfrc_write(REG_BitFramingReg, 0x80); /* ②StartSend後 */ HAL_Delay(waitMs); mfrc_write(REG_BitFramingReg, 0x00); irq = mfrc_read(REG_ComIrqReg); err = mfrc_read(REG_ErrorReg); n = mfrc_read(REG_FIFOLevelReg); DBG_STR(" I=0x"); DBG_HEX8(irq); DBG_STR(" E=0x"); DBG_HEX8(err); DBG_STR(" F="); DBG_HEX8(n); DBG_CRLF(); if (err & errMask) return MFRC_ERROR; if (n == 0) return MFRC_TIMEOUT; if (rx && rxLen) { uint8_t lim = (*rxLen < n) ? *rxLen : n; mfrc_read_burst(REG_FIFODataReg, rx, lim); *rxLen = lim; DBG_STR(" RX["); DBG_HEX8(lim); DBG_STR("]:"); for (i = 0; i < lim; i++) { DBG_STR(" "); DBG_HEX8(rx[i]); } DBG_CRLF(); } return MFRC_OK; } /* ================================================================ * mfrc_calc_crc() : ハードウェアCRC_A計算 * ================================================================ */ static MFRC_Status mfrc_calc_crc(uint8_t *data, uint8_t len, uint8_t *crcLow, uint8_t *crcHigh) { uint8_t i; mfrc_write(REG_CommandReg, CMD_Idle); mfrc_write(REG_ComIrqReg, 0x04); mfrc_fifo_flush(); for (i = 0; i < len; i++) mfrc_write(REG_FIFODataReg, data[i]); mfrc_write(REG_CommandReg, CMD_CalcCRC); HAL_Delay(WAIT_MS_CRC); mfrc_write(REG_CommandReg, CMD_Idle); if (!(mfrc_read(REG_ComIrqReg) & 0x04)) return MFRC_TIMEOUT; *crcLow = mfrc_read(REG_CRCResultRegL); *crcHigh = mfrc_read(REG_CRCResultRegH); return MFRC_OK; } /* ================================================================ * ntag_request() : REQA 7bit送信 (専用実装) * 【重要】送信シーケンスの正しい順序: * ① CommandReg = CMD_Transceive * ② BitFramingReg = 0x87 (StartSend=bit7 + TxLastBits=7) * 送信後 BitFramingReg を必ず 0x00 にリセットする * * NTAG215のATQA正常値: 44 00 * ================================================================ */ static MFRC_Status ntag_request(void) { uint8_t cmd = PICC_REQA; uint8_t rx[2]; uint8_t n, err; mfrc_fifo_flush(); mfrc_write(REG_ComIrqReg, 0x7F); mfrc_write(REG_CommandReg, CMD_Idle); mfrc_write(REG_BitFramingReg, 0x00); mfrc_write(REG_FIFODataReg, cmd); mfrc_write(REG_CommandReg, CMD_Transceive); /* ①コマンド先 */ mfrc_write(REG_BitFramingReg, 0x87); /* ②StartSend+7bit後 */ HAL_Delay(WAIT_MS_REQA); mfrc_write(REG_BitFramingReg, 0x00); /* 必ずリセット */ err = mfrc_read(REG_ErrorReg); n = mfrc_read(REG_FIFOLevelReg); if (err & ERR_MASK_ANTICOLL) return MFRC_ERROR; if (n == 0) return MFRC_TIMEOUT; /* ATQAを読み捨て (カード存在確認のみ) */ mfrc_read_burst(REG_FIFODataReg, rx, (n > 2) ? 2 : n); return MFRC_OK; } /* ================================================================ * ntag_select_7byte() * ISO14443A Cascade Level 1+2 でNTAG215の7バイトUIDを取得 * * Cascade Level 1: * AntiColl (93 20) → rx=[CT(0x88) uid0 uid1 uid2 BCC] * Select (93 70 CT uid0 uid1 uid2 BCC CRC_L CRC_H) → SAK=0x04 * * Cascade Level 2: * AntiColl (95 20) → rx=[uid3 uid4 uid5 uid6 BCC] * Select (95 70 uid3 uid4 uid5 uid6 BCC CRC_L CRC_H) → SAK=0x00 * ================================================================ */ static MFRC_Status ntag_select_7byte(uint8_t *uid7) { uint8_t rx[5]; uint8_t rxLen; uint8_t tx[9]; uint8_t bcc; uint8_t crcL, crcH; MFRC_Status st; /* ---- Cascade Level 1 ---- */ mfrc_clear_bits(REG_CollReg, 0x80); /* ValuesAfterColl クリア */ /* CL1 AntiColl */ DBG_STR("CL1AC"); tx[0] = PICC_SEL_CL1; tx[1] = 0x20; rxLen = sizeof(rx); st = mfrc_transceive(tx, 2, rx, &rxLen, ERR_MASK_ANTICOLL, WAIT_MS_ANTICOLL); if (st != MFRC_OK || rxLen < 5 || rx[0] != PICC_CT) return MFRC_ERROR; bcc = rx[0] ^ rx[1] ^ rx[2] ^ rx[3]; /* BCC再計算 */ /* CL1 Select */ DBG_STR("CL1SEL"); tx[0] = PICC_SEL_CL1; tx[1] = 0x70; tx[2] = rx[0]; tx[3] = rx[1]; tx[4] = rx[2]; tx[5] = rx[3]; tx[6] = bcc; if (mfrc_calc_crc(tx, 7, &crcL, &crcH) != MFRC_OK) return MFRC_ERROR; tx[7] = crcL; tx[8] = crcH; rxLen = 3; st = mfrc_transceive(tx, 9, rx, &rxLen, ERR_MASK_STRICT, WAIT_MS_SELECT); if (st != MFRC_OK) return MFRC_ERROR; /* SAK=0x04 → Level2へ続く */ uid7[0] = tx[3]; uid7[1] = tx[4]; uid7[2] = tx[5]; /* ---- Cascade Level 2 ---- */ mfrc_clear_bits(REG_CollReg, 0x80); /* CL2 AntiColl */ DBG_STR("CL2AC"); tx[0] = PICC_SEL_CL2; tx[1] = 0x20; rxLen = sizeof(rx); st = mfrc_transceive(tx, 2, rx, &rxLen, ERR_MASK_ANTICOLL, WAIT_MS_ANTICOLL); if (st != MFRC_OK || rxLen < 5) return MFRC_ERROR; bcc = rx[0] ^ rx[1] ^ rx[2] ^ rx[3]; /* BCC再計算 */ /* CL2 Select */ DBG_STR("CL2SEL"); tx[0] = PICC_SEL_CL2; tx[1] = 0x70; tx[2] = rx[0]; tx[3] = rx[1]; tx[4] = rx[2]; tx[5] = rx[3]; tx[6] = bcc; if (mfrc_calc_crc(tx, 7, &crcL, &crcH) != MFRC_OK) return MFRC_ERROR; tx[7] = crcL; tx[8] = crcH; rxLen = 3; st = mfrc_transceive(tx, 9, rx, &rxLen, ERR_MASK_STRICT, WAIT_MS_SELECT); if (st != MFRC_OK) return MFRC_ERROR; /* SAK=0x00 → 選択完了 */ uid7[3] = tx[2]; uid7[4] = tx[3]; uid7[5] = tx[4]; uid7[6] = tx[5]; return MFRC_OK; } /* ================================================================ * ntag_read_page() : NTAGページ読み取り (4ページ=16byte返却) * ================================================================ */ static MFRC_Status ntag_read_page(uint8_t page, uint8_t *data16) { uint8_t tx[4]; uint8_t buf[18]; /* [v10修正] 16データ + CRC2バイト = 18バイト受信 */ uint8_t rxLen = sizeof(buf); uint8_t crcL, crcH; uint8_t i; MFRC_Status st; tx[0] = NTAG_READ; tx[1] = page; if (mfrc_calc_crc(tx, 2, &crcL, &crcH) != MFRC_OK) return MFRC_ERROR; tx[2] = crcL; tx[3] = crcH; st = mfrc_transceive(tx, 4, buf, &rxLen, ERR_MASK_STRICT, WAIT_MS_READ); if (st != MFRC_OK) return st; /* 先頭16バイトのみ呼び出し側へコピー (末尾2バイトはCRC) */ for (i = 0; i < 16 && i < rxLen; i++) data16[i] = buf[i]; return MFRC_OK; } /* ================================================================ * extract_3digit() : raw[len]からASCII数字3連続を検索 * ================================================================ */ static uint8_t extract_3digit(uint8_t *raw, uint8_t len, char *out3) { uint8_t i; for (i = 0; i + 2 < len; i++) { if (raw[i] >= '0' && raw[i] <= '9' && raw[i+1] >= '0' && raw[i+1] <= '9' && raw[i+2] >= '0' && raw[i+2] <= '9') { out3[0] = (char)raw[i]; out3[1] = (char)raw[i+1]; out3[2] = (char)raw[i+2]; out3[3] = '\0'; return 1; } } return 0; } /* ================================================================ * rfid_task() : メインループから定期呼び出し * * NTAG215 メモリマップ: * page0-1: UID(7byte) * page3 : Capability Container (0xE1 0x10 0x6D 0x00) * page4〜: NDEF TLV (03 [len] D1 01 ...) ← テキストデータ * ================================================================ */ static void rfid_task(void) { uint8_t uid[7], page_data[16], raw[48]; char digit3[4]; uint8_t p, b; /* カード検出 */ if (ntag_request() != MFRC_OK) return; /* 7バイトUID取得 (Cascade Level 1+2) */ if (ntag_select_7byte(uid) != MFRC_OK) { uart_str("SEL NG\r\n"); return; } /* UID表示 */ uart_str("UID:"); for (b = 0; b < 7; b++) { uart_hex8(uid[b]); uart_str(" "); } uart_crlf(); /* page4〜6 読み取り (3ページ × 16byte = 48byte) */ for (p = 0; p < 3; p++) { if (ntag_read_page(4 + p, page_data) != MFRC_OK) { uart_str("RD NG\r\n"); goto halt_card; } for (b = 0; b < 16; b++) raw[p * 16 + b] = page_data[b]; } /* 3桁数字抽出・表示 */ if (extract_3digit(raw, 48, digit3)) { uart_str(">>>"); uart_str(digit3); uart_str("<<<\r\n"); } else { uart_str("NO 3DIGIT\r\n"); } halt_card: /* HALT送信 */ { uint8_t halt_tx[4], dummy[2]; uint8_t dLen = 2, crcL, crcH; halt_tx[0] = PICC_HLTA; halt_tx[1] = 0x00; mfrc_calc_crc(halt_tx, 2, &crcL, &crcH); halt_tx[2] = crcL; halt_tx[3] = crcH; mfrc_transceive(halt_tx, 4, dummy, &dLen, ERR_MASK_ANTICOLL, WAIT_MS_SELECT); } HAL_Delay(1000); } /* USER CODE END 0 */ /* ================================================================ * main() * ================================================================ */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(500); uart_str("RFID v10\r\n"); mfrc_init(); uart_str("Ready\r\n"); /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ while (1) { rfid_task(); HAL_Delay(300); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ ``` コードはClaude Sonnet4.6に書いてもらいました。 メニューの「Project」 → 「 Build All」 を押しコンパイル&ビルドします。  問題がなければ、下部のコンソール画面に「0errors, 0warnings」と表示されます。  ※前回の画像です。 # 配線、NTAG読み取り動作(デバッグ) ## マイコン等の配線 ### ST-LINK - マイコン(STM32C011F4P6) CN3 pin1(VDD検知) - pin4(VDD) pin2(SWCLK) - pin19(PA14 SWCLK) pin3(GND) - pin5(VSS) pin4(SWDIO) - pin18(PA13 SWDIO) pin5(NRST) - pin6(NRST) TX - pin8(PA1 RX) RX - pin7(PA0 TX) CN6 3V3(3.3V給電) - pin4(VDD) ### M5StackRFID2 - マイコン(STM32C011F4P6) GND - pin5(VSS) SDA - pin1(PB7) SCL - pin2(PC14) M5StackRFID2 - STLINK 5V - 5V(5V給電) 分かりづらいのですが、参考図が下記です。 TXとRXは入れ替えて接続します。(デバッガTX - マイコンRX)   ## NTAG読み取り動作(デバッグ) NucleoボードとパソコンをUSBで接続します。(接続中の場合はそのまま) 「Run」 → 「Debug」をクリック デバッグ画面に切り替えを提案されるため、 「Switch」を押して了承する。 「▶」Resumeボタンをクリック NTAGをRFID2にかざします。  ターミナルに下図表示がでます。 NTAG:001をかざすと001 NTAG:002をかざすと002  次回以降はUSBを刺すだけで同様の動作となります。(マイコンにプログラムが書き込まれるため) ※IDEを再起動すると、ターミナルが切断されます。 その場合は下記を実施してください。 Open a Terminal Serial Terminalを選択 デバッガのCOM番号を選択 OK # 参考リンク ## M5StackRFID2 Arduinoコード M5STACK, Unit RFID / RFID2 Arduino 使用チュートリアル https://docs.m5stack.com/ja/arduino/projects/unit/unit_rfid GitHub, m5stack/M5Unified https://github.com/m5stack/M5Unified GitHub, MFRC522-I2C-Library/MFRC522_I2C.h https://github.com/arozcan/MFRC522-I2C-Library/blob/master/MFRC522_I2C.h