最終更新日2021年3月2日
このプロジェクトの目的は、『DFPlayer』と呼ばれるMP3モジュールをLabVIEWから制御することです。
『DFPlayer』自体は単体でTFカード内のMP3/WMA等の音声ファイルを読み取ってDACして内蔵アンプを通してステレオ出力するモジュールです。このモジュールにはパワーアンプも搭載されており、Lch音声を最大3Wでスピーカドライブ可能です。
チップは『YX5200-24SS 』だと思われます。セカンドソースもたくさん出ているようです。
先人の書込を見ていると、昔小型の『iPod shuffle』が流行った頃に作られたカスタムチップが汎用品化されているという印象を持ちました。※Apple製品はTFカードが使えません。APODとして売られているパッチモンがそれですね。PCから敢えてリモート制御してまでMP3プレーヤを制御する必要性があるのか、要検討ですが、音声データ再生をリモート制御するとなれば用途はあるのかと思い、このプロジェクトを起案した次第です。
とても安価でコンパクトなスピーカBOXを、LANケーブル接続し、音声再生を遠隔地のPCから行います。予め用意しておいた別人の音声にて対応出来るため、意味がありますし、基本的な音声対応はスピーカBOX自体で自己完結し、EventLogだけPCに転送するというやり方も有りなのかと思います。
とりあえず代表的なchipである『YX5200-24SS 』をコマンド制御出来るツールを作成しました。
『YX5200-24SS 』のchipメーカは判っていません。そのためコマンドリファレンスもモジュールメーカであるKEYSTUDIO社が提供している資料から判断しています。
https://wiki.keyestudio.com/KS0387_keyestudio_YX5200-24SS_MP3_Module※KEYSTUDIO社のこのYX5200 MP3 デコーダミニですが、2020年5月29日にやっと入手出来ました。発注後実に90日経ってしまいました。
このモジュールですが、ヘッドフォンを接続してTFカードからMP3ファイルを再生したのですが、ノイズも少なくて好感が持てます。DIP型のモジュールが余りにノイズが酷いことを思うと、アナログ部に配慮があることは明かのようです
FUNCTION |
SENDING INSTRUCTIONS |
NOTES |
|
[Next] |
7E FF 06 01 00 00 00 FE FA EF |
||
[Previous] |
7E FF 06 02 00 00 00 FE F9 EF |
||
[Specify tracking] |
7E FF 06 03 00 00 01 FE F7 EF |
Specify track 1 |
|
7E FF 06 03 00 00 02 FE F6 EF |
Specify track 2 |
||
7E FF 06 03 00 00 0A FE EE EF |
Specify track 10 |
||
VOL+ |
7E FF 06 04 00 00 00 FE F7 EF |
||
VOL- |
7E FF 06 05 00 00 00 FE F6 EF |
[Specify volume] |
7E FF 06 06 00 00 1E FE D7 EF |
30 |
|
[Specify EQ] |
7E FF 06 07 00 00 01 FE F3 EF |
STAY |
|
[LOOP PLAYBACK] |
7E FF 06 08 00 00 01 FE F2 EF |
Loop play track 1 |
|
7E FF 06 08 00 00 02 FE F1 EF |
Loop play track 2 |
||
7E FF 06 08 00 00 0A FE E9 EF |
Loop play track 10 |
||
[Specify play device] |
7E FF 06 09 00 00 01 FE F1 EF |
Specify to play UDISK |
|
7E FF 06 09 00 00 02 FE F0 EF |
Specify to play TF |
||
7E FF 06 09 00 00 03 FE EF EF |
Specify play device-PC(download mode) |
||
7E FF 06 09 00 00 04 FE EE EF |
Specify to play FLASH |
||
7E FF 06 09 00 00 05 FE ED EF |
Specify play device-SLEEP |
||
[Enter into sleep mode] |
7E FF 06 0A 00 00 00 FE F1 EF |
||
[Waking sleep] |
7E FF 06 0B 00 00 00 FE F0 EF |
||
[Reset] |
7E FF 06 0C 00 00 00 FE EF EF |
||
[Play] |
7E FF 06 0D 00 00 00 FE EE EF |
||
[Pause] |
7E FF 06 0E 00 00 00 FE ED EF |
||
[Specify folder name] |
7E FF 06 0F 00 01 01 FE EA EF |
"01" folder,track "001" |
|
7E FF 06 0F 00 01 02 FE E9 EF |
"01" folder,track "002" |
||
Stop playing |
7E FF 06 16 00 00 00 FE E5 EF |
Stop the software decoding |
|
Specify folder to loop playback |
7E FF 06 17 00 00 01 FE E3 EF |
Specify folder 01 to loop playback |
|
7E FF 06 17 00 00 02 FE E2 EF |
Specify folder 02 to loop playback |
||
Single repeat |
7E FF 06 19 00 00 00 FE E2 EF |
Open single repeat playback |
|
7E FF 06 19 00 00 01 FE E1 EF |
Close single repeat playback |
||
Play with volume |
7E FF 06 22 00 1E 01 FE BA EF |
Play the track 1 with volume 30 |
|
7E FF 06 22 00 0F 01 FE C9 EF |
Play the track 1 with volume 15 |
||
7E FF 06 22 00 0F 02 FE C8 EF |
Play the track 2 with volume 15 |
||
set DAC |
7E FF 06 1A 00 00 00 FE E1 EF |
open DAC |
|
7E FF 06 1A 00 00 01 FE E0 EF |
close DAC[high resistance] |
||
Combination playback |
7E FF 09 21 01 02 02 03 01 04 EF |
Play
[1,2][2,3][1,4] The first number in |
|
7E
FF 15 21 01 02 02 03 01 04 01 |
with
checkout [1,2][2,3][1,4][1,3][1,4][1,5] |
||
7E
FF 15 21 01 02 02 03 01 04 01 |
[1,2][2,3][1,4][1,3][1,4][1,5][1,8][3,4][3,1] |
Stop playing ads |
7E FF 06 15 00 00 00 FE E6 EF |
Stop ads, return to play background music |
|
Stop playing |
7E FF 06 16 00 00 00 FE E5 EF |
Stop software decoding |
|
Spot ads. |
7E FF 06 13 00 00 01 FE E7 EF |
"ADVERT"foldertrack"0001" |
|
7E FF 06 13 00 00 02 FE E6 EF |
"ADVERT"foldertrack"0002" |
||
7E FF 06 13 00 00 FF FD E9 EF |
"ADVERT"foldertrack"0255" |
||
7E FF 06 13 00 07 CF FE 12 EF |
"ADVERT"foldertrack"1999" |
||
7E FF 06 13 00 0B B8 FE 25 EF |
"ADVERT"foldertrack"3000" |
||
Spot ads. - multiple folders |
7E FF 06 25 00 01 01 FE D4 EF |
"ADVERT1"foldertrack"001" |
|
7E FF 06 25 00 01 02 FE D3 EF |
"ADVERT1"foldertrack"002" |
||
7E FF 06 25 00 02 01 FE D3 EF |
"ADVERT2"foldertrack"001" |
||
Random playback |
7E FF 06 18 00 00 00 FE E3 EF |
Random playback of entire device |
[Query volume ] |
7E |
FF |
06 |
43 |
00 |
00 |
00 |
FE |
B8 |
EF |
||
[Query the current EQ] |
7E |
FF |
06 |
44 |
00 |
00 |
00 |
FE |
B7 |
EF |
Keep the function |
|
Query the total number of U-disk files |
7E |
FF |
06 |
47 |
00 |
00 |
00 |
FE |
B4 |
EF |
Total files of device |
|
Query the total number of TF files |
7E |
FF |
06 |
48 |
00 |
00 |
00 |
FE |
B3 |
EF |
||
Query the total number of FLASH files |
7E |
FF |
06 |
49 |
00 |
00 |
00 |
FE |
B2 |
EF |
||
Current track of U-disk |
7E |
FF |
06 |
4B |
00 |
00 |
00 |
FE |
B0 |
EF |
Play the current track |
|
Current track of TF |
7E |
FF |
06 |
4C |
00 |
00 |
00 |
FE |
AF |
EF |
||
Current track of FLASH |
7E |
FF |
06 |
4D |
00 |
00 |
00 |
FE |
AE |
EF |
||
Query
the total number of specified |
7E |
FF |
06 |
4E |
00 |
00 |
01 |
FE |
AC |
EF |
||
Query the total number of device files |
7E |
FF |
06 |
4F |
00 |
00 |
00 |
FE |
AC |
EF |
Support
TF card |
U-disk plug in |
7E FF 06 3A 00 00 01 xx xx EF |
||
TF plug in |
7E FF 06 3A 00 00 02 xx xx EF |
||
PC plug in |
7E FF 06 3A 00 00 04 xx xx EF |
||
U-disk pull out |
7E FF 06 3B 00 00 01 xx xx EF |
||
TF pull out |
7E FF 06 3B 00 00 02 xx xx EF |
||
PC pull out |
7E FF 06 3B 00 00 04 xx xx EF |
||
Played track 1 of U-disk |
7E FF 06 3C 00 00 01 xx xx EF |
Complete play track 1 of U-disk |
|
Played track 2 of U-disk |
7E FF 06 3C 00 00 02 xx xx EF |
Complete play track 2 of U-disk |
|
Played track 1 of TF card |
7E FF 06 3D 00 00 01 xx xx EF |
Complete play track 1 of TF card |
|
Played track 2 of TF card |
7E FF 06 3D 00 00 02 xx xx EF |
Complete play track 2 of TF card |
|
FLASH played track 1 |
7E FF 06 3E 00 01 01 xx xx EF |
Played track 1 of FOLDER1 |
|
FLASH played track 2 |
7E FF 06 3E 00 02 02 xx xx EF |
Played track 2 of FOLDER2 |
|
U-disk -- available |
7E FF 06 3F 00 00 01 xx xx EF |
Relative of all devices |
|
TF -- available |
7E FF 06 3F 00 00 02 xx xx EF |
||
PC -- available |
7E FF 06 3F 00 00 04 xx xx EF |
||
FLASH -- available |
7E FF 06 3F 00 00 08 xx xx EF |
||
U-diskTF -- available |
7E FF 06 3F 00 00 03 xx xx EF |
||
TF card andFLASH |
7E FF 06 3F 00 00 0A xx xx EF |
||
TF and PC online |
7E FF 06 3F 00 00 06 FE B6 EF |
||
U-disk
TF cardPC |
7E FF 06 3F 00 00 1F xx xx EF |
||
Played track 1 of U-disk |
7E FF 06 3C 00 00 01 xx xx EF |
Complete play track 1 of U-disk |
|
Played track 2 of U-disk |
7E FF 06 3C 00 00 02 xx xx EF |
Complete play track 2 of U-disk |
|
Played track 1 of TF card |
7E FF 06 3D 00 00 01 xx xx EF |
Complete play track 1 of TF card |
|
Played track 2 of TF card |
7E FF 06 3D 00 00 02 xx xx EF |
Complete play track 2 of TF card |
|
FLASH played track 1 |
7E FF 06 3E 00 01 01 xx xx EF |
Played track 1 of FOLDER1 |
|
FLASH played track 2 |
7E FF 06 3E 00 02 02 xx xx EF |
Played track 2 of FOLDER2 |
Return |
7E |
FF |
06 |
40 |
00 |
00 |
01 |
xx |
xx |
EF |
Module is initialized in the file system |
|
Current sleep mode |
7E |
FF |
06 |
40 |
00 |
00 |
02 |
xx |
xx |
EF |
Only
support the specified device |
|
Serial receiving error |
7E |
FF |
06 |
40 |
00 |
00 |
03 |
xx |
xx |
EF |
The
serial port has not received |
|
Checkout error |
7E |
FF |
06 |
40 |
00 |
00 |
04 |
xx |
xx |
EF |
Checksum error |
|
Specified file overreach |
7E |
FF |
06 |
40 |
00 |
00 |
05 |
xx |
xx |
EF |
Specify
the folder exceed the |
|
Specify folder not found |
7E |
FF |
06 |
40 |
00 |
00 |
06 |
xx |
xx |
EF |
Specify folder not found |
|
Inter cut error |
7E |
FF |
06 |
40 |
00 |
00 |
07 |
xx |
xx |
EF |
Spots
are only allowed in playing |
|
TF card play error |
7E |
FF |
06 |
40 |
00 |
00 |
08 |
xx |
xx |
EF |
TF
card read failed or TF card |
|
FLASH |
7E |
FF |
06 |
40 |
00 |
00 |
09 |
xx |
xx |
EF |
FLASH file error |
|
SLEPP |
7E |
FF |
06 |
40 |
00 |
00 |
0A |
xx |
xx |
EF |
Prompt to enter SLEPP mode |
【ホストアプリケーション】
アプリケーションは『設定』タブで接続先を選択し、接続後、『制御』タブに移って音声再生します。
目的が音楽再生だと『シャッフル再生』だとか『リピート再生』だとかの機能が必要かと思います。確かにこのchipには用意されています。
一方フォルダでカテゴリ分けして幾つかの音声ファイルをデータベースライクに用意しておけば、気の利いたメッセージをピンポイントで再生することが出来ます。
![]() |
||
@ | 終了ボタン | アプリケーションを終了する。 |
A | 接続インジケータ | TCP乃至はシリアルで接続していたら点灯します |
B | 再生 | 停止位置からの再生開始 |
C | 一時停止 | 再生位置の停止/再開 |
D | 停止 | 再生の停止 |
E | 1曲戻る | 次の曲の再生 |
F | 1曲進む | 前の曲の再生 |
G | トラック指定 | Jで指定したトラックに移行 |
H | リピート再生 | Iで指定したフォルダ内をリピート再生 |
I | フォルダインデックス |
01−99 下の数字はフォルダ数(隠しフォルダや、無効フォルダも形状) 『99』と云うフォルダが無いのに“99”を指定するとエラーが発生します。I参照 |
J | トラックインデックス | 001−255,1-3000 下の数字はファイルの総数 |
K | ボリューム値 | 0-30 |
L | ボリューム設定 | Kで示した値でボリュームを直接設定 |
M | ボリューム上下 | ▲を一回押すとボリューム値をインクリメント▼でデクリメント |
N | イコライザ設定 | Normal/POPS/ROCK/JAZZ/CLASSIC |
@ | VISA識別子 | COMx或いはNI-MAXで登録された値 |
A | 接続・切断 | |
B | インタフェース設定 | TF/USB/FLASH |
@ | コマンド | YX5200-24SSの資料にあるコマンド |
A | 応答要求? |
制御コマンドはECHOバックを期待するかどうか? ※応答が必要なコマンドは0x01にするとエラーになる。 |
B | SUM設定? |
チェックサムを使っても使わなくても使用できるため、この設定が用意されている。 チェックサムを使うと10[Byte]使わないと8[Byte] 0xEFが終端なのでなんとでもなる |
C | パラメータHigh | |
D | パラメータLow | |
E | コマンド送信 | |
F | コマンド送信バイト列 | 送信文字列を16進数表示 |
G | コマンド送信文字列 | 表示形式の変更が出来ます。通常は16進表記 |
H | コマンド受信文字列 | 表示形式の変更が出来ます。通常は16進表記 |
I | Actionメッセージ | イベントが起きたときのメッセージを表示 |
@ | エラー履歴 |
内部ではコマンド部は一つのVIに纏めてあります。
ターゲットデバイスと接続形態はシリアル接続とLAN接続を用意しています。
シリアル接続はDFPlayerが用意しているUARTにUSB<->シリアル変換モジュールで接続することを想定しています。PCにCOMポートがあったとしても電気的に直接接続出来ません。安価なモジュールがたくさんリリースされていますので適当な物で接続します。
※PC側ボーレートの設定方法ですが、アプリケーション側から変更出来れば良いのですが、その限りでは無い場合、デバイスドライバにて初期値を決定しておくべきです。DFPlayer側のボーレートが9600bps 8bit StopBit1 NonParty NonFlow
LAN接続するにはLAN<->UART変換器が必要になります。コマンドを単に変換するだけですので市販品もあるのかと思ったのですが、判断しづらいです。で有れば、『STM32MINIShield』で実現した方が確実です。
※WIZ107SRが説明文を読む限りLAN<->UART変換器のようです。
LabVIEWとはTCPソケット通信して、『STM32MINIShield』側で受信したコマンド文字列を接続されたDFPlayerに垂れ流す。
一方、DFPlayerからの応答もTCPソケット通信で返信するという物です。
この場合一寸問題があります。DFPlayerにTFカードが挿入されたとか抜かれたというEventが『STM32MINIShield』側迄は認識されてもLAN接続されたLabVIEWに通知する仕組みが用意出来ていないと云う事です。一応LAN接続時の『STM32MINIShield』のコードも紹介しておきます。Arduino(STM32duino)のスケッチです。
このコードを実行するに当たり追加が必要なライブラリは、
/* * 2020/2/25 T.Wanibe DFPlayer用プロジェクトコード * 制御コマンドはほぼ期待通りになったので問い合わせコマンドを対応すべく修正した。 * ライブラリを使用するとコマンド送信は出来ても返信を横取りされてしまう。ライブラリにthruコマンドが用意されていれば * なんとかなるのだが。。 * そこで『DFRobotDFPlayerMini』を使う事を止めたバージョンです。 * LabVIEWからシリアルコンバータ経由でDFPlayerにシリアル接続した場合は問い合わせコマンドも普通に動くことを確認出来たので * STM32duino側のコードにてシリアルコードを受け取ったらそのままTCPSocketに送るように変更する * STM32MINIShield基板に『DfPlayer』をシリアル接続して,LabVIEW(Windows)からLAN経由でSTM32MINIShield基板に接続し * 制御コマンドを送ると、そのコマンドをブリッジして『DfPlayer』に送って制御するというモノです。 * 接続する『DfPlayer』はKeyStudio社のKS0387が都合がいいです。KS0387はスピーカをドライブしなければSTM32MINIShield基板 * からの供給電力で賄えると考えています。そうで無い場合は接続するシリアルポートの電源供給はせず、KS0387内に別途電源供給する * 必要があります。 * コマンドはLabVIEW側で管理し、Socketで渡ってきたコマンド文字列をそのままSerial1の回します。 * コマンド文字列は以下のフォーマットです。 * $S VER Len CMD FB PRAM1 PARAM2 CSUMH CSUML $O * の10バイト固定長です。チェックサムを外した8バイト長も有効なデバイスもあるようですが、此処ではチェックサム付きとします。 * * 最大131072バイトのフラッシュメモリのうち、スケッチが53560バイト(40%)を使っています。 * 最大20480バイトのRAMのうち、グローバル変数が4792バイト(23%)を使っていて、ローカル変数で15688バイト使うことができます。 */ #include <SPI.h> #include <Ethernet3.h> #include <TextFinder.h> //WebSetting #include <EEPROM.h> #include <avr/pgmspace.h> #include <TM1638.h> //#include "DFRobotDFPlayerMini.h" #define SocketPort 50001 #define HttpPort 80 #define OKMSG "" #define NGMSG "" #define Version "STM32MINIShield_DFPlayer" #define W550io_CS PA4 //PB12 SPI_1に変更 #define W550io_Rst PA8 // #define LED1_Pin PB8 #define LED2_Pin PB9 #define BUSY_Pin PB0 //DFPlayer_Busy #define dataPin PB4 //LED&KEY #define clockPin PB3 //LED&KEY #define strobePin PA15 //LED&KEY //DFPlayer #define TimeOut 0 #define WrongStack 1 #define DFPlayerCardInserted 2 #define DFPlayerCardRemoved 3 #define DFPlayerCardOnline 4 #define DFPlayerPlayFinished 5 #define DFPlayerError 6 #define DFPlayerUSBInserted 7 #define DFPlayerUSBRemoved 8 #define DFPlayerUSBOnline 9 #define DFPlayerCardUSBOnline 10 #define DFPlayerFeedBack 11 #define Busy 1 #define Sleeping 2 #define SerialWrongStack 3 #define CheckSumNotMatch 4 #define FileIndexOut 5 #define FileMismatch 6 #define Advertise 7 byte mac[6] = {0x00, 0x08, 0xDC, 0x54, 0x4D, 0xD0}; //WiZ550ioに添付されているMACアドレス byte ip[] = {192,168,0,200}; //配列で扱わないと処理が難しい byte subnet[] = {255,255,255,0}; byte gateway[] = {192,168,0,1}; byte server[] = {192,168,0,255}; volatile bool EnableLAN = true; //ADC処理中はEnableLAN = falseにする。 volatile bool LANConnect = false; //LanModuleにアクセスしているときTrue volatile bool Continuation = false; //TCPパケットの続きがあるか? volatile bool ContinueRun = false; //連続パタン出力か? long int interval; long int gCycle = 100; //100msec 10S/s volatile long int LoopCount = 0; volatile long int MainLoopCount = 0; uint8_t toggle1 = 0; char buf[20]; bool alreadyConnected= false; const byte ID = 0x92; char next_msg[] = {0x7E, 0xFF, 0x06, 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFA, 0xEF}; char prev_msg[] = {0x7E, 0xFF, 0x06, 0x02, 0x00, 0x00, 0x00, 0xFE, 0xF9, 0xEF}; char volp_msg[] = {0x7E, 0xFF, 0x06, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xF7, 0xEF}; char volm_msg[] = {0x7E, 0xFF, 0x06, 0x05, 0x00, 0x00, 0x00, 0xFE, 0xF6, 0xEF}; char rpet_msg[] = {0x7E, 0xFF, 0x06, 0x19, 0x00, 0x00, 0x00, 0xFE, 0xE2, 0xEF}; char play_msg[] = {0x7E, 0xFF, 0x06, 0x0D, 0x00, 0x00, 0x00, 0xFE, 0xEE, 0xEF}; char paus_msg[] = {0x7E, 0xFF, 0x06, 0x0E, 0x00, 0x00, 0x00, 0xFE, 0xED, 0xEF}; char stop_msg[] = {0x7E, 0xFF, 0x06, 0x16, 0x00, 0x00, 0x00, 0xFE, 0xE5, 0xEF}; char volr_msg[] = {0x7E, 0xFF, 0x06, 0x43, 0x00, 0x00, 0x00, 0xFE, 0xB8, 0xEF}; EthernetServer socketServer = EthernetServer(SocketPort); EthernetServer webServer = EthernetServer(HttpPort); EthernetClient tcp; EthernetClient web; size_t size; char BUF[32]; char rSTR[48]; String EventBUF; TM1638 LedAndKey(dataPin, clockPin, strobePin); //データピンPB4、クロックピンPB3、およびストローブピンPA15でモジュールを定義する //--------------------- void printDetail(EthernetClient tcp,uint8_t type, int value){ switch (type) { case TimeOut: Serial.println(F("Time Out!")); //tcp.write("Time Out!\r\n"); break; case WrongStack: Serial.println(F("Stack Wrong!")); //tcp.write("Stack Wrong!\r\n"); break; case DFPlayerCardInserted: Serial.println(F("Card Inserted!")); //tcp.write("Card Inserted!\r\n"); break; case DFPlayerCardRemoved: Serial.println(F("Card Removed!")); //tcp.write("Card Removed!"); break; case DFPlayerCardOnline: Serial.println(F("Card Online!")); //tcp.write("Card Online!\r\n"); break; case DFPlayerUSBInserted: Serial.println(F("USB Inserted!")); //tcp.write("USB Inserted!\r\n"); break; case DFPlayerUSBRemoved: Serial.println(F("USB Removed!")); //tcp.write("USB Removed!\r\n"); break; case DFPlayerPlayFinished: Serial.print(F("Number:")); Serial.print(value); Serial.println(F(" Play Finished!")); //sprintf(BUF,"Number:%d Play Finished!\n",value); //tcp.write(BUF); break; case DFPlayerError: Serial.print(F("DFPlayerError:")); switch (value) { case Busy: Serial.println(F("Card not found")); //tcp.write("DFPlayerError:Card not found\r\n"); break; case Sleeping: Serial.println(F("Sleeping")); //tcp.write("DFPlayerError:Sleeping\r\n"); break; case SerialWrongStack: Serial.println(F("Get Wrong Stack")); //tcp.write("DFPlayerError:Get Wrong Stack\r\n"); break; case CheckSumNotMatch: Serial.println(F("Check Sum Not Match")); //tcp.write("DFPlayerError:Check Sum Not Match\r\n"); break; case FileIndexOut: Serial.println(F("File Index Out of Bound")); //tcp.write("DFPlayerError:File Index Out of Bound\r\n"); break; case FileMismatch: Serial.println(F("Cannot Find File")); //tcp.write("DFPlayerError:Cannot Find File\r\n"); break; case Advertise: Serial.println(F("In Advertise")); //tcp.write("DFPlayerError:In Advertise\r\n"); break; default: break; } break; default: break; } } //------------------LAN設定 void LANSetup(){ int idcheck = EEPROM.read(0); Serial.print(F("LocalID = 0x"));Serial.println(idcheck,HEX); if (idcheck == ID){ //idがIDと同じ値の場合、 //これは、このスケッチがシールドを設定するために使用されたことを意味します。 //EERPOMの値を読み取ってシールドを設定します。 for (int i = 0; i < 6; i++){ mac[i] = EEPROM.read(i+1); } for (int i = 0; i < 4; i++){ ip[i] = EEPROM.read(i+7); } for (int i = 0; i < 4; i++){ subnet[i] = EEPROM.read(i+11); } for (int i = 0; i < 4; i++){ gateway[i] = EEPROM.read(i+15); } }else{ //idが一致しない場合、初期値を書き込む事にします。 for (int i = 0 ; i < 6; i++){ EEPROM.write(i + 1,mac[i]); } for (int i = 0 ; i < 4; i++){ EEPROM.write(i + 7, ip[i]); } for (int i = 0 ; i < 4; i++){ EEPROM.write(i + 11, subnet[i]); } for (int i = 0 ; i < 4; i++){ EEPROM.write(i + 15, gateway[i]); } // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。 EEPROM.write(0, ID); } Ethernet.begin(mac, ip); // Ethernet.begin(mac); //DHCPの場合 // Ethernet.begin(mac, ip, subnet); //SubnetMaskを意識した場合。 // Ethernet.begin(mac, ip, subnet, gateway); //gatewayを意識した場合。 } //-------------------------- void SetWebPage( EthernetClient client){ client.print(F("<!DOCTYPE HTML PUBLIC \"\"><html><HEAD><META http-equiv=\"Content-Type\" charset=UTF-8\">")); client.print(F("<META http-equiv=\"Content-Style-Type\"><TITLE>")); client.print(Version); client.print(F(" Setup Page</TITLE></HEAD>")); client.print(F("<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\"><BLOCKQUOTE><BLOCKQUOTE>")); client.print(F("<table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\">")); client.print(F("<tr><td> ")); client.print(Version); client.print(F(" Setup Page</td></tr></table><br>")); // client.print(F("<script>function hex2num (s_hex) {eval(\"var n_num=0X\" + s_hex);return n_num;}</script>")); client.print(F("<FORM><input type=\"hidden\" name=\"SBM\" value=\"1\"><table><tr><td>MAC:</td><td>")); client.print(F("<input id=\"T1\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT1\" value=\"")); client.print(mac[0],HEX); client.print(F("\">.<input id=\"T3\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT2\" value=\"")); client.print(mac[1],HEX); client.print(F("\">.<input id=\"T5\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT3\" value=\"")); client.print(mac[2],HEX); client.print(F("\">.<input id=\"T7\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT4\" value=\"")); client.print(mac[3],HEX); client.print(F("\">.<input id=\"T9\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT5\" value=\"")); client.print(mac[4],HEX); client.print(F("\">.<input id=\"T11\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT6\" value=\"")); client.print(mac[5],HEX); // client.print(F("\"><input id=\"T2\" type=\"hidden\" name=\"DT1\"><input id=\"T4\" type=\"hidden\" name=\"DT2")); client.print(F("\"><input id=\"T6\" type=\"hidden\" name=\"DT3\"><input id=\"T8\" type=\"hidden\" name=\"DT4")); client.print(F("\"><input id=\"T10\" type=\"hidden\" name=\"DT5\"><input id=\"T12\" type=\"hidden\" name=\"DT6")); client.print(F("\"></td></tr><tr><td>IP:</td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT7\" value=\"")); client.print(ip[0],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT8\" value=\"")); client.print(ip[1],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT9\" value=\"")); client.print(ip[2],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT10\" value=\"")); client.print(ip[3],DEC); // client.print(F("\"></td></tr><tr><td>MASK: </td><td><input type= \"text\" size=\"3\" maxlength=\"3\" name=\"DT11\" value=\"")); client.print(subnet[0],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT12\" value=\"")); client.print(subnet[1],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT13\" value=\"")); client.print(subnet[2],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT14\" value=\"")); client.print(subnet[3],DEC); // client.print(F("\"></td></tr><tr><td>GW: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT15\" value=\"")); client.print(gateway[0],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT16\" value=\"")); client.print(gateway[1],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT17\" value=\"")); client.print(gateway[2],DEC); client.print(F("\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT18\" value=\"")); client.print(gateway[3],DEC); client.print(F("\"></td></tr><tr><td><br></td></tr><tr><td><input id=\"button1\"type=\"submit\" value=\"SUBMIT\" ")); // client.print(F("Onclick=\"document.getElementById('T2').value ")); client.print(F("= hex2num(document.getElementById('T1').value);")); client.print(F("document.getElementById('T4').value = hex2num(document.getElementById('T3').value);")); client.print(F("document.getElementById('T6').value = hex2num(document.getElementById('T5').value);")); client.print(F("document.getElementById('T8').value = hex2num(document.getElementById('T7').value);")); client.print(F("document.getElementById('T10').value = hex2num(document.getElementById('T9').value);")); client.print(F("document.getElementById('T12').value = hex2num(document.getElementById('T11').value);\"")); // client.print(F("></td><td></td></tr></form></table></BLOCKQUOTE></BLOCKQUOTE></BODY></html>")); } //-------------------------- void checkWebPage( EthernetClient client) { Serial.println(F("new webClient")); if (client) { TextFinder finder(client ); while (client.connected()) { //digitalWrite(LED, HIGH); if (client.available()) { //この部分はすべてのテキスト検索を行います。 if( finder.find("GET /") ) { // 「setup」とい語が見つかった場合は、さらに探してください。 // その単語が見つからない場合は、検索を停止して先に進みます。 // これにより、後でスケッチに独自のWebページを配置できます。 if (finder.findUntil("setup", "\n\r")){ // 「SBM」という単語が見つかった場合は、さらに探し続けます。 // その言葉が見つからない場合は、探して停止します。 // SUBMITボタンが押されていない、何も押されていないことを意味します // セットアップページが構築されている場所に移動し、クライアントのブラウザに表示します。 if (finder.findUntil("SBM", "\n\r")){ byte SET = finder.getValue(); // これで、「DT」という文字を探している間に、「DT」の後ろにあるすべての数字を覚えて、 // 値を一致させて、mac、ip、subnet、およびgatewayに入れる必要があります。 while(finder.findUntil("DT", "\n\r")){ int val = finder.getValue(); // 「DT」のvalが1?6の場合、対応する値はMAC値でなければなりません。 if(val >= 1 && val <= 6) { mac[val - 1] = finder.getValue(); } // 「DT」のvalが7?10の場合、対応する値はIP値でなければなりません。 if(val >= 7 && val <= 10) { ip[val - 7] = finder.getValue(); } // 「DT」のvalが11?14の場合、対応する値はMASK値でなければなりません。 if(val >= 11 && val <= 14) { subnet[val - 11] = finder.getValue(); } // 「DT」のvalが15?18の場合、対応する値はGW値でなければなりません。 if(val >= 15 && val <= 18) { gateway[val - 15] = finder.getValue(); } } // すべてのデータを取得したので、EEPROMに保存できます for (int i = 0 ; i < 6; i++){ EEPROM.write(i + 1,mac[i]); } for (int i = 0 ; i < 4; i++){ EEPROM.write(i + 7, ip[i]); } for (int i = 0 ; i < 4; i++){ EEPROM.write(i + 11, subnet[i]); } for (int i = 0 ; i < 4; i++){ EEPROM.write(i + 15, gateway[i]); } // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。 EEPROM.write(0, ID); // すべてのデータがEEPROMに書き込まれている場合、arduinoをリセットする必要があります。 //ハードウェアリセットボタンを使用する必要があります。 } // この時点から、セットアップページの構築を開始し、クライアントのブラウザーに表示できます。 client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); // SetWebPage(client); break; } } client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); // put your own html from here on client.print("IT WORKS: go to "); client.print(ip[0],DEC); for (int i= 1; i < 4; i++){ client.print("."); client.print(ip[i],DEC); } client.print("/setup"); // put your own html until here break; } } //digitalWrite(LED, LOW); delay(1); client.stop(); } } //------------------ void setup() { Serial.begin(115200); //USB経由の接続 Serial1.begin(9600,SERIAL_8N1); //DFPlayerとの接続 D8bit S1bit Nonパリティ delay(1000); Serial.println(F("\nStart")); pinMode(LED1_Pin, OUTPUT); digitalWrite(LED1_Pin, LOW); pinMode(LED2_Pin, OUTPUT); digitalWrite(LED2_Pin, LOW); pinMode(BUSY_Pin, INPUT); if(digitalRead(BUSY_Pin)) digitalWrite(LED1_Pin, HIGH); else digitalWrite(LED1_Pin, LOW); //Ethernet3で使用可能なAPI Ethernet.setCsPin(W550io_CS); // set Pin PA4 for CS Ethernet.setRstPin(W550io_Rst); // set Pin PA8 for RST //リセット処理 pinMode(W550io_Rst, OUTPUT); digitalWrite(W550io_Rst, LOW); delay(10); digitalWrite(W550io_Rst, HIGH); LANSetup(); //Setup Serial.print(F("Server is at ")); Serial.print(Ethernet.localIP());Serial.print(F("\t"));Serial.println(Version); socketServer.begin(); webServer.begin(); //LED&KEY 初期化 LedAndKey.setDisplayToString("00000000",0,0); /* if (!myDFPlayer.begin(Serial1)) { //Use softwareSerial to communicate with mp3. Serial.println(F("Unable to begin:")); Serial.println(F("1.Please recheck the connection!")); Serial.println(F("2.Please insert the SD card!")); while(true) delay(0); // Code to compatible with ESP8266 watch dog. } */ Serial.println(F("EndSetUp")); } //------------------ void loop() { if (MainLoopCount++ % 50) { if (EnableLAN) { Serial.print(F(".")); } else { Serial.print(F("x")); } } else { Serial.print(F("\n")); Serial.println(MainLoopCount); } long int StartTCP = micros(); LANConnect = true; delay(1); tcp = socketServer.available(); //Serial.println(F("socketServer.available")); if (tcp) { if (!alreadyConnected) { tcp.flush(); // clear out the input buffer: alreadyConnected = true; } while ((size = tcp.available()) > 0) { //受信処理 char* msg = (char*)malloc(size); delay(1); size = tcp.read((unsigned char*)msg, size); Serial.print(F("PacketSize = ")); Serial.println(size); for(int i=0;i<size;i++){ sprintf(BUF,"%02x",msg[i]); Serial.print(BUF); } Serial.println(); switch (msg[0]) { case 0x7E: //コマンド要求 if(msg[3] == 0x39){ //内部処理 //Serial.println(EventBUF.length()); if(EventBUF.length()){ for(int i=0;i<9;i++){ tcp.write(EventBUF.c_str()[i]); Serial.print(EventBUF.c_str()[i],HEX); } tcp.write('0xEF'); EventBUF = EventBUF.substring(0,0);; }else{ for(int i=0;i<size;i++){ tcp.write(msg[i]); } } }else{ for(int i=0;i<size;i++){ Serial1.write(msg[i]); //Serial1.print()ではうまくゆかない sprintf(BUF,"%02x",msg[i]); Serial.print(BUF); } Serial.println(); delay(30); //1文字でも受信させる時間余裕を設定 if(Serial1.available()){ String recivedSTR = Serial1.readStringUntil(0xEF);//デリミタはhEF for(int i=0;i<recivedSTR.length();i++){ tcp.write(recivedSTR.c_str()[i]); sprintf(BUF,"%02x",recivedSTR.c_str()[i]); Serial.print(BUF); } tcp.write('0xEF'); Serial.print(F("EF")); if (EnableLAN) tcp.write(OKMSG); tcp.flush(); } } break; default: if (EnableLAN) tcp.write(NGMSG); break; } free(msg); } } if (Serial1.available()) { //バッファにメッセージが残っていたら String EventSTR = Serial1.readStringUntil(0xEF); //デリミタはhEF int length = EventSTR.length(); //for(int i=0;i<length;i++){ // tcp.write(EventSTR.c_str()[i]); //} //tcp.write('0xEF');tcp.flush(); EventBUF = EventSTR.substring(0); byte cmd1 = EventSTR.c_str()[length-6]; int err1 = EventSTR.c_str()[length-3]; sprintf(BUF,"\nL=%d C=0x%x E=%d\n",length,cmd1,err1); Serial.print(BUF); printDetail(tcp,cmd1,err1); } web = webServer.available(); if(web) checkWebPage(web); web.stop(); // コネクションを閉じる。 LANConnect = false; String recivedSTR; int volValue; byte keys = LedAndKey.getButtons(); switch(keys){ case 0x01: LedAndKey.setDisplayToString("next ",0,0); for(int i=0;i<10;i++){ Serial1.write(next_msg[i]); //Serial1.print()ではうまくゆかない } break; case 0x02: LedAndKey.setDisplayToString("volp ",0,0); for(int i=0;i<10;i++){ Serial1.write(volp_msg[i]); //Serial1.print()ではうまくゆかない } delay(20); for(int i=0;i<10;i++){ Serial1.write(volr_msg[i]); //Serial1.print()ではうまくゆかない } delay(20); recivedSTR = Serial1.readStringUntil(0xEF); volValue = recivedSTR.c_str()[6]; Serial.println(volValue); sprintf(BUF,"%02d\0",volValue); LedAndKey.setDisplayToString(BUF,0,6); break; case 0x04: LedAndKey.setDisplayToString("vol- ",0,0); for(int i=0;i<10;i++){ Serial1.write(volm_msg[i]); //Serial1.print()ではうまくゆかない } delay(20); for(int i=0;i<10;i++){ Serial1.write(volr_msg[i]); //Serial1.print()ではうまくゆかない } delay(20); recivedSTR = Serial1.readStringUntil(0xEF); volValue = recivedSTR.c_str()[6]; sprintf(BUF,"%02d\0",volValue); LedAndKey.setDisplayToString(BUF,0,6); break; case 0x08: LedAndKey.setDisplayToString("prev ",0,0); for(int i=0;i<10;i++){ Serial1.write(prev_msg[i]); //Serial1.print()ではうまくゆかない } break; case 0x10: LedAndKey.setDisplayToString("repeat ",0,0); for(int i=0;i<10;i++){ Serial1.write(rpet_msg[i]); //Serial1.print()ではうまくゆかない } break; case 0x20: LedAndKey.setDisplayToString("play ",0,0); for(int i=0;i<10;i++){ Serial1.write(play_msg[i]); //Serial1.print()ではうまくゆかない } break; case 0x40: LedAndKey.setDisplayToString("pause ",0,0); for(int i=0;i<10;i++){ Serial1.write(paus_msg[i]); //Serial1.print()ではうまくゆかない } break; case 0x80: LedAndKey.setDisplayToString("stop ",0,0); for(int i=0;i<10;i++){ Serial1.write(stop_msg[i]); //Serial1.print()ではうまくゆかない } break; default: break; //何もしない } if(digitalRead(BUSY_Pin)) digitalWrite(LED1_Pin, HIGH); else digitalWrite(LED1_Pin, LOW); delay(100); }SlaveデバイスのIPアドレスやMACアドレスはBluePill内に書き込んでいます。Webブラウザでアクセスして変更が可能です。
折角『STM32MINIShield』を噛ませるのであれば、キーマップモジュールを用意して直接音声を選択出来る様な物を検討しても良いかと思います。
LED&KEYで採用されているchip、TM-1638は24個のタクトスイッチをスキャンできるように設計されています。
実際に24個タクトスイッチが搭載されたモジュールもあるのですが流通していません。
流通している物だと16個のタクトスイッチが搭載されて200円程度で提供されているQYF-TM1638があります。これを使用して16曲をダイレクトに選曲できるように出来ます。
ライブラリはhttps://github.com/rjbatista/tm1638-libraryがそのまま使える様です。オブジェクト自体はベクター殿のストレージをお借りしています。
https://www.vector.co.jp/soft/winnt/hardware/se514018.html
https://www.vector.co.jp/soft/winnt/hardware/se514019.html出来る事は、
- LabVIEW2014開発環境(32bit)環境で独自のアプリケーション開発が出来ます。
免責事項
本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。
商標・登録商標
Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。