06.picoでwifiデモ動作 C言語
06.picoでwifiデモ動作 C言語
Pico ESP8266
https://www.waveshare.com/wiki/Pico-ESP8266
のデモ動作の続きです。前回はATコマンドを手入力して確認しましたが、今回は上記の下側にあるExamples > Demo code のC言語で確認します。
IPとPortの設定
cppファイルでのIPとPortの設定値を以下にしました。tcp_server.cpp
・Port = 333・受信データが有ればそのまま返信します。
tcp_client.cpp
・Server(PC) = 192.168.68.60:8080・Serverへ2行送り、その後送られて来た文字をそのまま返信します。
udp.cpp
・remote(PC) = 192.168.68.60:50000・local_Port(ESP8266) = 51000
・動作はほぼ、Clientと同じ。
picoへ転送
build内の各ホルダに出来たuf2ファイルをpicoへコピーします。詳細は今までの内容を参照してください。各動作
tcp_server
・ESP8266とシリアルポート接続のTera Termに表示された内容です。(一部空白行は削除しました)AT
OK
AT+CWMODE=3
OK
AT+CWJAP="*****","*****" ←*に修正しました
WIFI DISCONNECT
WIFI CONNECTED
WIFI GOT IP
OK
AT+CIPMUX=1
OK
AT+CIPSERVER=1,333
OK
AT+CIFSR
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"46:17:93:04:8c:ae"
+CIFSR:STAIP,"192.168.68.61"
+CIFSR:STAMAC,"44:17:93:04:8c:ae"
OK
と表示されます。以上でESP8266(Server)の設定等が終わったので、前回使用したヘラクレスを起動します。TCP Client タブで
Module IP = 192.168.68.61, Port = 333に設定 > Connectボタンを押します。PCから
123456
と入力してSendボタン を押すと、Tera Term (ESP8266)側に
Recv 6 bytes
SEND OK
と表示され、ヘラクレス(PC)側に
123456
と受信表示されます。再度PCから送ることもできます。
tcp_client
まず、PC側にTCP Serverを起動しておきます。ヘラクレスにて、TCP ServerのタブをPort = 8080に設定し、Listenボタンを押します。
ESP8266を起動すると、ESP8266側のTera Term画面に、
AT
OK
AT+CWMODE=3
OK
AT+CWJAP="*****","*****" ←*に修正しました。
WIFI DISCONNECT
WIFI CONNECTED
WIFI GOT IP
OK
AT+CIFSR
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"46:17:93:04:8c:ae"
+CIFSR:STAIP,"192.168.68.61"
+CIFSR:STAMAC,"44:17:93:04:8c:ae"
OK
AT+CIPSTART="TCP","192.168.68.60",8080
CONNECT
OK
AT+CIPMODE=1
OK
AT+CIPSEND
OK
>
と表示され、Server(PC)のヘラクレスの受信欄に
Hello World !!!
ESP8266 TCP Client
と表示されます。ヘラクレスの送信欄に
123456 Sendボタンで
ESP8266のTera Term画面に
123456
と表示され、ESP8266はそのまま返信し、ヘラクレスの受信欄に
123456
と表示されます。
udp
ESP8266を起動すると、ESP8266側のTera Term画面に、AT
OK
AT+CWMODE=3
OK
AT+CWJAP="*****","*****" ←*に修正しました。
WIFI DISCONNECT
WIFI CONNECTED
WIFI GOT IP
OK
AT+CIFSR
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"46:17:93:04:8c:ae"
+CIFSR:STAIP,"192.168.68.61"
+CIFSR:STAMAC,"44:17:93:04:8c:ae"
OK
AT+CIPSTART="UDP","192.168.68.60",50000,51000,0
CONNECT
OK
AT+CIPMODE=1
OK
AT+CIPSEND
OK
>
と表示されます。ヘラクレスにて、UDPのタブを
Module IP(ESP8266) = 192.168.68.61, Port = 51000, Local port(PC) = 50000に設定し、Listenボタンを押します。
ヘラクレスのSent data欄に
7(CR無し)
と入力すると、Tera Term画面に
7
と表示され、ヘラクレスの受信欄にも
7
と表示されます。また、ヘラクレスのSend欄に
99999 Sendボタン
と押すと、Tera Term画面に
99999
と表示され、ESP8266はそのまま返信し、ヘラクレスの受信欄に先の続きに
99999
と表示されます。
ホルダの構成
[wifiDemo]├CMakeLists.txt (1)
├example_auto_set_url.make
├pico_sdk_import.make
├[tcp_client]
│ ├tcp_client.cpp
│ └CMakeLists.txt (2)
├[tcp_server]
│ ├tcp_server.cpp
│ └CMakeLists.txt (3)
└[udp]
├upd.cpp
└CMakeLists.txt (4)
(1)CMakeLists.txt
cmake_minimum_required(VERSION 3.12)include(pico_sdk_import.cmake)
project(pico_examples C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR})
pico_sdk_init()
include(example_auto_set_url.cmake)
add_subdirectory(tcp_client)
add_subdirectory(tcp_server)
add_subdirectory(udp)
(2)tcp_client\CMakeLists.txt
add_executable(tcp_client tcp_client.cpp)target_link_libraries(tcp_client pico_stdlib)
pico_enable_stdio_usb(tcp_client 1)
pico_enable_stdio_uart(tcp_client 0)
pico_add_extra_outputs(tcp_client)
example_auto_set_url(tcp_client)
(3)tcp_server\CMakeLists.txt
add_executable(tcp_server tcp_server.cpp)target_link_libraries(tcp_server pico_stdlib)
pico_enable_stdio_usb(tcp_server 1)
pico_enable_stdio_uart(tcp_server 0)
pico_add_extra_outputs(tcp_server)
example_auto_set_url(tcp_server)
(4)udp\CMakeLists.txt
add_executable(udp udp.cpp)target_link_libraries(udp pico_stdlib)
pico_enable_stdio_usb(udp 1)
pico_enable_stdio_uart(udp 0)
pico_add_extra_outputs(udp)
example_auto_set_url(udp)
初回のCMakeListsの内容
単一ホルダの時
[test]├test.c ←作る
├CMakeLists.txt ←ファイル名とホルダ名以外同じ(1)
├pico_sdk_import.make ←copy
└[build] ←自動的に出来る
├test.uf2 ←picoにコピーする
└等 ←使用しない
サブホルダの時
[test2]├[test2_sub]
│ ├test.c ←作る
│ └CMakeLists.txt ←ファイル名とホルダ名以外同じ(2)
├CMakeLists.txt ←ファイル名とホルダ名以外同じ(3)
├pico_sdk_import.make ←copyする
└[build] ←自動的に出来る
├[test2_sub]
│ ├test.uf2 ←picoにコピーする
│ └等 ←使用しない
└等 ←使用しない
(1)のCMakeLists.txt
#CMakeの必要最小限のバージョンを設定cmake_minimum_required(VERSION 3.12) #(3)と同じ
#公式の cmake を読込む。(プロジェクトの前に置く)
include(pico_sdk_import.cmake)
#プロジェクト名(project1)と言語を設定
project(project1 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
#SDKを初期化。Pico用環境を読込む
pico_sdk_init() #ここまで(3)と同じ
#実行ファイル(test)を作成するために test.c を読込む
add_executable(test test.c) #以下(2)と同じ
#一般的に使用される機能を集約するpico_stdlibをプル
target_link_libraries(test pico_stdlib)
#USB出力は有効、UART出力は無効
pico_enable_stdio_usb(test 1)
pico_enable_stdio_uart(test 0)
#map,bin,hex,uf2等を作成
pico_add_extra_outputs(test)
(2)のCMakeLists.txt
* (1)の下部と同じadd_executable(test test.c)
target_link_libraries(test pico_stdlib)
pico_enable_stdio_usb(test 1)
pico_enable_stdio_uart(test 0)
pico_add_extra_outputs(test)
(3)のCMakeLists.txt
* (1)の上部とほぼ同じcmake_minimum_required(VERSION 3.12)
include(pico_sdk_import.cmake)
project(project1 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
add_subdirectory(test2_sub) #サブディレクトリ追加
参考
CMakeリファレンスドキュメントhttps://cmake.org/cmake/help/latest/index.html#
ファイル
"*****"は、自分のssidとそのパスワードです。tcp_server.cpp
// 1 デモ tcp_server.cpp
#include <stdio.h> // 入出力ユーティリティ
#include "pico/stdlib.h" // picoの一般ユーティリティ
#include "hardware/uart.h" // UARTを使用
#include <string.h> // strstr,strcpyを使用
#include <stdlib.h> // 一般ユーティリティ
#define UART_ID uart0 // 使用pinによりuart0と1がある
#define BAUD_RATE 115200 // ボーレート
#define UART_TX_PIN 0 // UART_TxにGP0(1番pin)を使用
#define UART_RX_PIN 1 // UART_RxにGP1(2番pin)を使用
char SSID[] = "*****"; // 自分のwifiのSSID
char password[] = "*****"; // wifiのパスワード
char Port[] = "333"; // ESP8266
char s[50]=""; // 文字列作成用
char buf[100] = {0}; // コマンド送信文字列
char rbuf[100] = {0}; // 受信文字列
int ID; // 接続ID
bool sendCMD(const char * cmd,const char * act,int timeout=2000) {//コマンド送信関数
int i=0; // 文字数変数
uint64_t t = 0; // タイムスタンプ値(uS)用変数
uart_puts(UART_ID, cmd); // cmdを送信
uart_puts(UART_ID, "\r\n"); // CRとLFを送信
t = time_us_64(); // 現在のタイムスタンプ値(uS)
while(time_us_64() - t < timeout*1000){ // 2秒内の動作
while(uart_is_readable_within_us(UART_ID,2000)){
buf[i++] = uart_getc(UART_ID);
} // Rxが無くなるまで1文字最大2mS待ち読取る
if(i>0){ // 文字以上有ったら
buf[i]='\0'; // ufに終端文字追加
printf("%s\r\n",buf); // bufを表示
if(strstr(buf,act) != NULL){ // bufにactが有れば
return true; // 戻り値 true(1)
}else{ // bufにactが無ければ
i=0; // 文字数変数初期化
}
}
}
//printf("false\r\n");
return false; // 戻り値 false(0)
}
void sendData(int ID,const char *data){//データ送信関数
char tmp[20] = {0}; // 送信コマンド文字列
sprintf(tmp,"AT+CIPSEND=%d,%d",ID,strlen(data));//文字列作成
if(sendCMD(tmp,">")){ // コマンドを送信しokなら
uart_puts(UART_ID, data); // data送信
}
}
bool ReceiveData() { // データ受信関数
int i=0; // 文字数変数
while(uart_is_readable_within_us(UART_ID,2000)){
rbuf[i++] = uart_getc(UART_ID);
} // Rxが無くなるまで1文字最大2mS待ち読取る
if(i>0){ // 1文字以上有ったら
rbuf[i]='\0'; // rbufに終端文字追加
printf("%s\r\n",rbuf); // rbufを表示
char *p1 = strstr(rbuf,"+IPD"); // 文字列検索
if(p1 != NULL){ // "+IPD"が有れば
char *p2 = strstr(p1+5,","); // 文字列検索
*p2='\0'; // 終端文字追加
ID = atoi(p1+5); // IDの文字列→int
char *p3 = strstr(p2+1,":"); // 文字列検索
strcpy(rbuf,p3+1); // :の次からコピー
//printf("ID=%d, Data=%s\r\n",ID,rbuf);
return true; // 戻り値 true(1)
}
}
return false; // 戻り値 false(0)
} // 受信データから送信IDと送信用文字列を抜き出す
int main() {
stdio_init_all(); // 標準stdio型を初期化
sleep_ms(1000); // 1秒待つ
sleep_ms(1000);
sleep_ms(1000);
sleep_ms(1000);
sleep_ms(1000); // 計5秒待つ
uart_init(UART_ID, BAUD_RATE); // (uart0or1,ボーレート)
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);//GPIO機能選択(GP番号,リストから)
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); // 上と同じ
uart_puts(UART_ID, "+++"); // +++を送信
sleep_ms(1000); // 1秒待つ
while(uart_is_readable(UART_ID))uart_getc(UART_ID);//読取データがあれば読取る
sendCMD("AT","OK"); // AT起動の確認
sendCMD("AT+CWMODE=3","OK"); // WiFiモード 両方に設定
sprintf(s,"AT+CWJAP=\"%s\",\"%s\"",SSID,password);//文字列作成
sendCMD(s,"OK",20000); // SSIDに接続
sendCMD("AT+CIPMUX=1","OK"); // 複数接続の設定
sprintf(s,"AT+CIPSERVER=1,%s",Port); // 文字列作成
sendCMD(s,"OK"); // サーバー作成
sendCMD("AT+CIFSR","OK"); // IPアドレスを確認
while (true) { // 永久ループ
while(ReceiveData()){ // データ受信関数
sendData(ID,rbuf); // データ送信関数
}
}
}
tcp_client.cpp
// 2 デモ tcp_client.cpp
#include <stdio.h> // 入出力ユーティリティ
#include "pico/stdlib.h" // picoの一般ユーティリティ
#include "hardware/uart.h" // UARTを使用
#include <string.h> // strstrを使用
#define UART_ID uart0 // 使用pinによりuart0と1がある
#define BAUD_RATE 115200 // ボーレート
#define UART_TX_PIN 0 // UART_TxにGP0(1番pin)を使用
#define UART_RX_PIN 1 // UART_RxにGP1(2番pin)を使用
char SSID[] = "*****"; // 自分のwifiのSSID
char password[] = "*****"; // wifiのパスワード
char ServerIP[] = "192.168.68.60"; // PC
char Port[] = "8080"; // PC
char s[50]=""; // 文字列作成用
char buf[100] = {0}; // 送信文字列
bool sendCMD(const char * cmd,const char * act,int timeout=2000) {//コマンド送信関数
int i=0; // 文字数変数
uint64_t t = 0; // タイムスタンプ値(uS)変数
uart_puts(UART_ID, cmd); // cmdを送信
uart_puts(UART_ID, "\r\n"); // CRとLFを送信
t = time_us_64(); // 現在のタイムスタンプ値(uS)
while(time_us_64() - t < timeout*1000){ // 2秒内の動作
while(uart_is_readable_within_us(UART_ID,2000)){
buf[i++] = uart_getc(UART_ID);
} // Rxが無くなるまで1文字最大2mS待ち読取る
if(i>0){ // 1文字以上有ったら
buf[i]='\0'; // bufに終端文字追加
printf("%s\r\n",buf); // bufを表示
if(strstr(buf,act) != NULL){ // bufにactが有れば
return true; // 戻り値 true(1)
}else{ // bufにactが無ければ
i=0; // 文字数変数初期化
}
}
}
//printf("false\r\n");
return false; // 戻り値 false(0)
}
int main() {
stdio_init_all(); // 標準stdio型を初期化
sleep_ms(1000); // 1秒待つ
sleep_ms(1000);
sleep_ms(1000);
sleep_ms(1000);
sleep_ms(1000); // 計5秒待つ
uart_init(UART_ID, BAUD_RATE); // (uart0or1,ボーレート)
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);//GPIO機能選択(GP番号,リストから)
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);//上と同じ
uart_puts(UART_ID, "+++"); // +++を送信
sleep_ms(1000); // 1秒待つ
while(uart_is_readable(UART_ID))uart_getc(UART_ID);//読取るデータがあれば読取ります
sendCMD("AT","OK"); // AT起動の確認
sendCMD("AT+CWMODE=3","OK"); // WiFiモード 両方に設定
sprintf(s,"AT+CWJAP=\"%s\",\"%s\"",SSID,password);//文字列作成
sendCMD(s,"OK",20000); // SSIDに接続
sendCMD("AT+CIFSR","OK"); // IPアドレスを確認
sprintf(s,"AT+CIPSTART=\"TCP\",\"%s\",%s",ServerIP,Port);//文字列作成
sendCMD(s,"OK",10000); // クライアントとして接続開始
sendCMD("AT+CIPMODE=1","OK"); // 透過送信の設定
sendCMD("AT+CIPSEND",">"); // データを送信開始
uart_puts(UART_ID, "Hello World !!!\r\n"); // 送信
uart_puts(UART_ID, "ESP8266 TCP Client\r\n"); // 送信
int i=0; // 文字数変数
while (true) { // 永久ループ
while(uart_is_readable_within_us(UART_ID,10000)){
buf[i++] = uart_getc(UART_ID);
} // Rxが無くなるまで1文字最大10mS待ち読取る
if(i>0){ // 1文字以上有ったら
buf[i]='\0'; // bufに終端文字追加
printf("%s\r\n",buf); // bufを表示
uart_puts(UART_ID, buf); // bufを送信
i=0; // 文字数変数初期化
}
}
}
udp.cpp
// 3 デモ upd.cpp
#include <stdio.h> // 入出力ユーティリティ
#include "pico/stdlib.h" // picoの一般ユーティリティ
#include "hardware/uart.h" // UARTを使用
#include <string.h> // strstrを使用
#define UART_ID uart0 // 使用pinによりuart0と1がある
#define BAUD_RATE 115200 // ボーレート
#define UART_TX_PIN 0 // UART_TxにGP0(1番pin)を使用
#define UART_RX_PIN 1 // UART_RxにGP1(2番pin)を使用
char SSID[] = "*****"; // 自分のwifiのSSID
char password[] = "*****"; // wifiのパスワード
char remote_IP[] = "192.168.68.60"; // PC
char remote_Port[] = "50000"; // PC
char local_Port[] = "51000"; // ESP8266
char s[50]=""; // 文字列作成用
char buf[100] = {0}; // コマンド送信文字列
char rbuf[100] = {0}; // 受信文字列
bool sendCMD(const char * cmd,const char * act,int timeout=2000) { // コマンド送信関数
int i=0; // 文字数変数
uint64_t t = 0; // タイムスタンプ値(uS)変数
uart_puts(UART_ID, cmd); // cmdを送信
uart_puts(UART_ID, "\r\n"); // CRとLFを送信
t = time_us_64(); // 現在のタイムスタンプ値(uS)
while(time_us_64() - t < timeout*1000){ // 2秒内の動作
while(uart_is_readable_within_us(UART_ID,10000)){
buf[i++] = uart_getc(UART_ID);
} // Rxが無くなるまで1文字最大10mS待ち読取る
if(i>0){ // 1文字以上有ったら
buf[i]='\0'; // bufに終端文字追加
printf("%s\r\n",buf); // bufを表示
if(strstr(buf,act) != NULL){ // bufにactが有れば
return true; // 戻り値 true(1)
}else{ // bufにactが無ければ
i=0; // 文字数変数初期化
}
}
}
printf("false *****\r\n"); // エラー表示
return false; // 戻り値 false(0)
}
int main() {
stdio_init_all(); // 標準stdio型を初期化
sleep_ms(1000); // 1秒待つ
sleep_ms(1000);
sleep_ms(1000);
sleep_ms(1000);
sleep_ms(1000); // 計5秒待つ
uart_init(UART_ID, BAUD_RATE); // (uart0or1,ボーレート)
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);//GPIO機能選択(GP番号,リストから)
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);//上と同じ
uart_puts(UART_ID, "+++"); // +++を送信
sleep_ms(1000); // 1秒待つ
while(uart_is_readable(UART_ID))uart_getc(UART_ID);//読取るデータがあれば読取ります
sendCMD("AT","OK"); // AT起動の確認
sendCMD("AT+CWMODE=3","OK"); // WiFiモード 両方に設定
sprintf(s,"AT+CWJAP=\"%s\",\"%s\"",SSID,password);//文字列作成
sendCMD(s,"OK",20000); // SSIDに接続
sendCMD("AT+CIFSR","OK"); // IPアドレスを確認
sprintf(s,"AT+CIPSTART=\"UDP\",\"%s\",%s,%s,0",remote_IP,remote_Port,local_Port);//文字列作成
sendCMD(s,"OK",10000); // クライアントとして接続開始
sendCMD("AT+CIPMODE=1","OK"); // 透過送信の設定
sendCMD("AT+CIPSEND",">"); // データを送信開始
uart_puts(UART_ID, "Hello World !!!\r\n"); // 送信
uart_puts(UART_ID, "ESP8266 TCP Client\r\n"); // 送信
int i=0; // 文字数変数
while (true) { // 永久ループ
while(uart_is_readable_within_us(UART_ID,10000)){
rbuf[i++] = uart_getc(UART_ID);
} // Rxが無くなるまで1文字最大10mS待ち読取る
if(i>0){ // 1文字以上有ったら
rbuf[i]='\0'; // rbufに終端文字追加
printf("%s\r\n",rbuf); // rbufを表示
uart_puts(UART_ID, rbuf); // rbufを送信
i=0; // 文字数変数初期化
}
}
}