OYのアイコン画像
OY 2026年05月12日作成 (2026年05月12日更新) © CC0 1+
セットアップや使用方法 セットアップや使用方法 閲覧数 67
OY 2026年05月12日作成 (2026年05月12日更新) © CC0 1+ セットアップや使用方法 セットアップや使用方法 閲覧数 67

STM32C011F4P6でNTAGに対応した音楽を再生 (RFID2, DFPlayerMini)

STM32C011F4P6でNTAGに対応した音楽を再生 (RFID2, DFPlayerMini)

はじめに

前回「STM32C011F4P6でNFCタグを読む(M5Stack Unit RFID2)」 の続きです。

今回は、STM32C011F4P6とM5Stack Unit RFID2、DFPlayer miniを使って
読み取ったNTAG215内の数字に対応した音楽ファイルを再生します。
また電子工作初心者ですので、誤ったことを記載している可能性があります。
ご了承ください。

ブロック図

キャプションを入力できます

部品, 備品類

部品

AE-STM32C011F4P6-DIP(秋月電子キット)

Nucleo Board STM32C031C6
ブレッドボード(BB-801を使っています)
ジャンパーワイヤー オス-オス
ジャンパーワイヤー オス-メス
ピンヘッダ
USB A-マイクロB(2.0) (Nucleoボード接続用)
M5Stack用WS1850S搭載 RFID 2ユニット, 型番:M5STACK-U031-B(スイッチサイエンス)
NTAG215(AmazonのYFFSFDC NFCタグ NTAG215 30枚)
タクトスイッチ
DFPlayer mini (DFR0299)
マイクロSDカード
マイクロスピーカー 青/白リード付 8Ω(秋月電子)

備品, ソフト

パソコン(Windows11を使いました)
はんだごて、はんだ
STM32CubeMX
STM32CubeIDE
NFC Tools(iPhone版を使いました)

できたもの

NTAG215をRFID2にかざすと、対応したmp3が再生されます。
 (NTAG:001 >> 0001.mp3が再生)

ここに動画が表示されます

DFPlayer miniの動作確認

マイクロSDカードへ音楽ファイルの保管

下記ファイル構成で、mp3ファイルを保管します。

SDカード

├─mp3
   ├─0001.mp3
   ├─0002.mp3

音楽ファイルは、下記リンク先のものを使わせていただきました。
効果音ラボ
https://soundeffect-lab.info/sound/
Springin' Sound Stock
https://www.springin.org/sound-stock/

DFPlayer Miniの配線

下図のように配線しています。
 S3, S4はなし
 VCCはnucleoボードの5V給電
 GNDもnucleoボードのGND

マイクロSDは忘れずにセットしてください。

キャプションを入力できます

操作方法は下記です。
IO1:短く押す:次の曲再生/ 長く押す:音量低下
IO2:短く押す:前の曲再生/ 長く押す:音量増加

mp3を再生できることが分かったため、次に移ります。

ここに動画が表示されます

ピン設定等の初期設定、コード生成

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
 PA2:USART2_TX
 PA3:USART2_RX
  I2C:RFID2用、USART1:RFID2デバッグ用、USART2:DF Player mini用
キャプションを入力できます

I2CとUSART1の設定は、前回「STM32C011F4P6でNFCタグを読む(M5Stack Unit RFID2)」 同様に設定します。

USART2の設定
左メニューの「Connectivity」→「USART2」→Modeを「Asynchronous」へ変更します。
Baud Rateを9600bpsに変更します。(データシート記載のデフォルト)
キャプションを入力できます

「Project Manager」タブを押し、
「Project Name」にファイル名を記入
「Project Location」にて保存場所を選択
「Toolchain /IDE」をSTM32CubeIDEを選択

「GENERATE CODE」を押し、コード生成

※プロジェクトネームに"()"を使うと、ビルド時にエラーが発生するため使わないでください。
※プロジェクトロケーションは「CubeMX」直下としてください。
 「CubeMX\プロジェクトネーム」とした場合、CubeIDEでエラーが発生します。
キャプションを入力できます
※画像は1回目のものです。

補足:USART2左側の黄色三角警告について

USART2の左に黄色三角警告があります。
調べると、制限付きで使用可能のモードのようです。

CubeMXのSystem viewにてアラートはないため、このまま進めます。
キャプションを入力できます

STM32G0 -STM32CubeMXより
https://www.stmcu.jp/wp/wp-content/uploads/files/presentation-ja/STM32G0/STM32G0-Ecosystem-STM32CubeMX-Tool-J-.pdf
キャプションを入力できます

DF Player miniとSTM32の配線

前回「STM32C011F4P6でNFCタグを読む(M5Stack Unit RFID2)」 の配線に、
下記の配線を追加します。

DFplayer mini - マイコン(STM32C011F4P6)

pin2(RX) - 1kohm抵抗 - pin9(PA2)
pin2(TX) - pin10(PA3)
DFPlayerのRXには 1kΩ抵抗を直列に入れてください(3.3V信号を5V系DFPlayerに入力するための保護)

DFplayer mini - STLINK
VCC - 5V(5V給電)

DFplayer mini - 共通
pin7(GND), pin10(GND) - GND
 下記投稿によると、GND2ピン落とすと音質が良くなるとのこと。
 Issue with DFPlayer Mini and Raspberry Pi Pico - Only Hissing Sound
 https://www.reddit.com/r/raspberrypipico/comments/1gxy6jh/issue_with_dfplayer_mini_and_raspberry_pi_pico/?show=original

分かりづらいのですが、参考図が下記です。
TXとRXは入れ替えて接続します。(デバッガTX - マイコンRX)
キャプションを入力できます

コード入力、ビルド

STMCubeIDEのインポートしたプロジェクト内「Core」 → 「Src」 → 「main.c」にコードを記入します。

コードは下記範囲内にコピペしてください。
/* USER CODE BEGIN Header /
 コードのコピペ
/ USER CODE END 3 */

NTAG215+DFPlayerMini

/* 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桁数字) 読み取り + DFPlayer Mini 再生 v12 * STM32C011F4P6 + M5Stack RFID2 Unit (WS1850S) + DFPlayer Mini * * 【v11 → v12 変更点】 * [1] 同一カード連続再生スキップを廃止 → 毎回タッチで再生 * [2] DFPlayerコマンドを 0x0F → 0x12 に修正 * 0x12: /mp3/フォルダの4桁ファイル番号指定再生 * 例: num=1 → /mp3/0001.mp3, num=2 → /mp3/0002.mp3 * [3] 対応ファイル番号範囲を 1〜9999 に拡大 (999個運用可能) * [4] 不要な変数・define を削除してFLASH節約 * * 【SDカード内のフォルダ/ファイル構成】 * FAT32フォーマットのSDカード直下に /mp3/ フォルダを作成: * /mp3/0001.mp3 ← NTAGに"001"と書いた場合に再生 * /mp3/0002.mp3 ← NTAGに"002"と書いた場合に再生 * /mp3/0003.mp3 ← NTAGに"003"と書いた場合に再生 * ... ← 0999.mp3まで追加可能 * * 【配線まとめ】 * RFID2 SCL → PB7 (I2C1_SCL) * RFID2 SDA → PC14 (I2C1_SDA) * RFID2 VCC → 3.3V / GND → GND * ST-LINK → PA0(USART1_TX) / PA1(USART1_RX) ← デバッグ用 * DFPlayer TX → PA3 (USART2_RX) * DFPlayer RX → PA2 (USART2_TX) ← 1kΩ直列推奨 * DFPlayer VCC → 5V / GND → GND * DFPlayer SPK_1/SPK_2 → 8Ω スピーカー * * 【STM32CubeMX ピン設定】 * PB7 : I2C1_SCL * PC14 : I2C1_SDA * PA0 : USART1_TX (115200bps, デバッグ) * PA1 : USART1_RX * PA2 : USART2_TX (9600bps, DFPlayer) * PA3 : USART2_RX ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* 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 CMD_Idle 0x00 #define CMD_CalcCRC 0x03 #define CMD_Transceive 0x0C #define CMD_SoftReset 0x0F /* ---- NFC コマンド ---- */ #define PICC_REQA 0x26 #define PICC_CT 0x88 #define PICC_SEL_CL1 0x93 #define PICC_SEL_CL2 0x95 #define PICC_HLTA 0x50 #define NTAG_READ 0x30 /* ErrorReg マスク */ #define ERR_MASK_STRICT 0x13 #define ERR_MASK_ANTICOLL 0x13 /* 待機時間 (ms) */ #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=OFF, 1=ON */ #define RFID_DEBUG 0 /* ---- DFPlayer Mini コマンド定数 ---- */ #define DFP_START 0x7E #define DFP_VERSION 0xFF #define DFP_LEN 0x06 #define DFP_END 0xEF #define DFP_FEEDBACK 0x00 /* ACK不要 */ #define DFP_CMD_VOLUME 0x06 /* 音量設定 */ #define DFP_CMD_RESET 0x0C /* リセット */ #define DFP_CMD_PLAY_MP3 0x12 /* /mp3/フォルダ 4桁ファイル番号再生 */ #define DFP_VOLUME_DEFAULT 20 /* 音量 0〜30 */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ #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; UART_HandleTypeDef huart2; /* 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); static void MX_USART2_UART_Init(void); /* USER CODE BEGIN PFP */ /* UART1 ユーティリティ (デバッグ用) */ static void uart_str(const char *s); static void uart_hex8(uint8_t v); static void uart_crlf(void); /* WS1850S ドライバ */ 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); /* NTAG215 操作 */ 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); /* DFPlayer Mini */ static void dfp_send_cmd(uint8_t cmd, uint8_t param1, uint8_t param2); static void dfp_init(void); static void dfp_play_number(uint16_t num); /* メインタスク */ static void rfid_task(void); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* ================================================================ * UART1 ユーティリティ (デバッグ用・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, &reg, 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, &reg, 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); } 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); } /* ================================================================ * mfrc_transceive() * 【重要】送信順序: * ① CommandReg = CMD_Transceive (コマンド先) * ② BitFramingReg = 0x80 (StartSend後) * ================================================================ */ 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; 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); (void)mfrc_read(REG_ComIrqReg); /* irq読み捨て (未使用) */ err = mfrc_read(REG_ErrorReg); n = mfrc_read(REG_FIFOLevelReg); 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送信 * ================================================================ */ 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 + TxLastBits=7 */ 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; mfrc_read_burst(REG_FIFODataReg, rx, (n > 2) ? 2 : n); return MFRC_OK; } /* ================================================================ * ntag_select_7byte() : Cascade Level 1+2 で7バイトUID取得 * ================================================================ */ 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); 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]; 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; uid7[0] = tx[3]; uid7[1] = tx[4]; uid7[2] = tx[5]; /* ---- Cascade Level 2 ---- */ mfrc_clear_bits(REG_CollReg, 0x80); 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]; 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; 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]; /* 16データ + CRC2バイト */ 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; 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; } /* ================================================================ * DFPlayer Mini ドライバ * * コマンドフォーマット (10バイト): * [START] [VER] [LEN] [CMD] [FB] [P1] [P2] [CHK_H] [CHK_L] [END] * 0x7E 0xFF 0x06 ... 0x00 ... ... ... ... 0xEF * * チェックサム = -(VER + LEN + CMD + FB + P1 + P2) * * コマンド 0x12 (/mp3/フォルダ再生): * P1 = ファイル番号上位バイト * P2 = ファイル番号下位バイト * 例: num=1 → P1=0x00, P2=0x01 → /mp3/0001.mp3 * num=2 → P1=0x00, P2=0x02 → /mp3/0002.mp3 * num=999→ P1=0x03, P2=0xE7 → /mp3/0999.mp3 * ================================================================ */ static void dfp_send_cmd(uint8_t cmd, uint8_t param1, uint8_t param2) { uint8_t buf[10]; int16_t checksum; buf[0] = DFP_START; buf[1] = DFP_VERSION; buf[2] = DFP_LEN; buf[3] = cmd; buf[4] = DFP_FEEDBACK; buf[5] = param1; buf[6] = param2; checksum = -(int16_t)(buf[1] + buf[2] + buf[3] + buf[4] + buf[5] + buf[6]); buf[7] = (uint8_t)((checksum >> 8) & 0xFF); buf[8] = (uint8_t)(checksum & 0xFF); buf[9] = DFP_END; HAL_UART_Transmit(&huart2, buf, 10, 200); } static void dfp_init(void) { HAL_Delay(1000); /* DFPlayer 起動待ち */ dfp_send_cmd(DFP_CMD_RESET, 0, 0); HAL_Delay(1500); /* リセット後の初期化待ち */ dfp_send_cmd(DFP_CMD_VOLUME, 0, DFP_VOLUME_DEFAULT); HAL_Delay(100); } /* ================================================================ * dfp_play_number() * num : 1〜9999 * コマンド 0x12 で /mp3/XXXX.mp3 を再生 * NTAGの3桁数字 "001"〜"999" → num=1〜999 → 0001.mp3〜0999.mp3 * ================================================================ */ static void dfp_play_number(uint16_t num) { if (num < 1 || num > 9999) { uart_str("DFP: num out of range\r\n"); return; } /* 0x12: P1=上位バイト, P2=下位バイト */ dfp_send_cmd(DFP_CMD_PLAY_MP3, (uint8_t)(num >> 8), (uint8_t)(num & 0xFF)); uart_str("DFP: play /mp3/"); uart_hex8((uint8_t)(num >> 8)); uart_hex8((uint8_t)(num & 0xFF)); uart_crlf(); } /* ================================================================ * rfid_task() : メインループから定期呼び出し * * 【v12】同一カードスキップなし → タッチするたびに毎回再生 * ================================================================ */ 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桁数字抽出・DFPlayer再生 */ if (extract_3digit(raw, 48, digit3)) { uint16_t num; uart_str(">>>"); uart_str(digit3); uart_str("<<<\r\n"); num = (uint16_t)((digit3[0] - '0') * 100 + (digit3[1] - '0') * 10 + (digit3[2] - '0')); if (num >= 1) { dfp_play_number(num); /* 毎回タッチで再生 */ } else { uart_str("DFP: skip (num=0)\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(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(500); uart_str("RFID+DFPlayer v12\r\n"); mfrc_init(); uart_str("RFID Ready\r\n"); dfp_init(); uart_str("DFPlayer 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」 を押しコンパイル&ビルドします。
キャプションを入力できます
※1回目の画像です。

問題がなければ、下部のコンソール画面に「0errors, 0warnings」と表示されます。
キャプションを入力できます
※1回目の画像です。

動作確認(デバッグ)

NucleoボードとパソコンをUSBで接続します。(接続中の場合はそのまま)
「Run」 → 「Debug」をクリック

デバッグ画面に切り替えを提案されるため、
「Switch」を押して了承する。
▶」Resumeボタンをクリック

NTAGをRFID2にかざすと、[できたもの(https://elchika.com/article/e743071e-a789-4c5d-ae84-e8a5c14e05eb/#h_できたもの) の通り、
対応したmp3ファイルが再生されます。

STM32 Cube IDEのシリアルモニターは下記表示になります。
キャプションを入力できます

プログラムメモリ16kBに対し、15.65kBと結構使っています。
キャプションを入力できます

参考リンク

使わせていただいた音源

効果音ラボ
https://soundeffect-lab.info/sound/
Springin' Sound Stock
https://www.springin.org/sound-stock/

CubeMX解説 (ピン割り当て時、警告の説明)

STMicroelectronics, STM32G0 -STM32CubeMX
https://www.stmcu.jp/wp/wp-content/uploads/files/presentation-ja/STM32G0/STM32G0-Ecosystem-STM32CubeMX-Tool-J-.pdf

DFPlayer miniの使い方

DFROBOT, DFPlayer Mini Mp3 Player - DFRobot Wiki
https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299
秋月電子通商, [112544]DFPlayer mini (MP3プレーヤー)
https://akizukidenshi.com/catalog/g/g112544/
創造技術実習, DFPlayer – A Mini MP3 Playerを使う
https://robo164.com/archives/426
reddit, Issue with DFPlayer Mini and Raspberry Pi Pico - Only Hissing Sound
https://www.reddit.com/r/raspberrypipico/comments/1gxy6jh/issue_with_dfplayer_mini_and_raspberry_pi_pico/?tl=ja

  • OY さんが 前の火曜日の0:55 に 編集 をしました。 (メッセージ: 初版)
  • OY さんが 前の火曜日の0:56 に 編集 をしました。
ログインしてコメントを投稿する