本稿はWIZnet W55RP20チップのC言語チュートリアルの第14回で、公式最新ファームウェアに基づき作成されたコードはすべて実際に検証され、そのまま書き込み実行可能です。
はじめに
前回の実践チュートリアルでは、W55RP20チップのMQTTプロトコル基本通信を完了し、Alibabaクラウドサーバーとのメッセージ送受信を実現しました。本稿では、産業用IoTシナリオに焦点を当て、W55RP20がMQTTプロトコルを介してOneNET IoTプラットフォームと接続し、温度・湿度データを定期的にアップロードする方法を実装します。OneNETプラットフォームのデバイス登録、MQTT接続設定、物モデルデータ形式のパッケージングなどの核心スキルを習得し、産業用デバイスのクラウド接続要件に適合します。
W55RP20はハードウェアTCP/IPプロトコルスタックを統合し、MQTTクライアントライブラリを組み合わせることで、C言語プログラミングによってOneNETプラットフォームとの安定した通信を実現できます。ソケットの詳細を気にする必要はなく、WIZnet公式ドライバーライブラリとOneNET物モデル仕様に依存することで、組み込みデバイスのクラウド接続開発のハードルを大幅に下げ、スマートモニタリング、データ収集などの各種IoTシナリオに適しています。
本稿を学習すると、以下のスキルを習得できます:
- OneNET IoTプラットフォームのデバイス登録、プロダクト作成、およびMQTT接続パラメータの取得方法
- W55RP20とOneNETプラットフォーム接続のC言語実装(完全に実行可能なコード)
- OneNET物モデルJSONペイロードの構築(標準形式の自動パッケージング)
- DNS解像度の最適化、定期的なデータアップロード、ハートビート維持などの安定メカニズムの実装
- OneNETプラットフォームのデータ表示、デバッグ、および一般的な問題のトラブルシューティング方法
シリーズチュートリアル学習パス
本シリーズは全16回で、W55RP20-EVB-PicoモジュールのC言語開発全プロセスを段階的にカバーしています:
- 第1回:静的IP設定とネットワーク基礎
- 第2回:DHCP自動接続とネットワーク診断
- 第3回:TCPクライアント通信
- 第4回:TCPサーバー通信
- 第5回:UDPユニキャスト通信
- 第6回:UDPマルチキャスト/ブロードキャスト通信
- 第7回:DNSドメイン名解決
- 第8回:NTPによるネットワークからの時間取得
- 第9回:HTTPクライアントリクエスト
- 第10回:HTTPサーバー構築
- 第11回:HTTPプロトコルとOneNETプラットフォームデータクラウド接続
- 第12回:MQTTプロトコル基本通信検証
- 第13回:MQTTプロトコルとAlibabaクラウドプラットフォーム連携
- 第14回:MQTTプロトコルとOneNETプラットフォーム連携(本稿)
- 第15回:MQTTプロトコルとThingSpeakプラットフォーム連携
- 第16回:Modbus産業プロトコル通信
目次
- 準備
1.1. ソフトウェア準備 1.2. ハードウェア準備 1.3. OneNETプラットフォーム準備
- W55RP20 C言語開発環境構築
2.1. ドライバーライブラリ設定 2.2. ファームウェア書き込み
- ハードウェア接続とシリアルポート設定
3.1. ハードウェア接続 3.1.1. 基本接続(電源+デバッグ) 3.1.2. イーサネット接続 3.1.3. モジュールと開発ボードの接続(分離式モジュール用) 3.2. シリアルデバッグ設定
- OneNET MQTTプロトコル仕様解説
4.1. 核心接続仕様(必読) 4.2. 物モデルデータ形式仕様 4.3. 標準トピック形式(必須) 4.4. 最小限のワークフロー
- 核心C言語コードのコピーとコンパイル・書き込み
5.1. 依存ライブラリ説明 5.2. 完全なC言語コード(メインプログラム) 5.3. コードの重要設定説明 5.4. コンパイルと書き込み手順
- 実行結果とOneNETプラットフォーム検証
6.1. シリアル出力結果 6.2. OneNETプラットフォームデータ検証
-
一般的な問題のトラブルシューティング
-
W55RP20の核心的優位性比較
-
典型的なアプリケーションシナリオ
-
シリーズ予告とリソース取得
10.1. シリーズ予告 10.2. リソース取得
- 準備
1.1. ソフトウェア準備
必要なソフトウェアはすべて無料バージョンで、ダウンロード・インストールするだけで追加料金は不要です。C言語開発要件に適合し、OneNETプラットフォーム関連操作ツールが追加されています。
| ソフトウェア名 | バージョン要件 | ダウンロード先 | 説明 |
|---|---|---|---|
| VS Code(C/C++プラグイン付き) | 最新安定版 | VS Code公式ダウンロード | 軽量コードエディタ、C言語構文ハイライト、コンパイルデバッグをサポートし、初心者に優しい |
| W55RP20-EVB-PicoモジュールC言語ドライバーライブラリ | 最新安定版 | WIZnet公式ファームウェア/ドライバーライブラリダウンロード | W55RP20-EVB-Picoモジュール専用に作成され、WIZnetハードウェアドライバ、TCP/IPプロトコルスタック、MQTTクライアントライブラリを統合 |
| シリアルデバッグツール(SecureCRTなど) | 任意のバージョン | 公式ダウンロードまたはサードパーティツール | シリアル出力の実行ログ、デバッグ情報の表示に使用し、接続とデータアップロード問題の特定に役立つ |
| OneNET IoTプラットフォーム | オンライン版 | OneNET IoTプラットフォーム公式サイト | プロダクト作成、デバイス登録、MQTT接続パラメータの取得、アップロードされた温度・湿度データの表示に使用 |
1.2. ハードウェア準備
- W55RP20-EVB-Pico × 1
- Micro USBデータケーブル(データ転送をサポートする必要があり、充電専用ケーブルは不可)× 1
- 標準イーサネットケーブル × 1
- DHCP機能を有効にしたルーター/スイッチ × 1(ネットワークパラメータの取得とDNS解像に使用)
1.3. OneNETプラットフォーム準備
コード開発前に、OneNETプラットフォームでプロダクト作成とデバイス登録を完了し、MQTT接続に必要な核心パラメータ(プロダクトID、デバイス名、トークン)を取得する必要があります。手順は以下の通りです:
- OneNET IoTプラットフォームにログイン(アカウント登録が必要、個人版は無料)し、「IoTコアキット」→「プロダクト」に移動し、「プロダクト作成」をクリック;
- プロダクト設定:プロダクト名は任意(例:W55RP20温度・湿度収集)、プロトコルは「MQTT」、データ形式は「JSON」、デバイスタイプは「直接接続デバイス」を選択し、「作成を確認」をクリック;
- デバイス追加:作成したプロダクトに移動し、「デバイス管理」→「デバイス追加」をクリック、デバイス名は任意(例:W5500_01)とし、「確認」をクリックしてデバイス登録を完了;
- 接続パラメータ取得:デバイス詳細ページに移動し、以下の3つの核心パラメータを記録(後でコードに置換):
- プロダクトID(ONENET_PRODUCT_ID):プロダクト詳細ページ上部で取得、文字列形式
- デバイス名(ONENET_DEVICE_NAME):デバイス作成時に任意指定した名前
- トークン(ONENET_MQTT_PASSWORD):パスワード生成ツールを使用:https://open.iot.10086.cn/doc/iot_platform/images/tools/token.exe(注:トークンには有効期限があり、期限切れの場合は再生成が必要)
-
物モデル追加(必須):プロダクトの「物モデル定義」に「temp」(温度、浮動小数点型)と「humi」(湿度、浮動小数点型)の2つの属性を追加し、フィールド名はコード内と一致させる必要があります(プラットフォームで温度・湿度データを直感的に確認するため)。
-
W55RP20 C言語開発環境構築
2.1. ドライバーライブラリ設定
- W55RP20公式C言語ドライバーライブラリをダウンロードし、解凍して核心ファイル(wizchip_conf.h、socket.h、mqtt_interface.h、MQTTClient.hなどを含む)を取得;
- VS Codeを開き、新規プロジェクトを作成し、ドライバーライブラリのヘッダファイル(.h)をプロジェクトのincludeフォルダに、ソースファイル(.c)をsrcフォルダに配置;
- プロジェクトのコンパイルオプションを設定し、コンパイラ(ARM GCCなど)を指定し、ドライバーライブラリファイルを関連付け、コンパイル時にハードウェアドライバ、ネットワークインターフェース、MQTT関連関数を正常に呼び出せるようにする。
2.2. ファームウェア書き込み
W55RP20-EVB-PicoモジュールはラズベリーパイPicoのUF2ファームウェア書き込み方式に完全互換で、追加の書き込みデバイスが不要なため操作が簡単で、初心者でもすぐに使いこなせます:
-
RP2040開発ボードのBOOTSELボタンを押し続ける;
-
Micro USBデータケーブルで開発ボードとPCを接続;
-
PCがRPI-RP2という名前のUSBドライブとして認識されたら、BOOTSELボタンを離す;
-
コンパイルで生成されたUF2ファームウェアファイルをUSBドライブにドラッグ&ドロップ;
-
開発ボードが自動的に再起動し、ファームウェア書き込みが完了。
-
ハードウェア接続とシリアルポート設定
3.1. ハードウェア接続
W55RP20-EVB-Picoモジュールの接続は、電源/デバッグとイーサネット接続の2段階で行い、操作は簡単で複雑な配線は不要です。基本MQTT実践接続方式と同じです:
3.1.1. 基本接続(電源+デバッグ)
Micro USBデータケーブルでRP2040開発ボードとPCを接続し、開発ボードの電源供給、ファームウェア書き込み、シリアルデバッグに使用します。
3.1.2. イーサネット接続
イーサネットケーブルでW55RP20-EVB-PicoモジュールのイーサネットインターフェースとルーターのLANポート(またはPCのネットワークポートに直接接続、PCのIPを開発ボードと同じセグメントに手動設定する必要あり)を接続します。
3.1.3. モジュールと開発ボードの接続(分離式モジュール用)
分離式モジュールと開発ボードを使用する場合は、以下のピン対応で接続します(SPI通信):
【ハードウェア予約】ここにハードウェア接続図を挿入
3.2. シリアルデバッグ設定
VS Codeのシリアルデバッグツールを開き、以下のパラメータで設定し、開発ボードの実行ログとデバッグ情報を確認し、OneNET MQTT接続とデータアップロード問題の特定に使用します:
- ボーレート:115200
- データビット:8
- ストップビット:1
- パリティビット:なし
- フロー制御:なし
- 開発ボード対応のシリアルポート(通常COMxと表示)を選択し、「シリアルポートを開く」をクリック。
- OneNET MQTTプロトコル仕様解説
OneNETプラットフォームはMQTT 3.1.1プロトコルを使用します(コード内の設定と一致)、パブリッシュ/サブスクライブモデルに基づいてデバイスとプラットフォームの双方向通信を実現します。パブリックMQTTサーバーと比較した場合、核心的な違いは接続認証が厳格であり、物モデルデータ形式が標準化されている点です。これらが開発の重点と難点です。
4.1. 核心接続仕様(必読)
- MQTTバージョン:3.1.1バージョンを使用する必要があります(コード内ではMQTTVersion = 4と設定)、OneNETプラットフォームと完全互換;
- サーバーアドレス:固定で「studio-mqtt.heclouds.com」(OneNET MQTT公式ドメイン)、地域パラメータの変更は不要;
- ポート:1883を使用(非暗号化ポート、開発・デバッグに適用;本番環境では8883暗号化ポートを使用可能);
- 接続パラメータ:ClientID=デバイス名、Username=プロダクトID、Password=プラットフォーム生成のトークン、3つは厳密に一致させる必要があり、不一致の場合は接続に失敗します。
4.2. 物モデルデータ形式仕様
OneNETプラットフォームは、デバイスがアップロードするデータを指定されたJSON形式にする必要があります。核心にはid、version、paramsの3つのフィールドが含まれます。例は以下の通り:
{ "id":"123456789", "version":"1.0", "params":{ "temp":{ "value":35.7 }, "humi":{ "value":60.2 } } }
説明:
- id:ランダム数またはタイムスタンプ、メッセージを識別し、重複を避けるために使用、コード内で自動生成;
- version:「1.0」に固定、物モデルデータ形式のバージョンを表す;
- params:デバイスがアップロードする具体的なデータ、フィールド名(temp、humi)はOneNET物モデルで定義された属性名と一致する必要があり、valueは具体的な数値;
- timeフィールドは手動で追加する必要はなく、コード内で最小限の形式に最適化され、プラットフォームの正常な解析が保証されます。
4.3. 標準トピック形式(必須)
OneNET物モデル通信では固定トピックを使用する必要があり、カスタマイズは不要です。プロダクトIDとデバイス名を置換するだけです:
- 属性報告トピック(デバイス→プラットフォーム):$sys/プロダクトID/デバイス名/thing/property/post
- 報告応答トピック(プラットフォーム→デバイス):$sys/プロダクトID/デバイス名/thing/property/post/reply
コード内ではトピック形式がカプセル化されており、プロダクトIDとデバイス名を置換するだけで、手動で連結する必要はありません。
4.4. 最小限のワークフロー
-
W55RP20はDNS解像を介してOneNET MQTTサーバードメインを解決し、サーバーIPを取得;
-
OneNETプラットフォーム提供のプロダクトID、デバイス名、トークンを使用してMQTT接続を確立;
-
W55RP20はOneNET物モデル仕様に従って温度・湿度データ(JSON形式)をパッケージ化し、報告トピックにデータを公開;
-
OneNETプラットフォームはデータを受信し、デバイス詳細ページにリアルタイムの温度・湿度データを表示し、同時に応答トピックに確認メッセージを送信し、デバイスは受信して印刷。
-
核心C言語コードのコピーとコンパイル・書き込み
5.1. 依存ライブラリ説明
核心的な依存関係はWIZnet公式ドライバーライブラリ(wizchip_conf.h、socket.h、mqtt_interface.h、MQTTClient.hなどを含む)で、W55RP20ハードウェアの初期化、ネットワーク接続、DNS解像、MQTTクライアントの接続、公開、サブスクライブなどの基础機能の実現に使用されます。OneNET専用ライブラリの追加は不要で、コード内に接続設定、物モデルJSONパッケージング、メッセージコールバックロジックが統合されており、プロジェクトに直接関連付けて使用できます。
5.2. 完全なC言語コード(メインプログラム)
以下のコードをVS Codeプロジェクトのメインファイル(例:main.c)にコピーし、OneNETプラットフォームから取得した接続パラメータを重点的に置換します。コンパイルしてUF2ファームウェアを生成し、開発ボードに書き込みます。コードのコメントは明確で、重要な設定部分はマーキングされており、直接修正できます。
/**
Copyright (c) 2021 WIZnet Co.,Ltd
Modified for W55RP20 with OneNET MQTT (optimized version)
SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "port_common.h"
#include "wizchip_conf.h"
#include "wizchip_spi.h"
#include "mqtt_interface.h"
#include "MQTTClient.h"
#include "timer.h"
#include "time.h"
#include "dns.h"
/* バッファ */
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
/* ソケット */
#define SOCKET_MQTT 0
#define SOCKET_DNS 3
/* ポート */
#define PORT_MQTT 1883
/* タイムアウト */
#define DEFAULT_TIMEOUT 1000
/* ========== OneNET設定(実際に合わせて修正)========== */
#define ONENET_PRODUCT_ID "ZGB6zBD0nS" // プロダクトID
#define ONENET_DEVICE_NAME "sensor_device" // デバイス名
// MQTTパスワード(トークン)、OneNETデバイス詳細ページからコピー、有効期限に注意
#define ONENET_MQTT_PASSWORD "version=2018-10-31&res=products%2FZGB6zBD0nS%2Fdevices%2Fsensor_device&et=1780016971&method=md5&sign=AAMTeit90OTmwPpugN%2Fe%2Bg%3D%3D"
#define ONENET_MQTT_DOMAIN "studio-mqtt.heclouds.com" // OneNET MQTTサーバードメイン
/* 物モデルトピック */
#define PROPERTY_POST_TOPIC "$sys/" ONENET_PRODUCT_ID "/" ONENET_DEVICE_NAME "/thing/property/post"
#define PROPERTY_POST_REPLY_TOPIC "$sys/" ONENET_PRODUCT_ID "/" ONENET_DEVICE_NAME "/thing/property/post/reply"
/* 温度・湿度データ(シミュレーション値、実際のセンサーに置換可能) */
#define TEMP_READING 42.3
#define HUMI_READING 65.7
/* 公開周期(ミリ秒) */
#define MQTT_PUBLISH_INTERVAL (1000 * 15)
#define MQTT_KEEP_ALIVE 60
/* ========== ネットワーク設定(実際の環境に合わせて修正)========== */
static wiz_NetInfo network_config = {
.mac = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
.ip = {192, 168, 1, 110},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 1, 1},
.dns = {223, 5, 5, 5},
#if _WIZCHIP_ > W5500
.lla = {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0xdc, 0xff, 0xfe, 0x57, 0x57, 0x25},
.gua = {0},
.sn6 = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.gw6 = {0},
.dns6 = {0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88},
.ipmode = NETINFO_STATIC_ALL
#else
.dhcp = NETINFO_STATIC
#endif
};
/* DNS解像結果保存 */
static uint8_t mqtt_server_ip[4] = {0};
/* MQTT関連変数 */
static uint8_t mqtt_tx_buffer[ETHERNET_BUF_MAX_SIZE] = {0};
static uint8_t mqtt_rx_buffer[ETHERNET_BUF_MAX_SIZE] = {0};
static Network mqtt_network;
static MQTTClient mqtt_client;
static MQTTPacket_connectData mqtt_connect_data = MQTTPacket_connectData_initializer;
static MQTTMessage mqtt_message;
static volatile uint32_t system_millis = 0;
/* DNS解像用バッファ */
static uint8_t dns_query_buffer[ETHERNET_BUF_MAX_SIZE] = {0};
/* 関数宣言 */
static void timer_callback(void);
static uint32_t get_system_millis(void);
static void create_onenet_data_package(char *data, int max_size, float temp, float humi);
static int resolve_domain(const char *domain, uint8_t *ip_address);
static void handle_incoming_message(MessageData *msg_data);
/**
* @brief DNSドメイン名解像関数
*/
static int resolve_domain(const char *domain_name, uint8_t *ip_addr)
{
int8_t result = 0;
uint8_t dns_server_ip[4];
dns_server_ip[0] = network_config.dns[0];
dns_server_ip[1] = network_config.dns[1];
dns_server_ip[2] = network_config.dns[2];
dns_server_ip[3] = network_config.dns[3];
if (dns_server_ip[0] == 0 && dns_server_ip[1] == 0 && dns_server_ip[2] == 0 && dns_server_ip[3] == 0) {
dns_server_ip[0] = network_config.gw[0];
dns_server_ip[1] = network_config.gw[1];
dns_server_ip[2] = network_config.gw[2];
dns_server_ip[3] = network_config.gw[3];
printf("DNS: ゲートウェイをDNSサーバーとして使用 %d.%d.%d.%d\n", dns_server_ip[0], dns_server_ip[1], dns_server_ip[2], dns_server_ip[3]);
} else {
printf("DNS: DNSサーバーを使用 %d.%d.%d.%d\n", dns_server_ip[0], dns_server_ip[1], dns_server_ip[2], dns_server_ip[3]);
}
printf("DNS: ドメイン解像中: %s\n", domain_name);
DNS_init(SOCKET_DNS, dns_query_buffer);
result = DNS_run(dns_server_ip, (uint8_t *)domain_name, ip_addr);
if (result == 1) {
printf("DNS: 成功!IP: %d.%d.%d.%d\n", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]);
return 0;
} else {
printf("DNS: 失敗!エラー: %d\n", result);
return -1;
}
}
/**
* @brief OneNET物モデルJSONデータ構築(余分なスペースなし、timeフィールドなし)
*/
static void create_onenet_data_package(char *payload, int max_len, float temp, float humi) {
snprintf(payload, max_len,
"{\"id\":\"%lu\",\"version\":\"1.0\",\"params\":{\"temp\":{\"value\":%.1f},\"humi\":{\"value\":%.1f}}}",
(unsigned long)get_system_millis(), temp, humi);
}
/* タイマーコールバック */
static void timer_callback(void) {
system_millis++;
MilliTimer_Handler();
}
/* ミリ秒取得 */
static uint32_t get_system_millis(void) {
return system_millis;
}
/* メッセージ受信コールバック(応答トピックをサブスクライブ) */
static void handle_incoming_message(MessageData *msg_data) {
MQTTMessage *msg = msg_data->message;
printf("応答受信: トピック=%.*s, ペイロード=%.*s\n",
msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data,
(int)msg->payloadlen, (char*)msg->payload);
}
/**
* @brief メイン関数
*/
int main() {
int32_t return_value = 0;
uint32_t last_publish_time = 0;
uint32_t current_time = 0;
char data_package[256];
stdio_init_all();
sleep_ms(3000);
printf("\r\n=== W55RP20 OneNET MQTTデモ(最適化版) ===\r\n");
wizchip_spi_initialize();
wizchip_cris_initialize();
wizchip_reset();
wizchip_initialize();
wizchip_check();
wizchip_1ms_timer_initialize(timer_callback);
network_initialize(network_config);
print_network_information(network_config);
/* DNS解像 */
printf("\n--- DNS解像フェーズ ---\n");
int dns_retry_count = 0;
while (resolve_domain(ONENET_MQTT_DOMAIN, mqtt_server_ip) != 0) {
dns_retry_count++;
if (dns_retry_count >= 3) {
printf("3回の試行後DNS解像に失敗しました!\n");
while (1);
}
printf("3秒後にリトライ %d...\n", dns_retry_count);
sleep_ms(3000);
}
/* TCP接続 */
NewNetwork(&mqtt_network, SOCKET_MQTT);
printf("OneNET MQTTブローカーに接続中 %d.%d.%d.%d:%d...\n",
mqtt_server_ip[0], mqtt_server_ip[1],
mqtt_server_ip[2], mqtt_server_ip[3], PORT_MQTT);
return_value = ConnectNetwork(&mqtt_network, mqtt_server_ip, PORT_MQTT);
if (return_value != 1) {
printf("ネットワーク接続に失敗!戻り値=%d\n", return_value);
while (1);
}
printf("ネットワーク接続完了。\n");
/* MQTT初期化 */
MQTTClientInit(&mqtt_client, &mqtt_network, DEFAULT_TIMEOUT,
mqtt_tx_buffer, ETHERNET_BUF_MAX_SIZE,
mqtt_rx_buffer, ETHERNET_BUF_MAX_SIZE);
/* 重要:MQTTプロトコルバージョン 4 = 3.1.1 */
mqtt_connect_data.MQTTVersion = 4;
mqtt_connect_data.cleansession = 1;
mqtt_connect_data.willFlag = 0;
mqtt_connect_data.keepAliveInterval = MQTT_KEEP_ALIVE;
mqtt_connect_data.clientID.cstring = ONENET_DEVICE_NAME;
mqtt_connect_data.username.cstring = ONENET_PRODUCT_ID;
mqtt_connect_data.password.cstring = ONENET_MQTT_PASSWORD;
printf("OneNETにMQTT接続中...\n");
return_value = MQTTConnect(&mqtt_client, &mqtt_connect_data);
if (return_value < 0) {
printf("MQTT接続に失敗: %d\n", return_value);
while (1);
}
printf("OneNETプラットフォームにMQTT接続完了!\n");
/* 応答トピックのサブスクライブ(エラーメッセージ取得用) */
return_value = MQTTSubscribe(&mqtt_client, PROPERTY_POST_REPLY_TOPIC, QOS0, handle_incoming_message);
if (return_value < 0) {
printf("サブスクライブ警告: %d\n", return_value);
} else {
printf("応答トピックをサブスクライブ: %s\n", PROPERTY_POST_REPLY_TOPIC);
}
sleep_ms(500);
/* QOS0で公開(テストに便利) */
mqtt_message.qos = QOS0;
mqtt_message.retained = 0;
mqtt_message.dup = 0;
last_publish_time = get_system_millis();
/* メインループ */
while (1) {
current_time = get_system_millis();
if (current_time >= last_publish_time + MQTT_PUBLISH_INTERVAL) {
create_onenet_data_package(data_package, sizeof(data_package), TEMP_READING, HUMI_READING);
mqtt_message.payload = data_package;
mqtt_message.payloadlen = strlen(data_package);
printf("トピック: %s\n", PROPERTY_POST_TOPIC);
printf("ペイロード: %s\n", data_package);
return_value = MQTTPublish(&mqtt_client, PROPERTY_POST_TOPIC, &mqtt_message);
if (return_value < 0) {
printf("公開に失敗: %d\n", return_value);
} else {
printf("データ公開完了(QOS0)\n");
}
last_publish_time = get_system_millis();
}
/* Yieldタイムアウト1000ミリ秒、ネットワークパケットの適時処理を確保 */
return_value = MQTTYield(&mqtt_client, 1000);
if (return_value < 0) {
printf("Yieldエラー: %d\n", return_value);
sleep_ms(1000);
}
}
return 0;
}
5.3. コードの重要設定説明
- OneNET MQTTパラメータ(核心的な修正):
- ONENET_PRODUCT_ID:OneNETプラットフォームプロダクト詳細ページから取得したプロダクトIDに置換、文字列形式で文字は変更不可;
- ONENET_DEVICE_NAME:OneNETプラットフォームで作成したデバイス名に置換、プラットフォームと完全一致し、大文字小文字を区別;
- ONENET_MQTT_PASSWORD:OneNETデバイス生成ツールからコピーしたトークンに置換、トークンには有効期限があり、期限切れ後は再生成して置換する必要あり;
- ONENET_MQTT_DOMAIN:「studio-mqtt.heclouds.com」に固定、変更不要;
- 物モデルトピック:コード内で自動連結され、手動で修正する必要はなく、プロダクトIDとデバイス名を置換すると自動的に有効になります。
ネットワーク設定:ルーターの実際のセグメントに合わせてnetwork_configのip、gw、dnsを修正し、ルーターと同じセグメントであることを確認;DNSはAlibabaクラウドDNS(223.5.5.5)の使用を推奨し、解像成功率を向上させます;
MQTTバージョン:コード内では3.1.1バージョン(MQTTVersion = 4)に設定済みで、変更不要、OneNETプラットフォームと互換性があります;
データアップロード周期:MQTT_PUBLISH_INTERVALを15秒に定義(単位:ミリ秒)、要件に応じて修正可能;
温度・湿度データ:現在は固定値(TEMP_READING、HUMI_READING)ですが、実際の開発ではセンサー収集のリアルタイムデータ(例:DHT11、DS18B20)に置換可能です。
5.4. コンパイルと書き込み手順
-
第一步:上記コードをVS Codeプロジェクトのメインファイルにコピーし、WIZnet公式ドライバーライブラリを関連付け(すべてのヘッダファイルが正常に参照され、エラーがないことを確認);
-
第二步:コード内のOneNET MQTTパラメータ、ネットワーク設定を修正し、ファイルを保存;
-
第三步:プロジェクトをコンパイルし、UF2ファームウェアファイルを生成(コンパイルエラーの場合、優先的にドライバーライブラリの関連付けが正しいか、ヘッダファイル名のスペルミスがないかを確認);
-
第四步:前文「ファームウェア書き込み」の手順に従い、UF2ファームウェアをW55RP20開発ボードに書き込み;
-
第五步:シリアルデバッグツールを開き、開発ボードの実行ログを確認し、ネットワーク初期化、DNS解像、MQTT接続の成功を確認;
-
第六步:OneNETプラットフォームにログインし、デバイス詳細ページに移動し、「物モデルデータ」を確認し、温度・湿度データが定期的にアップロードされていることを確認。
-
実行結果とOneNETプラットフォーム検証
6.1. シリアル出力結果
書き込み完了後、開発ボードは自動的に再起動し、シリアルデバッグツールを開くと以下が出力され、ネットワーク初期化、DNS解像、MQTT接続、データアップロードの成功を示します:
---- シリアルポート COM80 を開きました ----
=== W55RP20 OneNET MQTTデモ(最適化版) ===
[PIO SPIクロックスピード : 31.25 MHz] (sys=125.00 MHz)
====================================================================================================
W5500ネットワーク設定 : 静的
MAC : 00:11:22:33:44:55
IP : 192.168.1.110
サブネットマスク : 255.255.255.0
ゲートウェイ : 192.168.1.1
DNS : 223.5.5.5
====================================================================================================
--- DNS解像フェーズ ---
DNS: DNSサーバーを使用 223.5.5.5
DNS: ドメイン解像中: studio-mqtt.heclouds.com
DNS: 成功!IP: 218.201.45.7
OneNET MQTTブローカーに接続中 218.201.45.7:1883...
ネットワーク接続完了。
OneNETにMQTT接続中...
OneNETプラットフォームにMQTT接続完了!
応答トピックをサブスクライブ: $sys/ZGB6zBD0nS/sensor_device/thing/property/post/reply
トピック: $sys/ZGB6zBD0nS/sensor_device/thing/property/post
ペイロード: {"id":"12345","version":"1.0","params":{"temp":{"value":42.3},"humi":{"value":65.7}}}
データ公開完了(QOS0)
トピック: $sys/ZGB6zBD0nS/sensor_device/thing/property/post
ペイロード: {"id":"22346","version":"1.0","params":{"temp":{"value":42.3},"humi":{"value":65.7}}}
データ公開完了(QOS0)
トピック: $sys/ZGB6zBD0nS/sensor_device/thing/property/post
ペイロード: {"id":"32347","version":"1.0","params":{"temp":{"value":42.3},"humi":{"value":65.7}}}
データ公開完了(QOS0)
説明:「DNSリトライ」と表示される場合は正常現象で、最大3回リトライします;常に解像または接続に失敗する場合は、「一般的な問題トラブルシューティング」の部分を参照してください。
6.2. OneNETプラットフォームデータ検証
OneNET IoTプラットフォームにログインし、デバイス詳細ページに移動し、データアップロード状況を確認します。手順は以下の通りです:
- OneNETプラットフォーム「IoTコアキット」→「デバイス管理」に移動し、登録済みデバイスを見つけ、デバイス名をクリックして詳細ページに入る;
- 「物モデルデータ」→「リアルタイムデータ」をクリックすると、温度・湿度データが定期的に更新されているのがわかります(15秒ごと)、シリアル印刷のペイロードデータと一致;
- 「メッセージログ」をクリックすると、デバイス接続、データアップロード、応答メッセージの詳細ログを確認でき、データアップロードに失敗した場合は、ここでエラー原因を確認;
- (任意)「データ可視化」をクリックし、ダッシュボードを作成すると、温度・湿度データの変化傾向を直感的に表示できます。
これで、W55RP20のC言語版MQTTプロトコルとOneNET IoTプラットフォーム連携実践が完了しました!
- 一般的な問題のトラブルシューティング
OneNET連携の特殊性を考慮し、以下に高頻度問題とトラブルシューティング手順を示します。接続パラメータと形式の問題を優先的に確認してください:
| 問題現象 | トラブルシューティング手順 |
|---|---|
| 1. シリアルに印刷がないまたは印刷が乱れている | 1. シリアルパラメータ設定が正しいことを確認(ボーレート115200、パリティなし);2. ファームウェアがW55RP20専用C言語ファームウェアであること;3. ファームウェアを再書き込みし、USBデータケーブルがデータ転送をサポートしていることを確認。 |
| 2. DNS解像に失敗し、エラーが表示される | 1. DNSアドレスが正しいことを確認(AlibabaクラウドDNS:223.5.5.5の使用を推奨);2. ルーターが正常に接続できることを確認;3. OneNET MQTTサーバードメインのスペルが正しいことを確認;4. ルーターと開発ボードを再起動。 |
| 3. MQTT接続に失敗し、戻り値が負数 | 1. TCP接続が成功していることを確認(シリアル印刷の「ネットワーク接続完了」メッセージを確認);2. MQTTバージョンが3.1.1であることを確認(コード内で設定済み、変更不要);3. プロダクトID、デバイス名、トークンがOneNETプラットフォームと一致し、スペルミスがないことを確認;4. トークンが期限切れでないことを確認、期限切れの場合は再生成が必要。 |
| 4. OneNETに接続できるが、データをアップロードできない | 1. 報告トピック形式が正しいことを確認し、プロダクトIDとデバイス名が置換されていること;2. JSONペイロード形式が正しいことを確認し、構文エラーがないこと(シリアル印刷のペイロードをJSON検証ツールにコピーして検証可能);3. OneNET物モデルでの属性名がペイロードのフィールド名と一致すること(temp、humi、大文字小文字を区別)。 |
- W55RP20の核心的優位性比較
W55RP20の価値をより直感的に理解するため、現在主流の3つの組み込みイーサネットソリューションを比較します:
| 比較項目 | W55RP20統合ソリューション | 外部PHYチップソリューション | 外部シリアル変イーサネットモジュールソリューション |
|---|---|---|---|
| BOMコスト | 低(単チップ) | 中高(MCU + モジュール + 周辺デバイス) | 高 |
| PCB面積 | 小(イーサネット回路のみ) | 大(チップと配線スペースの確保が必要) | 高 |
| 開発難易度 | 低(公式ドライバーライブラリ、1行でネットワーク接続) | 中高(プロトコルスタックのデバッグ、ドライバ作成) | 低 |
| ネットワーク安定性 | 極めて高い(WIZnetが25年間専門でハードウェアTCP/IPプロトコルスタックを開発) | 不安定(開発者に高い要求、プロトコルスタックとネットワーク開発の知識が必要で、安定性をデバッグする必要がある) | 不安定(開発会社の能力レベルによる) |
| CPUリソース使用率 | 0%(プロトコルスタックのネットワーク処理は完全にハードウェアで実行) | 50%以上(プロトコルスタックは完全にMCU上で実行され、関連リソースを消費) | 0% |
| ハードウェアソケット数 | 8つの独立したハードウェアソケット | MCUの能力に依存、理論的に多路拡張をサポート | 一般的に単透伝 |
| ネットワークスループット | 最大15Mbps | MCUの能力に依存 | 約3-5Mbps |
| インターフェース易用性 | 単チップ統合 | MCUがMII/RMIIなどのインターフェースを必要とする | TTLインターフェース |
| デプロイ難易度 | 低(公式C言語ドライバーライブラリが成熟し、アプリケーション層プロトコルが適応され、柔軟にデプロイ可能) | 高(アプリケーション層プロトコルはオープンソースライブラリの手動移植が必要) | モジュール統合状況に依存、統合されていない機能は自己パッケージング・アンパッケージングが必要 |
- 典型的なアプリケーションシナリオ
W55RP20チップはイーサネット機能を統合しており、その産業レベルの安定性により、以下のアプリケーションシナリオに非常に適しています:
-
産業データ収集ゲートウェイ:現場配置を簡素化し、センサーデータの安定したアップロードを実現
-
リモートモニタリングターミナル:工場、サーバールーム、変電所などの環境のデバイス状態リモートモニタリングに使用
-
シリアル変イーサネットデバイス:従来のRS232/RS485シリアルデバイスを迅速にイーサネットデバイスにアップグレード
-
スマートビルディングノード:照明、空調、ドアロックなどのビルディングデバイスのネットワーク制御に使用
-
産業PLC拡張モジュール:PLCにイーサネット通信能力を追加し、リモートプログラミングとデータ収集を実現
-
シリーズ予告とリソース取得
10.1. シリーズ予告
次回のチュートリアルでは、W55RP20 C開発におけるMQTT+ThingSpeakによるデータアップロードを実装します。接続確立、ハートビート維持、異常再接続などの核心メカニズムを理解し、組み込みイーサネット通信の基礎能力を習得します。
10.2. リソース取得
本稿の完全コード:WIZnet公式Giteeリポジトリ W55RP20チップマニュアル:WIZnet公式資料サイト