wo4fisher

个性签名:水不撩不知深浅 人不拼怎知输赢

  • 2024-03-20
  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico platform IO下使用Ethernet3库设置静态IP

    lugl4313820 发表于 2024-3-9 16:22 第四步:在setup初始化函数中设置CS和rst引脚,并调用begin()函数/方法初始化W5500的网络参数。 初始化 ... 是的 主要是有人造好了轮子

  • 2024-03-10
  • 发表了主题帖: 【得捷Follow me第4期】项目总结

    因起:rp2040早两年就面世了,并且在不同的开发平台都有对其的支持,本身也是一款性能比较强劲的芯片,这次W5500-EVB-Pico在官方pico基础上增加了W5500这颗 集成全硬件TCPIP协议栈网络芯片,是一个学习通过嵌入式平台接入以太网的,以及各种网络协议栈学习的绝好机会。 **在每个帖子中,均有安装过程,代码和最后运行的结果(静态图片和动画的形式展现),硬件相对简单,没有录制视频,后边有时间再补充。   发帖地址汇总: 入门任务:    第一帖:【得捷Follow me第4期】W5500-EVB-Pico arduino离线HFS方式搭建第三方库开发环境     帖子中有完整的离线安装过程、库文件链接和github加速下载...                       第二帖:【得捷Follow me第4期】W5500-EVB-Pico platform io方式开发环境踩坑记录 基础任务一:第三帖: 【得捷Follow me第4期】W5500-EVB-Pico platform IO下使用Ethernet3库设置静态IP  基础任务二:第四帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO UDP收发测试                      第五帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO下TCP协议实现Webclient和WebServer 进阶任务:   第六帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO通过NTP服务器获取网络时间 终极任务二:第七帖:【得捷Follow me第4期】W5500-EVB-Pico PIO 挂载SD卡并实现文件读写访问                       第八帖: 未完待续...... 入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld) ① arduino 第一个任务主要是开发环境搭建,这里没有使用其他小伙伴使用的***Python环境,而是使用了Arduino环境和vscode + platformIO环境,原因,第一平时用python不多,第二主要是借助本次测试正好进一步了解一下vscode + platformIO环境下的开发板添加、各种库的使用方法、以及开发环境中的各种配置。 任务一分两步进行,首先在Arduino环境中进行了rp2040 pico开发环境的安装,因为中rp2040仅支持arduino环境。 所以想着先通过Arduino中搭建开发环境并测试开发板,以验证rp2040底层,跑通“helloworld”第一步,这样,方便在vscode + platformIO中万一遇到各种问题,好排查问题所在。 过程比较曲折,开始尝试通过在线安装,两次没成功。 后来网上搜索,使用离线方式安装,同时发现了一个非官方的库,大佬就是大佬(感谢开源路上各个无私奉献的大佬们!!!),arduino官方中的库应该也是来自于这位大佬,不过更新/同步不及时。于是乎使用HFS离线方式在arduino搭建了rp2040 pico 的库以及工具链等,中vscode + platformIO间过程也还好,不算太绕。 arduino库提供了丰富的示例库,无论是通用的arduino开发板,还是rp2040 pico 。但是弊端是没有编程过程中的代码提示功能和调试功能。(后来发现在visualStudio中已经有支持arduino工程的插件),于是,打算通过测评,测试另一目标比较流行的开发方式:vscode + platformIO。 结论:通过例程BLINK,arduino的库,是最快入门嵌入式学习的途径,不要太好用。   ② vscode + platformIO 首先是vscode + platformIO的安装。 安装完成后,便可以通过添加新工程的方式,让platformIO自动将rp2040 pico的库和工具链添加到系统环境。 这一步在线安装比在arduino中快很多,一次成功。 如果某硬件arduino和platformIO中是同步的,那么arduino中的例程是可以直接拷贝过来使用的,仅需要在mian.cpp中增加“#include <arduino.h>”,添加对arduino.h的应用即可。也就是platformIO可以借鉴arduino丰富的生态,并且绝大多数arduino的库都有使用例程。 platformIO也提供了在线搜索library的功能,并且查询到的库,可以通过链接打开库的网址。并且,如果直接使用这些库,不需要修改的话,仅需在PIO HOME中查询库,打开库之后单击  即可。 下图演示过程: 下载的库文件也会添加到lib文件夹下:   另一种添加第三方库的方式是,手动查找对应的库,下载后,将库手动拷贝至工程目录下对应的lib文件夹内即可。platformIO中提供ldf功能,会自动搜索lib文件下下的源文件,在编译时进行编译。 这里遇到的一个坑是,rp2040 pico通过usb下载一键下载程序使用驱动问题,在帖子中也有详细说明。这一步,在arduino中工具菜单下通过一些选项配置即可完成,没有遇到问题。 结论:过程有一些曲折,但是代码编辑自动提示、可以直接借鉴arduino生态,还是有新引力的(另外,platformIO对esp32、esp8266、stm32多个系列均有支持)。   基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。 因为此前对platformIO的不熟悉,因此,在本任务中,主要首先网络搜索,发现有Ethernet3库,这个库比较新,并且提供了对W5500的支持。 后来发现,pico库中自带Ethernet库,不过不支持CS引脚和RST引脚,需要在此基础上进行二次修改,同时Ethernet是否原生支持W5500,也是个问题。   因为,在后边的UDP和TCP/IP中都需要以本任务做基础,另,当时写本任务和后面基础任务二、进阶任务时,当时pico不在身边,没法测试。所以,本任务无最终测试,但是通过基础任务二、进阶任务,可知,使用Ethernet3可以完成本任务基本要求。 同时,在计算机端ping PICO的ip地址,可以返回数据(在其他任务中测试)。 结论:Ethernet3“是”pico原生Ethernet库的扩展,提供了CS引脚和RST引脚以及对应的io操作函数,以进行片选和硬件复位,同时通了udp、tcp/ip等协议栈的接口操作。   基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作) ① Udp协议收发测试 这里使用了ETHERNET3库中的示例代码,pico建立udp服务端,pc端使用net assist软件模拟udp客户端,进行数据收发。 PC端: pico端(下图开始时有一段时间静止(在操作pc端)):   ② TCP/IP协议 Webclient的实现 依然使用Ethernet3库,使用其web client例程 首先创建web client客户端,然后向服务端发起连接请求,当接收到数据后,打印接收数据。 结论:成功建立web client ,访问baidu.com,并成功返回连接请求数据。 ③ TCP/IP协议 Web server 的实现 这里继续使用Ethernet3库,使用pico创建web 服务器,在pc端,使用net assist软件,建立web 客户端。客户端发送数据给pico,pico进行应答。 pico 服务端: pc 客户端: 结论:作为web server可以成功接收客户端发送的请求数据,(写总结时)发现,pico作为服务端没有成功返回给客户端数据,这个后边查卡壳原因。   进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。 从NTP服务器获取网络时间,还是在UDP协议上的一个延伸,只要udp协议可以正常收发数据。 接下来就是按照NTP要求向NTP服务器发送请求数据报文即可获取时间数据,接下来就是对返回时间戳进行计算,根据需要计算得到不同格式的时间数据。 在例子中分别得到了1900年起到现在的秒数、1970年起到现在的秒数、和当前的日期和时间。   结论:在rp2040 pico中通过w5500可以方便实现有线连接获取网络时间,从而实现本地校时功能。   终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。 这一步需要将之前的Ethernet功能基础上增加ftp服务,同时需要在原来硬件基础上,扩展SD卡。需要使用多个库才能实现最终功能。 ① 首先实现pico 硬件SPI1 挂载SD卡 这里使用了RP2040_SD 库,同时在RP2040_SD 库的基础上进行了部分修改(RP2040_SD 库,以及 pico的库文件),使得支持硬件SPI1访问SD卡(原生仅支持SPI0)。原贴中有详细的修改步骤。 运行结果: 硬件连接: 未实现部分: 最后一个任务需要使用Ethernet库、FTP server库和SD库,因为原生pico库中没有很好的提供硬件支持(或者没找到),在实现以上任务中使用到的库文件在最后一个任务中,出现了不兼容的情况,因此FTP server和SD库,总有部分编译时出现各种重定义、错误等警告。 业余时间又断断续续折腾了一周,还是不见效果,但是折腾的过程也逐渐学习了各种库的实现、platformio库文件管理、不通库如何相互协作(引用)、C++语法等相关知识内容。 同时在折腾中,也发现了一些非常好的库文件,后边有时间再继续折腾。  

  • 发表了日志: 【得捷Follow me第4期】项目总结

  • 加入了学习《【得捷电子Follow me第4期】任务视频》,观看 【得捷电子Follow me第4期】任务视频

  • 2024-03-05
  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO 挂载SD卡并实现文件读写访问

    外部SD卡挂载成功,并检测到SD卡类型,读写文件。 待解决:打印目录及其内容执行有异常...       

  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO UDP收发测试

    udp rp2040串口打印信息:

  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO UDP收发测试

    UDP 测试pc端口    

  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO下TCP协议实现Webclient和WebServer

      web server 服务器端串口打印信息:  

  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO下TCP协议实现Webclient和WebServer

    web server客户端截屏:  

  • 2024-03-04
  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO下TCP协议实现Webclient和WebServer

    在pio中,rp2040的库没有ethernet或者有点乱,没找到。这里选用了外部第三方库,ethernet3为arduino生态中最新的库,并且适配了w5500,支持了rp2040(只需要“借用”一下硬件spi即可),通过测试,webclient成功从百度获取数据,说明移植没有问题。Webserver例程应该也没有问题,限于时间关系,今天没有测试成功,明天测试一下…

  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO 挂载SD卡并实现文件读写访问

    eew_9XVJps 发表于 2024-3-4 16:10 学习学习,修改这个SPI还挺复杂,之前研究过,没改过来,楼主这个介绍的很详细呀 希望对你有帮助其实核心就是sd卡各个class能够使用spi1和对应setting类中的参数访问到硬件spi1上就可以了。库本身应该都是能用的说起来简单,确实别人的东西改起来不顺利的话,会把自己整晕进去,然后重来一遍。rp2040说实话,pio的库比起8266和esp32起来,差的有点远,尤其是外部扩展应用上折腾这几天,收获很大

  • 回复了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO下TCP协议实现Webclient和WebServer

    成功从百度获取数据

  • 2024-03-03
  • 发表了日志: 【得捷Follow me第4期】W5500-EVB-Pico PIO FTP服务器测试

  • 发表了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO 挂载SD卡并实现文件读写访问

      本节实现功能:通过使用第三方SD库,实现PICO 访问外扩SD卡,并实现读取卡的信息、显示SD卡目录列表、文件读写访问... 1. 准备 下载SD卡扩展库 地址:https://github.com/khoih-prog/RP2040_SD  概述:This library enables you to use SPI SD cards with RP2040-based boards such as Nano_RP2040_Connect, RASPBERRY_PI_PICO using either RP2040 Arduino-mbed or arduino-pico core. This SD-Fat v2 can support FAT16, FAT32, exFAT file systems. exFAT supports files larger than 4GB by using uint64_t as file offset. 该库主要为RP2040而来,支持FAT16, FAT32, exFAT,同时支持容量大于4GB。 *但是该库内部使用了PICO的spi0,由于W5500连接了SPI0,这里需要做一些改动,使得外扩SD卡连接到SPI1。 2. 创建基础工程,并将下载的库复制到工程的lib文件夹中 /* SD card connection This example shows how to read an SD Card's CardInfo shows how to read and write data to and from an SD card file The circuit: SD card attached to SPI bus as follows: // Arduino-pico core ** MISO - pin 12 ** MOSI - pin 11 ** CS - pin 13 ** SCK - pin 10 */ #include <Arduino.h> #include <SPI.h> #include <RP2040_SD.h> #define _RP2040_SD_LOGLEVEL_ 1 #define PIN_SD_SS PIN_SPI1_SS // set up variables using the SD utility library functions: Sd2Card card; SdVolume volume; File root; #define fileName "example.txt" File myFile; uint32_t writeData = 0xDEADBEEF; uint32_t readData = 0; void printDirectory(File dir, int numTabs) { while (true) { File entry = dir.openNextFile(); if (! entry) { // no more files break; } for (uint8_t i = 0; i < numTabs; i++) { Serial.print('\t'); } Serial.print(entry.name()); if (entry.isDirectory()) { Serial.println("/"); printDirectory(entry, numTabs + 1); } else { // files have sizes, directories do not Serial.print("\t\t"); Serial.println(entry.size(), DEC); } entry.close(); } } bool checkFileExist(const char * fileNameInput) { // Check to see if the file exists now if (SD.exists(fileNameInput) ) { Serial.print(fileNameInput); Serial.println(" exists."); return true; } else { Serial.print(fileNameInput); Serial.println(" doesn't exist."); return false; } } void setup() { // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial); delay(1000); #if defined(ARDUINO_ARCH_MBED) Serial.print("Starting SD Card CardInfo on MBED "); #else Serial.print("Starting SD Card CardInfo on "); #endif Serial.println(BOARD_NAME); Serial.println(RP2040_SD_VERSION); Serial.print("Initializing SD card with SS = "); Serial.println(PIN_SPI1_SS); Serial.print("SCK = "); Serial.println(SPI1_SCK); Serial.print("MOSI = "); Serial.println(SPI1_MOSI); Serial.print("MISO = "); Serial.println(SPI1_MISO); // we'll use the initialization code from the utility libraries // since we're just testing if the card is working! if (!card.init(SPI_HALF_SPEED, PIN_SPI1_SS)) { Serial.println("initialization failed. Things to check:"); Serial.println("* is a card inserted?"); Serial.println("* is your wiring correct?"); Serial.println("* did you change the chipSelect pin to match your shield or module?"); while (1); } else { Serial.println("Wiring is correct and a card is present."); } // print the type of card Serial.println(); Serial.print("Card type: "); switch (card.type()) { case SD_CARD_TYPE_SD1: Serial.println("SD1"); break; case SD_CARD_TYPE_SD2: Serial.println("SD2"); break; case SD_CARD_TYPE_SDHC: Serial.println("SDHC"); break; default: Serial.println("Unknown"); } // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 if (!volume.init(card)) { Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); while (1); } Serial.print("Clusters: "); Serial.println(volume.clusterCount()); Serial.print("Blocks x Cluster: "); Serial.println(volume.blocksPerCluster()); Serial.print("Total Blocks: "); Serial.println(volume.blocksPerCluster() * volume.clusterCount()); Serial.println(); // print the type and size of the first FAT-type volume uint32_t volumesize; Serial.print("Volume type is: FAT"); Serial.println(volume.fatType(), DEC); volumesize = volume.blocksPerCluster(); // clusters are collections of blocks volumesize *= volume.clusterCount(); // we'll have a lot of clusters volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB) Serial.print("Volume size (Kb): "); Serial.println(volumesize); Serial.print("Volume size (Mb): "); volumesize /= 1024; Serial.println(volumesize); Serial.print("Volume size (Gb): "); Serial.println((float)volumesize / 1024.0); if (!SD.begin(PIN_SD_SS)) { Serial.println("Initialization failed!"); return; } Serial.println("Initialization done."); root = SD.open("/"); printDirectory(root, 0); Serial.println("read cardinfo done."); checkFileExist(fileName); // open a new file and immediately close it: Serial.print("Creating "); Serial.println(fileName); myFile = SD.open(fileName, FILE_WRITE); if (myFile) { myFile.write((uint8_t *) &writeData, sizeof(writeData)); Serial.print("writeData = 0x"); Serial.println(writeData, HEX); myFile.close(); } else { Serial.print("Error open for writing "); Serial.println(fileName); } myFile = SD.open(fileName, FILE_READ); if (myFile) { myFile.read((uint8_t *) &readData, sizeof(readData)); Serial.print("readData = 0x"); Serial.println(readData, HEX); myFile.close(); } else { Serial.print("Error open for reading "); Serial.println(fileName); } checkFileExist(fileName); // delete the file: Serial.println("Removing example.txt..."); SD.remove(fileName); checkFileExist(fileName); } void loop() { // nothing happens after setup finishes. } 第一步:定义全局对象 Sd2Card card; SdVolume volume; File root; 第二步:使用card.init()进行SD卡初始化,内部使用了SPI1。 第三步:根据card.type() 输出SD卡类型。 第四步:volume.init(card) SD卡卷的初始化,并打印显示SD卡卷信息。 第五步:再次SD.begin()初始化SD卡,SD.open("/")打开SD卡根目录。 第六步:printDirectory(root, 0);遍历SD卡目录并通过串口打印显示。 第七步:checkFileExist()检测文件是否存在SD卡中,并通过函数SD.open、File.write、File.close、File.read、SD.remove等实现文件打开、增删改查。   3. 需要修改的地方 3.1. \.platformio\packages\framework-arduino-mbed\variants\RASPBERRY_PI_PICO\pins_arduino.h 增加: // SPI1 #define PIN_SPI1_MISO (12u) #define PIN_SPI1_MOSI (11u) #define PIN_SPI1_SCK (10u) #define PIN_SPI1_SS (13u)   修改:#define SPI_HOWMANY     (1) (MBED的库默认仅设置了SPI0 引脚的相关宏定义) 为: #define SPI_HOWMANY (2) 增加: #define SPI1_MISO (digitalPinToPinName(PIN_SPI1_MISO)) #define SPI1_MOSI (digitalPinToPinName(PIN_SPI1_MOSI)) #define SPI1_SCK (digitalPinToPinName(PIN_SPI1_SCK))   spi.h和spi.c文件相关内容如下: spi1在定义的时候已经绑定了对应的引脚     3.2 RP2040_SD库下 RP2040_SD\src\utility\Sd2Card.cpp 修改 SDCARD_SPI SPI为: #define SDCARD_SPI SPI1        

  • 发表了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO下TCP协议实现Webclient和WebServer

    本帖最后由 wo4fisher 于 2024-3-2 16:25 编辑 1. 准备工作 新建基础工程,并添加Ethernet3库到工程中 2. WebClient测试 使用Tcp协议创建WebClient,连接远端服务器,并发送http请求,并打印返回数据 #include <Arduino.h> #include <SPI.h> #include <Ethernet3.h> // Enter a MAC address for your controller below. // Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // if you don't want to use DNS (and reduce your sketch size) // use the numeric IP instead of the name for the server: //IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) char server[] = "www.baidu.com"; // name address for Google (using DNS) // Set the static IP address to use if the DHCP fails to assign IPAddress ip(192, 168, 2, 177); IPAddress myDns(192, 168, 2, 1); // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): EthernetClient client; // Variables to measure the speed unsigned long beginMicros, endMicros; unsigned long byteCount = 0; bool printWebData = true; // set to false for better speed measurement uint8_t svrIp[4]= {0}; void setup() { // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Ethernet.setCsPin(17); Ethernet.setRstPin(20); // start the Ethernet connection: Serial.println("Initialize Ethernet with DHCP:"); if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // Check for Ethernet hardware link status if (Ethernet.link() == 0) { Serial.println("Ethernet cable is not connected."); } // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip, myDns); } else { Serial.print(" DHCP assigned IP "); Serial.println(Ethernet.localIP()); } // give the Ethernet shield a second to initialize: delay(1000); Serial.print("connecting to "); Serial.print(server); Serial.println("..."); // if you get a connection, report back via serial: if (client.connect(server, 80)) { Serial.print("connected to "); client.remoteIP(svrIp); Serial.print(svrIp[0]);Serial.print(','); Serial.print(svrIp[1]);Serial.print(','); Serial.print(svrIp[2]);Serial.print(','); Serial.print(svrIp[3]);Serial.println(); // Make a HTTP request: client.println("GET /search?q=arduino HTTP/1.1"); client.println("Host: www.baidu.com"); client.println("Connection: close"); client.println(); } else { // if you didn't get a connection to the server: Serial.println("connection failed"); } beginMicros = micros(); } void loop() { // if there are incoming bytes available // from the server, read them and print them: int len = client.available(); if (len > 0) { byte buffer[80]; if (len > 80) len = 80; client.read(buffer, len); if (printWebData) { Serial.write(buffer, len); // show in the serial monitor (slows some boards) } byteCount = byteCount + len; } // if the server's disconnected, stop the client: if (!client.connected()) { endMicros = micros(); Serial.println(); Serial.println("disconnecting."); client.stop(); Serial.print("Received "); Serial.print(byteCount); Serial.print(" bytes in "); float seconds = (float)(endMicros - beginMicros) / 1000000.0; Serial.print(seconds, 4); float rate = (float)byteCount / seconds / 1000.0; Serial.print(", rate = "); Serial.print(rate); Serial.print(" kbytes/second"); Serial.println(); // do nothing forevermore: while (true) { delay(1); } } } 实现过程: 第一步:定义mac地址、W5500 静态ip地址、DNS地址和web服务器主机ip名称。 第二步:定义EthernetClient。 第三步:在初始化函数setup中完成cs引脚和rst引脚的配置,调用begin函数完成W5500网络参数初始化(首先尝试动态分配,动态分配失败的话,使用静态分配方式进行初始化),接下来调用connect方法连接远端服务器。 第四步:在循环函数Loop中,当接收到返回数据,通过串口打印;断开连接的话,停止。   3. WebServer测试 创建WebServer服务器,如果客户端连接访问,返回pico ADC模数转换结果 #include <Arduino.h> #include <SPI.h> #include <Ethernet3.h> // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 2, 177); // Initialize the Ethernet server library // with the IP address and port you want to use // (port 80 is default for HTTP): EthernetServer server(80); uint8_t ClientIp[4]= {0}; void setup() { // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Ethernet.setCsPin(17); Ethernet.setRstPin(20); Serial.println("Ethernet WebServer Example"); // start the Ethernet connection and the server: Ethernet.begin(mac, ip); // start the server server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP()); } void loop() { // listen for incoming clients EthernetClient client = server.available(); if (client) { Serial.println("new client"); // an http request ends with a blank line boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { // send a standard http response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println("Refresh: 5"); // refresh the page automatically every 5 sec client.println(); client.println("<!DOCTYPE HTML>"); client.println("<html>"); int sensorReading = analogRead(A3); client.print("pico Voltage"); client.print(" is "); client.print(sensorReading); client.println("<br />"); client.println("</html>"); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); Serial.println("client disconnected"); } } 实现过程: 第一步:定义mac地址、W5500 静态ip地址。 第二步:定义EthernetServer,并使用默认80端口。 第三步:在初始化函数setup中完成cs引脚和rst引脚的配置,调用server.begin函数完成W5500网络参数初始化并启动Web服务器。 第四步:在循环函数Loop中,当有客户端连接请求,打印请求内容,之后,读取电源电压ADC转换值,并返回HTTP请求给客户端。  

  • 发表了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO通过NTP服务器获取网络时间

    本帖最后由 wo4fisher 于 2024-3-5 13:42 编辑 1. 可用的NTP服务器测试 使用如下的命令可以测试NTP授时服务器是否可用 w32tm /stripchart /computer:ntp_server_address ntp_server_address 可以是服务器主机名称,也可以是IP地址。 可用的NTP服务器地址: 国家授时中心 NTP 服务器      ntp.ntsc.ac.cn        114.118.7.161                114.118.7.163 中国 NTP 快速授时服务         cn.ntp.org.cn           223.113.97.98                119.29.26.206 教育网                                    edu.ntp.org.cn        202.118.1.130                 202.118.1.81 2. 新建基本工程并添加Ethernet3库文件到工程lib目录 3. 代码编辑   /* Udp NTP Client Get the time from a Network Time Protocol (NTP) time server Demonstrates use of UDP sendPacket and ReceivePacket For more on NTP time servers and the messages needed to communicate with them, see http://en.wikipedia.org/wiki/Network_Time_Protocol created 4 Sep 2010 by Michael Margolis modified 9 Apr 2012 by Tom Igoe modified 02 Sept 2015 by Arturo Guadalupi This code is in the public domain. */ #include <Arduino.h> #include <SPI.h> #include <Ethernet3.h> #include <EthernetUdp3.h> #define FOURYEARDAY (365 + 365 + 365 + 366) // 4年一个周期内的总天数(1970~2038不存在2100这类年份,故暂不优化) #define TIMEZONE (8) // 北京时区调整 typedef struct rtc_time_struct { uint16_t ui8Year; // 1970~2038 uint8_t ui8Month; // 1~12 uint8_t ui8DayOfMonth; // 1~31 uint8_t ui8Week; uint8_t ui8Hour; // 0~23 uint8_t ui8Minute; // 0~59 uint8_t ui8Second; // 0~59 } rtc_time_t; static uint8_t month_day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 平年 static uint8_t Leap_month_day[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 闰年 // static char weekCHS[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // Enter a MAC address for your controller below. // Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; unsigned int localPort = 8888; // local port to listen for UDP packets const char timeServer[] = "ntp.ntsc.ac.cn"; // time.nist.gov NTP server const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP EthernetUDP Udp; // 判断是否是闰年 return:1:闰年, 0: 平年 uint8_t isLeapYear(uint16_t year); // 将Unix时间戳转换为北京时间 void covUnixTimeStp2Beijing(uint32_t unixTime, rtc_time_t *tempBeijing); void setup() { // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Ethernet.setCsPin(17); Ethernet.setRstPin(20); // start Ethernet and UDP if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // no point in carrying on, so do nothing forevermore: for (;;) ; } Udp.begin(localPort); } void sendNTPpacket(const char *address); void loop() { sendNTPpacket(timeServer); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); if (Udp.parsePacket()) { // We've received a packet, read the data from it Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer // the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, extract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; Serial.print("Seconds since Jan 1 1900 = "); Serial.println(secsSince1900); // now convert NTP time into everyday time: Serial.print("Unix time = "); // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: unsigned long epoch = secsSince1900 - seventyYears; // print Unix time: Serial.println(epoch); // print the date & Time Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) rtc_time_t tempBeijing2; char dtBuf[30] = {0}; covUnixTimeStp2Beijing(epoch, &tempBeijing2); sprintf(dtBuf, "%d/%02d/%02d-%02d:%02d:%02d", tempBeijing2.ui8Year, tempBeijing2.ui8Month, tempBeijing2.ui8DayOfMonth, tempBeijing2.ui8Hour, tempBeijing2.ui8Minute, tempBeijing2.ui8Second); Serial.println(dtBuf); } // wait ten seconds before asking for the time again delay(6000); Ethernet.maintain(); } // send an NTP request to the time server at the given address void sendNTPpacket(const char *address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: Udp.beginPacket(address, 123); // NTP requests are to port 123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); } // 判断是否是闰年 // year: 需要判断的年 // return:1:闰年 // 0: 平年 uint8_t isLeapYear(uint16_t year) { uint8_t res = 0; if (year % 4 == 0) // 能够被4整除 { if ((year % 100 == 0) && (year % 400 != 0)) // 能够被100整除,但是不能够被400整除 { res = 0; } else { res = 1; } } return res; } // 将Unix时间戳转换为北京时间 // unixTime: 需要判断的Unix时间戳 // *tempBeijing:返回的北京时间 // return:none // note:没对输入参数正确性做判断 void covUnixTimeStp2Beijing(uint32_t unixTime, rtc_time_t *tempBeijing) { uint32_t totleDayNum = 0, totleSecNum = 0; uint16_t remainDayofYear = 0, tempYear = 0; uint8_t *pr = NULL; totleDayNum = unixTime / (24 * 60 * 60); // 总天数(注意加括号) totleSecNum = unixTime % (24 * 60 * 60); // 当天剩余的秒速 memset(tempBeijing, 0x00, sizeof(rtc_time_t)); // 1.先计算时间 HH:MM:SS tempBeijing->ui8Hour = totleSecNum / 3600; tempBeijing->ui8Minute = (totleSecNum % 3600) / 60; // error:变量搞错 tempBeijing->ui8Second = (totleSecNum % 3600) % 60; // 2.对时间进行时区调整(注意:这里可能造成日期 +1) tempBeijing->ui8Hour += TIMEZONE; if (tempBeijing->ui8Hour > 23) { // printf("modify day..\n"); tempBeijing->ui8Hour -= 24; remainDayofYear++; // 日期+1 } // 3.计算哪一年 tempBeijing->ui8Year = 1970 + (totleDayNum / FOURYEARDAY) * 4; // 4年为一个周期 remainDayofYear += totleDayNum % FOURYEARDAY; // printf("year:%d, day:%d.\n", tempBeijing->ui8Year, remainDayofYear); tempYear = isLeapYear(tempBeijing->ui8Year) ? 366 : 365; while (remainDayofYear >= tempYear) // 计算4年整数倍外的年。 { tempBeijing->ui8Year++; remainDayofYear -= tempYear; tempYear = isLeapYear(tempBeijing->ui8Year) ? 366 : 365; } // 4.计算哪一月的哪一天 pr = isLeapYear(tempBeijing->ui8Year) ? Leap_month_day : month_day; remainDayofYear++; // 这里开始计算具体日期。remainDayofYear为 0 时其实是 1 号,所以这里要 +1 while (remainDayofYear > *(pr + tempBeijing->ui8Month)) { remainDayofYear -= *(pr + tempBeijing->ui8Month); tempBeijing->ui8Month++; } // printf("year:%d, day:%d.\n", tempBeijing->ui8Year, remainDayofYear); tempBeijing->ui8Month++; // month tempBeijing->ui8DayOfMonth = remainDayofYear; // day // printf("year:%d, day:%d.\n", tempBeijing->ui8Year, tempBeijing->ui8DayOfMonth); } 主要步骤: 第一步:定义mac地址、本地端口、ntp服务器,并且定义UDP客户端EthernetUDP实例。 第二步:在初始化函数setup中使用Ethernet.begin函数初始化W5500网络参数,然后启动udp客户端: Udp.begin(localPort)。 第三步:在Loop函数中 首先向NTP服务器发送请求包sendNTPpacket(),然后解析接收到的应答数据包,并且分别显示自1900年开始的秒数、UNIX时间(即从1970年1月1日开始的秒数)和NTC时间的时分秒。 备注:中间有增加unix时间戳计算当前日期和时间的函数,没有计算星期几。    结果,NTP时间和右下角显示时间一致

  • 发表了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico PIO UDP收发测试

    本帖最后由 wo4fisher 于 2024-3-2 17:58 编辑 1. 新建基础工程并添加Ethernet3库文件到工程目录 2. UDP协议收发代码编辑 Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。 即UDP基于无连接,通过IP地址和端口即可以收发数据。 上代码: #include <Arduino.h> #include <SPI.h> // needed for Arduino versions later than 0018 #include <Ethernet3.h> #include <EthernetUdp3.h> // UDP library from: bjoern@cs.stanford.edu 12/30/2008 // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 2, 177); unsigned int localPort = 8888; // local port to listen on // buffers for receiving and sending data char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, char ReplyBuffer[] = "acknowledged"; // a string to send back // An EthernetUDP instance to let us send and receive packets over UDP EthernetUDP Udp; void setup() { Ethernet.setCsPin(17); Ethernet.setRstPin(20); // start the Ethernet and UDP: Ethernet.begin(mac, ip); Udp.begin(localPort); Serial.begin(115200); } void loop() { // if there's data available, read a packet int packetSize = Udp.parsePacket(); if (packetSize) { Serial.print("Received packet of size "); Serial.println(packetSize); Serial.print("From "); IPAddress remote = Udp.remoteIP(); for (int i = 0; i < 4; i++) { Serial.print(remote[i], DEC); if (i < 3) { Serial.print("."); } } Serial.print(", port "); Serial.println(Udp.remotePort()); // read the packet into packetBufffer Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); Serial.println("Contents:"); Serial.println(packetBuffer); // send a reply, to the IP address and port that sent us the packet we received Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); Udp.write(ReplyBuffer); Udp.endPacket(); } delay(10); } 主要步骤: 第一步:定义mac地址、本机ip地址、端口号和EthernetUDP 实例。 第二步:在setup中 初始化/定义cs引脚和rst引脚, Ethernet.begin(mac, ip);初始化网络参数 Udp.begin(localPort);启动UDP服务器 第三步:在loop中 监听Udp.parsePacket(),如果有数据,进行解析 Udp.read()读取数据并通过串口输出后,再通过Udp.write()函数进行应答。 other: UDP客户端实例就会以上例子反过来,因为UDP为无连接协议。因此 大概思路就是: 实例化UDP 封装发送数据 通过     Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());     Udp.write(ReplyBuffer);     Udp.endPacket(); 进行发送 然后解析、读取应答数据 Udp.parsePacket(); Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); 需要的话增加超时判断(可能没有应答)即可。  

  • 发表了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico platform IO下使用Ethernet3库设置静态IP

    本篇完成任务:使用arduino Ethernet3库,设置静态IP,连接远端服务器测试 1. Ethernet3库的获取 https://github.com/sstaub/Ethernet3 打开以上网址,克隆仓库文件到本地。 2. 新建项目 打开vs code,打开左侧的platform IO插件图标,打开home页。 在home页中,选择新建工程    输入关键字“pico”,然后在下边的列表中选择“Raspberry Pi Pico”,然后在name一栏中输入项目/工程名称:(如:pico_telnet_test)。   等一小会,待工程创建完毕。 3. 添加第三方库Ethernet3到工程中 工程创建完毕后,复制Ethernet3库文件夹至项目文件夹下的lib子文件夹下(在项目列表中,在任一文件上鼠标右键,选择在文件资源管理器中显示)。   添加完成后,可见code中资源管理器该工程下的lib子项下显示Ethernet3目录,说明添加成功。 4. 代码编写 在工程main.cpp中编辑如下代码: #include <Arduino.h> #include <SPI.h> #include <Ethernet3.h> // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 2, 186); // Enter the IP address of the server you're connecting to: IPAddress server(180,101,50,188); //www.baidu.com // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 23 is default for telnet; // if you're using Processing's ChatServer, use port 10002): EthernetClient client; void setup() { // start the Ethernet connection: Ethernet.setCsPin(17); Ethernet.setRstPin(20); Ethernet.begin(mac, ip); Serial.begin(115200); // give the Ethernet shield a second to initialize: delay(1000); Serial.println("connecting..."); // if you get a connection, report back via serial: if (client.connect(server, 80)) { Serial.println("connected"); } else { // if you didn't get a connection to the server: Serial.println("connection failed"); } } void loop() { /* *********** Telnet client test*********** */ // if there are incoming bytes available // from the server, read them and print them: if (client.available()) { char c = client.read(); Serial.print(c); } // as long as there are bytes in the serial queue, // read them and send them out the socket if it's open: while (Serial.available() > 0) { char inChar = Serial.read(); if (client.connected()) { client.print(inChar); } } // if the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); client.stop(); // do nothing: while (true); } }  说明: 第一步:引用头文件 第二步:定义mac地址(w5500)、IP静态地址、要连接的服务器IP地址(这里使用百度的ip)、   第三步:新建一个EthernetClient类型对象 第四步:在setup初始化函数中设置CS和rst引脚,并调用begin()函数/方法初始化W5500的网络参数。 初始化之后,使用connect函数连接远端服务器的指定端口,并输出连接情况、如果连接成功,输出服务器返回内容。  

  • 2024-03-02
  • 发表了日志: 【得捷Follow me第4期】W5500-EVB-Pico PIO 挂载SD卡并实现文件读写访问

  • 发表了日志: 【得捷Follow me第4期】W5500-EVB-Pico PIO UDP收发测试

最近访客

< 1/6 >

统计信息

已有2845人来访过

  • 芯积分:273
  • 好友:9
  • 主题:80
  • 回复:782

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言