เมื่อไม่นานนี้ Raspberry Pi Trading เปิดตัวบอร์ด Raspberry Pi Pico W โดยออกแบบเหมือนกับ บอร์ด Raspberry Pi Pico รุ่นเดิม ทั้งคู่มาพร้อมกับไมโครคอนโทรลเลอร์ RP2040 dual-core Cortex-M0+ แต่เพิ่ม Pico W เพิ่มโมดูล Wireless รองรับการเชื่อมต่อ WiFi 4 และ Bluetooth LE 5.2 (แต่ไม่ได้เปิดใช้งาน Bluetooth ในขณะนี้ และคาดว่าจะเปิดใช้งานในอนาคตต่อไป)
บริษัทได้ส่ง Raspberry Pi Pico W เพื่อทดสอบ/ประเมินผล ในบทความนี้ และฉันจะเน้นการทดสอบที่เกี่ยวข้องกับ WiFi เนื่องจาก Raspberry Pi Pico W รองรับ MicroPython และ C/C++ SDK เหมือนกับบอร์ด Raspberry Pi Pico และ API อื่นๆ สำหรับการเชื่อมต่อแบบ Wireless
แกะกล่อง Raspberry Pi Pico W
บอร์ด Raspberry Pi Pico W ที่ฉันได้รับถูกตัดจากม้วน/เทป 480 ชิ้น และฉันยังได้รับสายไมโคร USB เป็น USB ยาว 1 เมตร หากคุณสั่งซื้อบอร์ดราคา $6 (~210฿) น่าจะไม่รวมอยู่ด้วย
บอร์ดจะมีขนาดจิ๋วเท่ากับรุ่นเดิม, และพินเอาต์เหมือนกับบอร์ด RP2040 รุ่นแรก, และยังมีการทำเครื่องหมายไว้ที่ด้านล่างของบอร์ดอย่างชัดเจน
การเชื่อมต่อ Raspberry Pi Pico W เข้ากับคอมพิวเตอร์
เมื่อเราเชื่อมต่อบอร์ดกับโฮสต์แล้ว บอร์ดจะแสดงในคอมพิวเตอร์เป็นไดรเวอร์ RPI-RP2 แล็ปท็อปของฉันแม้ว่าจะใช้งาน Ubuntu 20.04 แต่ก็เหมือนกับที่ใช้บน Windows หรือ macOS
มีสองไฟล์ในไดรเวอร์ RPI-RP2 ที่มี INFO_UF2.txt สำหรับเวอร์ชัน bootloader ของ UF2 และรุ่นของบอร์ด และ INDEX.HTM ซึ่งเปลี่ยนเส้นทาง ไปยังเอกสารประกอบของ Pico บนเว็บไซต์ Raspberry Pi ไม่มีอะไรเปลี่ยนแปลงที่นี่จริงๆ
นี่คือผลลัพธ์จากบันทึกเคอร์เนล สำหรับการอ้างอิง:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[31039.896573] usb 1-1: new full-speed USB device number 7 using xhci_hcd [31040.068190] usb 1-1: New USB device found, idVendor=2e8a, idProduct=0003, bcdDevice= 1.00 [31040.068198] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [31040.068201] usb 1-1: Product: RP2 Boot [31040.068203] usb 1-1: Manufacturer: Raspberry Pi [31040.068205] usb 1-1: SerialNumber: E0C9125B0D9B [31040.126291] usb-storage 1-1:1.0: USB Mass Storage device detected [31040.126674] scsi host2: usb-storage 1-1:1.0 [31040.126893] usbcore: registered new interface driver usb-storage [31040.134814] usbcore: registered new interface driver uas [31041.138666] scsi 2:0:0:0: Direct-Access RPI RP2 3 PQ: 0 ANSI: 2 [31041.139090] sd 2:0:0:0: Attached scsi generic sg2 type 0 [31041.139462] sd 2:0:0:0: [sdc] 262144 512-byte logical blocks: (134 MB/128 MiB) [31041.140240] sd 2:0:0:0: [sdc] Write Protect is off [31041.140242] sd 2:0:0:0: [sdc] Mode Sense: 03 00 00 00 [31041.142282] sd 2:0:0:0: [sdc] No Caching mode page found [31041.142290] sd 2:0:0:0: [sdc] Assuming drive cache: write through [31041.150224] sdc: sdc1 [31041.154246] sd 2:0:0:0: [sdc] Attached SCSI removable disk |
WiFi พร้อม MicroPython
Raspberry Pi Pico และ Pico W ใช้ bootloader เดียวกัน แต่เฟิร์มแวร์ MicroPython นั้นแตกต่างกัน ฉันคิดว่าอาจเป็นเพราะความแตกต่างของฮาร์ดแวร์เล็กน้อย (เช่น การเชื่อมต่อ LED ของผู้ใช้) แต่เนื่องจากการเพิ่มสแต็ก WiFi ลงใน Raspberry Pi Pico นั้นไม่สมเหตุสมผล เนื่องจาก Pico ไม่มี WiFi และ การเพิ่มอาจเป็นการสิ้นเปลืองพื้นที่จัดเก็บและหน่วยความจำอันมีค่าของ Pico ในไมโครคอนโทรลเลอร์ที่มีข้อจำกัดด้านทรัพยากร
เราสามารถค้นหาไฟล์เฟิร์มแวร์ที่ถูกต้องบน เว็บไซต์ Raspberry Pi หรือสามารถดาวน์โหลดได้โดยตรงดังนี้:
1 |
wget https://micropython.org/download/rp2-pico-w/rp2-pico-w-latest.uf2 |
เมื่อเราดาวน์โหลดแล้ว เพียงคัดลอก rp2-pico-w-latest.uf2 ไปยังไดรฟ์ RPI-RP2…
หลังจากคัดลอกเสร็จแล้ว ไดรฟ์จะหายไป และ Raspberry Pi Pico W จะแสดงเป็นอุปกรณ์ซีเรียล:
1 2 3 4 5 6 7 8 9 |
[31932.896450] usb 1-1: new full-speed USB device number 8 using xhci_hcd [31933.070029] usb 1-1: New USB device found, idVendor=2e8a, idProduct=0005, bcdDevice= 1.00 [31933.070039] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [31933.070043] usb 1-1: Product: Board in FS mode [31933.070046] usb 1-1: Manufacturer: MicroPython [31933.070049] usb 1-1: SerialNumber: e6614c311b939432 [31933.164647] cdc_acm 1-1:1.0: ttyACM0: USB ACM device [31933.164710] usbcore: registered new interface driver cdc_acm [31933.164714] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters |
Raspberry Pi Pico W สามารถตรวจพบได้ใน BootTerm (หรือเครื่องมืออื่นๆ เช่น Putty, minicom, tio ฯลฯ…):
1 2 3 4 |
$ bt -l port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- * 0 | 132 | ttyACM0 | cdc_acm | Board CDC |
หากเราเชื่อมต่อกับอุปกรณ์ซีเรียล เราจะเข้าสู่อินเทอร์เฟซ REPL ซึ่งตอนนี้เราสามารถพิมพ์คำสั่งบางอย่างเพื่อแสดงรายการจุดเข้าใช้งาน 2.4 GHz:
1 2 3 4 5 6 7 8 9 10 11 |
$ bt No port specified, using ttyACM0 (last registered). Use -l to list ports. Trying port ttyACM0... Connected to ttyACM0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. >>> import network >>> wlan = network.WLAN(network.STA_IF) >>> wlan.active(True) >>> print(wlan.scan()) [(b'CNX_Software_Xiaomi', b'<\xcdW\xf5\xaf\x92', 8, -24, 5, 5), (b'', b'B\xcdW\xf5\xaf\x92', 8, -26, 0, 2)] >>> |
ยอดเยี่ยม! มันใช้งานได้ เนื่องจากฉันอาศัยอยู่ในพื้นที่ชนบท จึงตรวจพบจุดเชื่อมต่อที่มองเห็นได้เพียงจุดเดียวเท่านั้น อีกค่าหนึ่ง (“) คือ SSID ที่ซ่อนอยู่ซึ่งเปิดใช้งานบนเราเตอร์ Xiaomi ของฉัน ตามเอกสารของ MicroPython API ค่าอื่นๆ อีกห้าค่าสำหรับ bssid หมายเลขช่องสัญญาณ RSSI โหมดตรวจสอบสิทธิ์ และสถานะที่ซ่อนอยู่ตามลำดับ แต่ตัวเลขสองตัวสุดท้ายอยู่นอกช่วง:
ความปลอดภัยมีห้าค่า:
- 0 – open
- 1 – WEP
- 2 – WPA-PSK
- 3 – WPA2-PSK
- 4 – WPA/WPA2-PSK
และสถานะที่ซ่อนอยู่:
- 0 – มองเห็นได้
- 1 – ซ่อน
ต่อไป มาดูเอกสารประกอบคำแนะนำ “การเชื่อมต่ออินเทอร์เน็ต” สำหรับบอร์ด วิธีที่ง่ายที่สุดในการอัปเดตโค้ดเพื่อติดตั้งโปรแกรมตัวแก้ไข Thonny ก่อน:
1 2 |
sudo apt install python3-tk pip3 install thonny |
หลังจากไปที่ Run->Select Interpreter และเลือก “MicroPython (Raspberry Pi Pico)” เราสามารถเรียกใช้โปรแกรม MicroPython ก่อนหน้าใน Thonny IDE ได้โดยไม่มีปัญหาใดๆ
ตอนนี้เราเชื่อมต่อกับ CNX_Software_Xiaomi SSID โดยใช้:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import time import network ssid = 'CNX_Software_Xiaomi' password = 'The Password' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) # Wait for connect or fail max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('waiting for connection...') time.sleep(1) # Handle connection error if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print( 'ip = ' + status[0] ) |
จากด้านบนคุณจะเห็นว่า Raspberry Pi Pico W ของฉันมีที่อยู่ IP และฉันสามารถ ping ได้สำเร็จ:
1 2 3 4 5 6 |
$ ping 192.168.31.120 PING 192.168.31.120 (192.168.31.120) 56(84) bytes of data. 64 bytes from 192.168.31.120: icmp_seq=1 ttl=255 time=187 ms 64 bytes from 192.168.31.120: icmp_seq=2 ttl=255 time=35.3 ms 64 bytes from 192.168.31.120: icmp_seq=3 ttl=255 time=54.1 ms 64 bytes from 192.168.31.120: icmp_seq=4 ttl=255 time=77.1 ms |
สำหรับการอ้างอิง เราจะเห็นว่าปรากฏเป็น PYPB บนเว็บ:
1 2 3 4 5 6 |
$ nmap -sP 192.168.31.0/24 Starting Nmap 7.80 ( https://nmap.org ) at 2022-07-02 14:04 +07 ... Nmap scan report for PYBD (192.168.31.120) Host is up (0.026s latency). ... |
เฟิร์มแวร์มาพร้อมกับการตั้งค่าระดับสากลที่ปลอดภัย แต่ผู้ใช้สามารถเปิดใช้งานช่องเพิ่มเติมได้โดยการตั้งค่าประเทศและภูมิภาค:
1 2 |
import rp2 rp2.country('TH') |
หากคุณพบบอร์ดที่ไม่สามารถเชื่อมต่อกับเราเตอร์ได้เนื่องจากช่องสัญญาณไม่พร้อมใช้งาน ไม่ต้องกังวล สิ่งนี้มีประโยชน์มากจริงๆ
กรณีใช้งานทั่วไปสำหรับบอร์ดประเภทนี้คือการมีเว็บอินเตอร์เฟสเพื่อควบคุม LED หรือ GPIO ตอนนี้เราเรียกใช้เว็บเซิร์ฟเวอร์เพื่อควบคุม LED ของผู้ใช้บนบอร์ด:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
import network import socket import time from machine import Pin # Select the onboard LED led = machine.Pin("LED", machine.Pin.OUT) ssid = 'CNX_Software_Xiaomi' password = 'A Password' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) html = """<!DOCTYPE html> <html> <head> <title>CNX Software's Pico W </title> </head> <body> <h1>CNX Software's Pico W</h1> <p>%s</p> </body> </html> """ # Wait for connect or fail max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('waiting for connection...') time.sleep(1) # Handle connection error if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print( 'ip = ' + status[0] ) # Open socket addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] s = socket.socket() s.bind(addr) s.listen(1) print('listening on', addr) # Listen for connections while True: try: cl, addr = s.accept() print('client connected from', addr) request = cl.recv(1024) print(request) request = str(request) led_on = request.find('/light/on') led_off = request.find('/light/off') print( 'led on = ' + str(led_on)) print( 'led off = ' + str(led_off)) if led_on == 6: print("led on") led.value(1) stateis = "LED is ON" if led_off == 6: print("led off") led.value(0) stateis = "LED is OFF" response = html % stateis cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') cl.send(response) cl.close() except OSError as e: cl.close() print('connection closed') |
โค้ดนี้ค่อนข้างยาวเนื่องจากมีการจัดการข้อผิดพลาดอยู่ด้วย เราสามารถเห็นได้ว่ามันใช้งานได้ดีโดยดูวิดีโอสาธิตสั้นๆ ด้านล่างนี้
สามารถปรับเปลี่ยนโค้ดเพื่อควบคุมรีเลย์หรือ GPIO ได้อย่างง่ายดาย
นอกจากนี้ยังสามารถติดตั้งและเรียกใช้เครื่องมือ iperf3 ยอดนิยมบน Raspberry Pi Pico W:
1 2 3 4 5 6 7 8 |
import network wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect('CNX_Software_Xiaomi', 'The Password') import upip upip.install("uiperf3") import uiperf3 uiperf3.client('192.168.31.48') |
รหัสค่อนข้างสั้นเพราะเราข้ามการจัดการข้อผิดพลาดสำหรับการเชื่อมต่อ นี่คือผลลัพธ์จากการทดสอบ benchmark เครือข่าย :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Connecting to ('192.168.31.48', 5201) Interval Transfer Bitrate 0.00-1.00 sec 492 KBytes 4.03 Mbits/sec 1.00-2.00 sec 552 KBytes 4.51 Mbits/sec 2.00-3.00 sec 587 KBytes 4.80 Mbits/sec 3.00-4.00 sec 579 KBytes 4.74 Mbits/sec 4.00-5.00 sec 567 KBytes 4.65 Mbits/sec 5.00-6.00 sec 521 KBytes 4.26 Mbits/sec 6.00-7.00 sec 551 KBytes 4.51 Mbits/sec 7.00-8.00 sec 563 KBytes 4.61 Mbits/sec 8.00-9.00 sec 564 KBytes 4.61 Mbits/sec 9.00-10.00 sec 533 KBytes 4.38 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.00-10.00 sec 5.38 MBytes 4.51 Mbits/sec sender 0.00-10.85 sec 5.38 MBytes 4.16 Mbits/sec receiver |
สิ่งนี้ค่อนข้างช้าสำหรับฉัน แม้ว่าประสิทธิภาพบางอย่างจะไม่ใช่ข้อกำหนดหลักสำหรับแพลตฟอร์มประเภทนี้ อันที่จริง เกณฑ์มาตรฐานนี้อาจเป็นเรื่องปกติของฮาร์ดแวร์ดังกล่าว สำหรับข้อมูลอ้างอิง Damien George หัวหน้านักพัฒนาของ MicroPython ได้ ทำการทดสอบบนบอร์ด Pyboard D-series แล้วด้วยความเร็ว ประมาณ 7 Mbits/วินาที
อันที่จริง Raspberry Pi Pico W ยังสามารถใช้เป็นจุดเชื่อมต่อสำหรับไคลเอ็นต์ได้ถึงสี่เครื่อง ฉันไม่พบบทช่วยสอนใด ๆ ใน MicroPython แต่มีคำแนะนำสำหรับ ESP8266 และ ESP32 ดังนั้นตอนนี้ให้ลองตั้งค่า CNX-PICO SSID ต่อไปนี้และเชื่อมต่อจากโทรศัพท์:
1 2 3 4 5 6 7 |
import network ssid = 'CNX-PICO' password = 'cnx-review' ap = network.WLAN(network.AP_IF) ap.active(True) ap.config(essid=ssid, password=password) |
ข่าวดีก็คือ Raspberry Pi Pico W ของฉันคือจุดเชื่อมต่อ (AP) ในตอนนี้ แต่สิ่งที่แย่คือการกำหนดค่า ssid แบบกำหนดเองไม่ทำงาน แต่บอร์ดจะสร้างการเชื่อมต่อเครือข่ายแบบเปิดโดยอัตโนมัติ ใน ชื่อจุด – PICO349B
ดังนั้น API จึงแตกต่างออกไป หรือเฟิร์มแวร์ Raspberry Pi Pico W MicroPython ยังไม่รองรับชื่อจุดเข้าใช้งานที่กำหนดเอง
การใช้ WiFi บน Raspberry Pi Pico W ด้วยการเขียนโปรแกรม C
ตอนนี้ มาลองทำซ้ำตัวอย่างโค้ดด้านบนด้วย C/C++ SDK หากคุณยังไม่ได้ลองสิ่งนี้ คุณจะต้องตั้งค่า SDK เหมือนกับที่เราทำกับบอร์ด Raspberry Pi Pico และรับตัวอย่างในคอมพิวเตอร์ Linux หรือบอร์ด Raspberry Pi:
1 2 3 4 5 6 |
sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential git clone https://github.com/raspberrypi/pico-sdk cd pico-sdk git submodule update --init cd .. git clone -b master https://github.com/raspberrypi/pico-examples.git |
ขณะนี้เรามีไดเรกทอรีใหม่สำหรับ Pico W:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ ls -l pico-examples/pico_w/ total 44 drwxrwxr-x 3 jaufranc jaufranc 4096 Jul 2 16:32 access_point drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 blink -rw-rw-r-- 1 jaufranc jaufranc 985 Jul 2 16:32 CMakeLists.txt drwxrwxr-x 4 jaufranc jaufranc 4096 Jul 2 16:32 freertos drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 iperf -rw-rw-r-- 1 jaufranc jaufranc 3417 Jul 2 16:32 lwipopts_examples_common.h drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 ntp_client drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 python_test_tcp drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 tcp_client drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 tcp_server drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 wifi_scan |
นี่คือตัวอย่างโค้ดสำหรับการสแกน WiFi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
** * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" static int scan_result(void *env, const cyw43_ev_scan_result_t *result) { if (result) { printf("ssid: %-32s rssi: %4d chan: %3d mac: %02x:%02x:%02x:%02x:%02x:%02x sec: %u\n", result->ssid, result->rssi, result->channel, result->bssid[0], result->bssid[1], result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5], result->auth_mode); } return 0; } #include "hardware/vreg.h" #include "hardware/clocks.h" int main() { stdio_init_all(); if (cyw43_arch_init()) { printf("failed to initialise\n"); return 1; } cyw43_arch_enable_sta_mode(); absolute_time_t scan_test = nil_time; bool scan_in_progress = false; while(true) { if (absolute_time_diff_us(get_absolute_time(), scan_test) < 0) { if (!scan_in_progress) { cyw43_wifi_scan_options_t scan_options = {0}; int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result); if (err == 0) { printf("\nPerforming wifi scan\n"); scan_in_progress = true; } else { printf("Failed to start scan: %d\n", err); scan_test = make_timeout_time_ms(10000); // wait 10s and scan again } } else if (!cyw43_wifi_scan_active(&cyw43_state)) { scan_test = make_timeout_time_ms(10000); // wait 10s and scan again scan_in_progress = false; } } // the following #ifdef is only here so this same example can be used in multiple modes; // you do not need it in your code #if PICO_CYW43_ARCH_POLL // if you are using pico_cyw43_arch_poll, then you must poll periodically from your // main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done. cyw43_arch_poll(); sleep_ms(1); #else // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work // is done via interrupt in the background. This sleep is just an example of some (blocking) // work you might be doing. sleep_ms(1000); #endif } cyw43_arch_deinit(); return 0; } |
สิ่งนี้ซับซ้อนกว่าตัวอย่าง MicroPython ด้านบนเล็กน้อย ตอนนี้เราเตรียมระบบเพื่อสร้างตัวอย่าง C:
1 2 3 4 5 |
cd pico-examples/ mkdir build cd build export PICO_SDK_PATH=../../pico-sdk cmake -DPICO_BOARD=pico_w -DWIFI_SSID="Your Network" -DWIFI_PASSWORD="Your Password" .. |
เราจำเป็นต้องเปลี่ยน SSID และรหัสผ่านให้ตรงกับรหัสผ่านในเครือข่าย ต่อไปนี้คือผลลัพธ์ของคำสั่ง เพื่อการอ้างอิงเท่านั้น:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Using PICO_SDK_PATH from environment ('../../pico-sdk') PICO_SDK_PATH is /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk Defaulting PICO_PLATFORM to rp2040 since not specified. Defaulting PICO platform compiler to pico_arm_gcc since not specified. -- Defaulting build type to 'Release' since not specified. PICO compiler is pico_arm_gcc -- The C compiler identification is GNU 9.2.1 -- The CXX compiler identification is GNU 9.2.1 -- The ASM compiler identification is GNU -- Found assembler: /usr/bin/arm-none-eabi-gcc Build type is Release PICO target board is pico_w. Using CMake board configuration from /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/src/boards/pico_w.cmake Using board configuration from /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/src/boards/include/boards/pico_w.h -- Found Python3: /usr/bin/python3.8 (found version "3.8.10") found components: Interpreter TinyUSB available at /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040; enabling build support for USB. cyw43-driver available at /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/cyw43-driver lwIP available at /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/lwip Enabling build support for Pico W wireless. Skipping tcp_client example as TEST_TCP_SERVER_IP is not defined Skipping Pico W FreeRTOS examples as FREERTOS_KERNEL_PATH not defined -- Configuring done -- Generating done -- Build files have been written to: /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-examples/build |
ตอนนี้เราสามารถสร้างตัวอย่าง wifi_scan ได้แล้ว:
1 2 |
cd pico_w/wifi_scan make -j8 |
ผลลัพธ์ค่อนข้างยาว แต่โดยพื้นฐานแล้วควรเริ่มต้นและสิ้นสุดดังนี้:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Scanning dependencies of target ELF2UF2Build [ 0%] Creating directories for 'ELF2UF2Build' [ 0%] No download step for 'ELF2UF2Build' [ 0%] No patch step for 'ELF2UF2Build' [ 0%] No update step for 'ELF2UF2Build' [ 0%] Performing configure step for 'ELF2UF2Build' -- The C compiler identification is GNU 9.4.0 -- The CXX compiler identification is GNU 9.4.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works ... [100%] Building C object pico_w/wifi_scan/CMakeFiles/picow_wifi_scan_background.dir/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/lwip/src/netif/ppp/polarssl/md5.c.obj [100%] Building C object pico_w/wifi_scan/CMakeFiles/picow_wifi_scan_background.dir/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/lwip/src/netif/ppp/polarssl/sha1.c.obj [100%] Building C object pico_w/wifi_scan/CMakeFiles/picow_wifi_scan_background.dir/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/src/rp2_common/pico_lwip/nosys.c.obj [100%] Linking CXX executable picow_wifi_scan_background.elf [100%] Built target picow_wifi_scan_background |
บิลด์จะสร้างไฟล์จำนวนมาก รวมถึงไฟล์ UF2 ที่เราจะใช้เพื่อคัดลอกไปยังบอร์ด:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ ls -l total 8560 drwxrwxr-x 4 jaufranc jaufranc 4096 Jul 2 16:48 CMakeFiles -rw-rw-r-- 1 jaufranc jaufranc 1027 Jul 2 16:48 cmake_install.cmake -rw-rw-r-- 1 jaufranc jaufranc 482519 Jul 2 16:48 Makefile -rwxrwxr-x 1 jaufranc jaufranc 306968 Jul 2 16:51 picow_wifi_scan_background.bin -rw-rw-r-- 1 jaufranc jaufranc 1499022 Jul 2 16:51 picow_wifi_scan_background.dis -rwxrwxr-x 1 jaufranc jaufranc 380952 Jul 2 16:51 picow_wifi_scan_background.elf -rw-rw-r-- 1 jaufranc jaufranc 452605 Jul 2 16:51 picow_wifi_scan_background.elf.map -rw-rw-r-- 1 jaufranc jaufranc 863499 Jul 2 16:51 picow_wifi_scan_background.hex -rw-rw-r-- 1 jaufranc jaufranc 614400 Jul 2 16:51 picow_wifi_scan_background.uf2 -rwxrwxr-x 1 jaufranc jaufranc 308304 Jul 2 16:51 picow_wifi_scan_poll.bin -rw-rw-r-- 1 jaufranc jaufranc 1490453 Jul 2 16:51 picow_wifi_scan_poll.dis -rwxrwxr-x 1 jaufranc jaufranc 418272 Jul 2 16:51 picow_wifi_scan_poll.elf -rw-rw-r-- 1 jaufranc jaufranc 437754 Jul 2 16:51 picow_wifi_scan_poll.elf.map -rw-rw-r-- 1 jaufranc jaufranc 867250 Jul 2 16:51 picow_wifi_scan_poll.hex -rw-rw-r-- 1 jaufranc jaufranc 616960 Jul 2 16:51 picow_wifi_scan_poll.uf2 |
เนื่องจากเรามีเฟิร์มแวร์ MicroPython ติดตั้งอยู่บนบอร์ดแล้ว ตอนนี้เราต้องกดปุ่ม BOOT และรีบูตบอร์ดเพื่อเข้าสู่โหมดที่เก็บข้อมูลขนาดใหญ่ และคัดลอก ไฟล์ picow_wifi_scan_poll.uf2 ไปยังไดรฟ์ RPI-RP2
ที่นี่ไดรฟ์หายไป จากนั้นจำเป็นต้องรีบูตและโปรแกรมเริ่มทำงานโดยอัตโนมัติ และฉันยังสังเกตเห็นว่าบอร์ดไม่แสดงเป็นอุปกรณ์ซีเรียลอีกต่อไป เหตุผลหลักคือเราต้องเข้าถึงคอนโซลอนุกรมผ่านพิน UART ของ Raspberry Pi Pico W (พิน 1 Tx, พิน 2 Rx และพิน 3 GND) ดังนั้นฉันจึงบัดกรีส่วนหัวสั้น ๆ บนหมุดที่เกี่ยวข้องบน Raspberry Pi Pico W และใช้บอร์ด USB เป็น TTL เพื่อเชื่อมต่อกับแล็ปท็อปของฉัน แต่ถ้าพวกคุณใช้ Raspberry Pi SBC เพื่อตั้งโปรแกรมบอร์ด Pico W คุณสามารถเปลี่ยน UART ไปยังส่วนหัว GPIO 40 พิน
ตอนนี้ฉันสามารถใช้ BootTerm และดู CNX_Software_Xiaomi SSID และ SSID ที่ซ่อนอยู่ในเราเตอร์ถูกตรวจพบอย่างถูกต้อง:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ bt -n 0 ports found, waiting for a new one... port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- 0 | 0 | ttyUSB0 | ch341-uart | USB2.0-Serial Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. Performing wifi scan ssid: rssi: -35 chan: 8 mac: 42:cd:57:f5:af:92 sec: 0 ssid: CNX_Software_Xiaomi rssi: -36 chan: 8 mac: 3c:cd:57:f5:af:92 sec: 5 ssid: CNX_Software_Xiaomi rssi: -35 chan: 8 mac: 3c:cd:57:f5:af:92 sec: 5 ssid: CNX_Software_Xiaomi rssi: -33 chan: 8 mac: 3c:cd:57:f5:af:92 sec: 5 ssid: rssi: -34 chan: 8 mac: 42:cd:57:f5:af:92 sec: 0 |
การสแกนจึงใช้งานได้ แม้ว่าจะแสดง SSID เดียวกันหลายครั้ง ตอนนี้ เราสามารถลองเชื่อมต่อกับเราเตอร์ WiFi ของเราโดยใช้ตัวอย่างต่อไปนี้ใน wifi_connect/wifi_connect.c (ตัวอย่างจากเอกสาร Pico W):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" char ssid[] = "CNX_Software_Xiaomi"; char pass[] = "A Password"; int main() { stdio_init_all(); if (cyw43_arch_init_with_country(CYW43_COUNTRY_UK)) { printf("failed to initialise\n"); return 1; } printf("initialised\n"); cyw43_arch_enable_sta_mode(); if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, CYW43_AUTH_WPA2_AES_PSK, 10000)) { printf("failed to connect\n"); return 1; } printf("connected\n"); } |
เพียงตรวจสอบให้แน่ใจว่าคุณได้เปลี่ยนค่า ssid ค่าที่ส่งผ่าน และประเทศ (เช่น: CYW43_COUNTRY_TH) ต่อไปเราต้องการ ไฟล์ CMakeLists.txt :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
cmake_minimum_required(VERSION 3.13) include(pico_sdk_import.cmake) project(test_project C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) pico_sdk_init() add_executable(wifi_connect wifi_connect.c ) pico_enable_stdio_usb(wifi_connect 1) pico_enable_stdio_uart(wifi_connect 1) pico_add_extra_outputs(wifi_connect) target_include_directories(wifi_connect PRIVATE ${CMAKE_CURRENT_LIST_DIR} ) target_link_libraries(wifi_connect pico_cyw43_arch_lwip_threadsafe_background pico_stdlib) |
นอกจากนี้ จำเป็นต้องคัดลอกไฟล์พิเศษบางไฟล์ไปยังไดเร็กทอรีการทำงานด้วย:
1 2 |
cp ../../../pico-sdk/external/pico_sdk_import.cmake . cp ../lwipopts_examples_common.h lwipopts.h |
ตอนนี้คุณควรจะได้โฟลเดอร์ที่มีสี่ไฟล์:
1 2 3 4 5 6 |
jaufranc@cnx-laptop-4:~/edev/Raspberry-Pi-Pico-W/pico-examples/pico_w/wifi_connect$ ls -l total 16 -rw-rw-r-- 1 jaufranc jaufranc 480 Jul 3 11:59 CMakeLists.txt -rw-rw-r-- 1 jaufranc jaufranc 3417 Jul 3 12:01 lwipopts.h -rw-rw-r-- 1 jaufranc jaufranc 3165 Jul 3 12:00 pico_sdk_import.cmake -rw-rw-r-- 1 jaufranc jaufranc 519 Jul 3 11:55 wifi_connect.c |
ตอนนี้เราสามารถสร้างโปรแกรมได้เหมือนที่เคยทำ:
1 2 3 4 5 |
mkdir build cd build export PICO_SDK_PATH=../../../../pico-sdk/ cmake -DPICO_BOARD=pico_w .. make -j8 |
หากมีสิ่งผิดปกติเกิดขึ้นระหว่างขั้นตอน cmake ให้แก้ไขไฟล์ CMakeLists.txt และลบไฟล์ทั้งหมดในโฟลเดอร์บิลด์ จากนั้นรันคำสั่ง cmake อีกครั้ง
เนื่องจากฉันอยู่ในประเทศไทย ตอนแรกฉันคิดว่า CYW43_COUNTRY_TH น่าจะใช้ได้ แต่ผลที่ได้คือผิด!
1 2 3 4 5 |
/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-examples/pico_w/wifi_connect/wifi_connect.c:11:36: error: 'CYW43_COUNTRY_TH' undeclared (first use in this function); did you mean 'CYW43_COUNTRY_UK'? 11 | if (cyw43_arch_init_with_country(CYW43_COUNTRY_TH)) { | ^~~~~~~~~~~~~~~~ | CYW43_COUNTRY_UK /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-examples/pico_w/wifi_connect/wifi_connect.c:11:36: note: each undeclared identifier is reported only once for each function it appears in |
หากคุณกำลังประสบปัญหานี้เช่นกัน ไดเร็กทอรีประเทศที่พร้อมใช้งานจะมีอยู่ใน pico-sdk/lib/cyw43-driver/src/cyw43_country.h นี่เป็นข้อความที่ตัดตอนมาที่คุณสามารถตรวจสอบได้:
1 2 3 4 5 6 7 |
... #define CYW43_COUNTRY_SWITZERLAND CYW43_COUNTRY('C', 'H', 0) #define CYW43_COUNTRY_TAIWAN CYW43_COUNTRY('T', 'W', 0) #define CYW43_COUNTRY_THAILAND CYW43_COUNTRY('T', 'H', 0) #define CYW43_COUNTRY_TURKEY CYW43_COUNTRY('T', 'R', 0) #define CYW43_COUNTRY_UK CYW43_COUNTRY('G', 'B', 0) #define CYW43_COUNTRY_USA CYW43_COUNTRY('U', 'S', 0) |
หลังจากที่ฉันเปลี่ยนไปใช้ CYW43_COUNTRY_THAILAND ฉันก็สามารถสร้างให้เสร็จได้ ไฟล์ UF2 ที่เราต้องการมีลักษณะดังนี้:
1 2 |
ls -l *.uf2 -rw-rw-r-- 1 jaufranc jaufranc 638976 Jul 3 14:00 wifi_connect.uf2 |
ตอนนี้เราแฟลชไปที่บอร์ดตามปกติและดูว่าเราสามารถเชื่อมต่อกับเราเตอร์ได้จริงหรือไม่:
1 2 3 4 5 6 7 8 9 |
$ bt -n 1 ports found, waiting for a new one... port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- 1 | 0 | ttyACM0 | cdc_acm | Board CDC Trying port ttyACM0... Connected to ttyACM0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. connected |
มีการพิมพ์ข้อมูลไม่มากนักที่นี่ แต่อย่างน้อยโปรแกรมก็ทำงานโดยไม่มีข้อผิดพลาด หากคุณต้องการใช้ C บน Raspberry Pi Pico W อาจต้องใช้เวลาสักครู่ในการเรียนรู้ รวมถึงการเรียนรู้ CYW43 API ใหม่ ไลบรารี LWiP และแม้แต่การใช้ FreeRTOS สำหรับตัวอย่างที่ซับซ้อนยิ่งขึ้น
เนื่องจากขณะนี้ยังไม่มีโค้ดตัวอย่างสำหรับควบคุม LEDs ผ่านหน้าเว็บ เรามาดูตัวอย่าง iperf กันก่อน ก่อนอื่นเราไปที่โฟลเดอร์ /pico-examples/build/pico_w/iperfและสร้างตัวอย่าง:
1 |
make -j8 |
ในกรณีนี้เรามีไฟล์ UF2 สองไฟล์:
1 2 3 |
$ ls -l *.uf2 -rw-rw-r-- 1 jaufranc jaufranc 629760 Jul 3 14:28 picow_iperf_server_background.uf2 -rw-rw-r-- 1 jaufranc jaufranc 632832 Jul 3 14:28 picow_iperf_server_poll.uf2 |
เราต้องการดูรหัสที่เลือกผ่าน PICO_CYW43_ARCH_POLL:
- PICO_CYW43_ARCH_POLL = 1 – หากคุณใช้ pico_cyw43_arch_poll คุณต้องสำรวจเป็นระยะจากลูป (loop) หลักของคุณ (ไม่ใช่จากตัวจับเวลา) เพื่อตรวจสอบไดรเวอร์ WiFi หรืองาน lwIP ที่ต้องทำ
- PICO_CYW43_ARCH_POLL != 1 – หากคุณไม่ได้ใช้ pico_cyw43_arch_poll แสดงว่าไดรเวอร์ WiFI และ lwIP จะต้องดำเนินการโดยใช้การขัดจังหวะพื้นหลัง แน่นอนว่าการนอนหลับนี้เป็นเพียงตัวอย่างบางส่วนเท่านั้น
การใช้การโพล (polling) หรือ interrup ของโปรแกรมเป็นแนวทางการเขียนโปรแกรมที่แตกต่างกันสองวิธี โดยทั่วไปการ interrup ของโปรแกรมจะมีประสิทธิภาพมากกว่า แต่ซับซ้อนกว่า ที่นี่ฉันเพิ่ง คัดลอก picow_iperf_server_background.uf2ไปยังบอร์ดเพื่อทำการทดสอบ โปรดทราบว่าการใช้งานจะขึ้นอยู่กับ iperf2 ไม่ใช่ iperf3 เช่น MicroPython เซิร์ฟเวอร์ iperf สามารถทำงานบน Raspberry Pi Pico W ได้ดังนี้:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ bt -n 1 ports found, waiting for a new one... port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- 0 | 0 | ttyUSB0 | ch341-uart | USB2.0-Serial Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. Connecting to WiFi... Connected. Ready, running iperf server at 192.168.31.120 |
ตอนนี้เรารันไคลเอนต์ iperf บนแล็ปท็อป:
1 2 3 4 5 6 7 8 |
jaufranc@cnx-laptop-4:~$ iperf -c 192.168.31.120 ------------------------------------------------------------ Client connecting to 192.168.31.120, TCP port 5001 TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ 3] local 192.168.31.48 port 50008 connected with 192.168.31.120 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 9.75 MBytes 8.15 Mbits/sec |
ผลลัพธ์ของการทำงานคือ 8 Mbps ซึ่งดีกว่าเมื่อรันด้วย MicroPython เล็กน้อย แต่ยังอยู่ในช่วงเดียวกัน ผลลัพธ์จะแสดงในคอนโซลซีเรียล Pico W ด้วย:
1 2 |
Completed iperf transfer of 9 MBytes @ 8.1 Mbits/sec Total iperf megabytes since start 9 Mbytes |
หากคุณต้องการเรียกใช้ตัวอย่างฝั่งไคลเอ็นต์ iperf บน Pico W คุณต้องเพิ่มสองบรรทัดต่อไปนี้หลังชื่อ:
1 2 |
#define CLIENT_TEST 1 #define IPERF_SERVER_IP <IP_address of the server> |
“คู่มือเริ่มต้นใช้งาน” นี้ให้ความรู้สึกเหมือนยาวและยาวกว่าที่ฉันคาดไว้ในตอนแรก ดังนั้นฉันจึงข้ามส่วนนี้ไป
ตอนนี้ มาดูบทแนะนำเกี่ยวกับ WiFi โดยใช้การสาธิตจุดเข้าใช้งานของ Raspberry Pi Pico W ก่อนสร้างตัวอย่าง ให้ดูโค้ดใน pico-examples/pico_w/access_point/picow_access_point.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const char *ap_name = "picow_test"; #if 1 const char *password = "password"; #else const char *password = NULL; #endif cyw43_arch_enable_ap_mode(ap_name, password, CYW43_AUTH_WPA2_AES_PSK); ip4_addr_t gw, mask; IP4_ADDR(&gw, 192, 168, 4, 1); IP4_ADDR(&mask, 255, 255, 255, 0); // Start the dhcp server dhcp_server_t dhcp_server; dhcp_server_init(&dhcp_server, &gw, &mask); |
ในฟังก์ชัน main() ส่วนนี้เราจะเห็น SSID เริ่มต้น (จุดเข้าใช้งาน name0 คือ picow_test รหัสผ่านคือรหัสผ่าน (ความปลอดภัย WPA2) ซับเน็ตคือ 192.168.4.0 โปรแกรมนี้จะเริ่มเซิร์ฟเวอร์ DHCP ให้ไคลเอ็นต์รับ ที่อยู่ IP หากตั้งรหัสผ่านเป็น NULL ควรเป็นเครือข่ายแบบเปิด ดังนั้นฉันจึงเปลี่ยน ap_name เป็น picow_cnxsoft และรหัสผ่านเป็น 123456…
1 2 3 4 5 6 |
const char *ap_name = "picow_cnxsoft"; #if 1 const char *password = "123465"; #else const char *password = NULL; #endif |
ตอนนี้สร้างตัวอย่างตามปกติและ คัดลอก picow_access_point_poll.uf2หรือpicow_access_point_background.uf2ไปที่บอร์ด นี่คือเอาต์พุตเทอร์มินัล:
1 2 3 4 5 |
$ bt No port specified, using ttyUSB0 (last registered). Use -l to list ports. Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. Starting server on port 80 |
โปรดทราบว่าเซิร์ฟเวอร์บนพอร์ต 80 ไม่ใช่เว็บเซิร์ฟเวอร์ แต่เป็นเซิร์ฟเวอร์ TCP พื้นฐาน ซึ่งฉันคิดว่าควรมีจุดประสงค์หลักเพื่อใช้กับตัวอย่างไคลเอนต์ TCP ที่ติดตั้งบน Raspberry Pi Pico อื่น
อย่างไรก็ตาม ฉันยังสามารถเชื่อมต่อโทรศัพท์กับจุดเข้าใช้งาน picow_cnxsoft…
ยังทำงานในแล็ปท็อป Ubuntu ของฉัน
อุปกรณ์ทั้งสองนี้ยังปรากฏในเทอร์มินัลอนุกรมของ Raspberry Pi Pico W:
1 2 3 |
Starting server on port 80 DHCPS: client connected: MAC=bc:2e:f6:6a:71:64 IP=192.168.4.16 DHCPS: client connected: MAC=70:c9:4e:b7:84:77 IP=192.168.4.17 |
เอกสารประกอบสำหรับ Raspberry Pi Pico W นั้นดีจริง ๆ สำหรับการเริ่มต้นใช้งาน WiFi แต่ไม่สมบูรณ์ เช่น ขณะนี้ยังไม่มีโค้ดตัวอย่างสำหรับการตั้งค่าจุดเชื่อมต่อใน MicroPython อีกตัวอย่างหนึ่งคือฉันต้องดูโค้ดใน C/C++ SDK ไม่ใช่เอกสาร เพื่อค้นหาการตั้งค่าสำหรับประเทศและภูมิภาคที่เกี่ยวข้อง อย่างไรก็ตาม ฉันคิดว่าคนส่วนใหญ่จะใช้ MicroPython ในบอร์ดพัฒนานี้ก่อน เพราะ C/C++ SDK นั้นยืดหยุ่นกว่า แต่จะเรียนรู้ได้ยากและใช้เวลานานกว่ามาก
แปลจากบทความภาษาอังกฤษ : Getting started with WiFi on Raspberry Pi Pico W board
บรรณาธิการข่าวและบทความภาษาไทย CNX Software ได้มีความสนใจในด้านเทคโนโลยี โดยเฉพาะ Smart Home และ IoT