一、前言(含视频)
本次Follow Me 4共分为4个任务:入门任务,基础任务,进阶任务和终极任务,其中,基础任务分为两个小任务,所以共六个任务,都顺利完成。
并且已经将内容一的视频上传至网络大学堂,视频地址为:https://training.eeworld.com.cn/video/39296 ;视频里包含了各任务的现场烧录演示及说明。
任务完成所用开发环境为Paspberry Pi的Pico SDK v1.5.1+VSCode;其中VSCode不多赘述,而Paspberry Pi的Pico SDK v1.5.1的下载地址为 ,安装过程可参考 WIZnet W5500-EVB-Pico树莓派入门教程(一)-CSDN博客;
任务完成所用硬件如下几个:W5500-EVB-Pico(必购);Pico-LCD 1.14(用于大部分的显示任务);AtomS3(W5500-EVB-Pico在做FTP服务器时,读取SD卡需要用的SPI,导致无法使用Pico-LCD做显示,通过UDP传输显示数据给AtomS3,用AtomS3做显示);SEEED XIAO ESP32 C3(测试W5500-EVB-Pico的UDP Server功能)、DAPLink一个(自备,用于在线仿真,方便调试网络)以及自己绘制的LCD转接板一个,方便给将W5500-EVB-Pico主板与Pico-LCD组合起来,转接板如下:
图1-1
下面将各任务逐一介绍并展示(内容二)。
二、入门任务
2.1 任务介绍
搭建开发环境,点亮小灯让其闪烁,并在显示屏上显示内容。
2.2 主要代码片段
LCD的显示主要靠移植Pico-LCD的官方驱动,其下载地址为 将其C驱动部分复制至工程目录下,并改名为LCD,在工程目录下的CMake中添加如下命令:
- add_subdirectory(DISPLAY/Config)
- add_subdirectory(DISPLAY/LCD)
- add_subdirectory(DISPLAY/Fonts)
- add_subdirectory(DISPLAY/GUI)
并在项目目录下的CMake中添加如下命令:
- include_directories(../DISPLAY/Config)
- include_directories(../DISPLAY/GUI)
- include_directories(../DISPLAY/LCD)
这样即包含了Pico-LCD的驱动库,初始化后就可直接显示输入内容,初始化过程如下:
- DEV_Module_Init();
- DEV_SET_PWM(30);
- LCD_1IN14_V2_Init(HORIZONTAL);
- LCD_1IN14_V2_Clear(BLACK);
-
- UDOUBLE Imagesize = LCD_1IN14_V2_HEIGHT*LCD_1IN14_V2_WIDTH*2;
- BlackImage = (UWORD *)malloc(Imagesize);
- Paint_NewImage((UBYTE *)BlackImage,LCD_1IN14_V2.WIDTH,LCD_1IN14_V2.HEIGHT, 0, BLACK);
- Paint_SetScale(65);
- Paint_SetRotate(ROTATE);
- Paint_Clear(BLACK);
- LCD_1IN14_V2_Display(BlackImage);
-
-
-
之后在Paint_DrawString_EN函数中输入字符串数组,显示坐标即可显示相应内容。
小灯的闪烁代码如下:
- const uint LED_PIN = PICO_DEFAULT_LED_PIN;
- gpio_init(LED_PIN);
- gpio_set_dir(LED_PIN, GPIO_OUT);
-
- while (true) {
- gpio_put(LED_PIN, 1);
- sleep_ms(250);
- gpio_put(LED_PIN, 0);
- sleep_ms(250);
- }
2.3 功能展示
图2-1 驱动显示屏(显示屏通过转接板叠加在主控板上)
三、基础任务一
3.1 任务介绍
主板W5500-EVB-Pico获取静态IP,并且PC能够ping通,同时主板可以ping通外网;PCping通结果抓包显示。
3.2 主要代码片段
需要用到W5500的官方库,其地址为https://gitee.com/wiznet-hk/w5500-evb-pico-routine.git
随后如同上述LCD添加入库,即可调用相关函数即可实现静态IP:只要初始化W5500完成,再设置网络信息,标记为静态获取即可。
-
- wiz_NetInfo net_info = {
- .mac = {0x00, 0x08, 0xdc, 0x1e, 0xed, 0x2e},
- .ip = {192, 168, 1, 31},
- .sn = {255, 255, 255, 0},
- .gw = {192, 168, 1, 1},
- .dns = {8, 8, 8, 8},
- };
-
- wizchip_initialize();
- sleep_ms(50);
- wizchip_setnetinfo(&net_info);
- print_network_information(get_info);
想要ping通互联网,则是向特定的目的主机发送 ICMP(Internet Control Message Protocol 因特网报文控制协议)Echo 请求报文,核心代码如下:
- void ping_auto(uint8_t s, uint8_t *addr)
- {
- uint8_t i;
- int32_t len = 0;
- uint8_t cnt=0;
- for(i = 0; i<=3;i++)
- {
- sleep_ms(10);
- switch(getSn_SR(s))
- {
- case SOCK_CLOSED:
- close(s);
- IINCHIP_WRITE(Sn_PROTO(s), IPPROTO_ICMP);
- if(socket(s,Sn_MR_IPRAW,3000,0)!=0)
- { }
- while(getSn_SR(s)!=SOCK_IPRAW);
- sleep_ms(2000);
- break;
-
- case SOCK_IPRAW:
- ping_request(s, addr);
- req++;
- sleep_ms(50);
- while(1)
- {
- if ( (len = getSn_RX_RSR(s) ) > 0)
- {
- ping_reply(s, addr, len);
- sleep_ms(50);
- rep++;
- break;
- }
- else if(cnt > 200)
- {
- printf( "Request Time out. \r\n");
- cnt = 0;
- break;
- }
- else
- {
- cnt++;
- sleep_ms(50); /*wait 50ms*/
- }
- // wait_time for 2 seconds, Break on fail
- }
-
- break;
- default:
- break;
- }
- #ifdef PING_DEBUG
- if(rep!=0)
- {
- printf("Ping Request = %d, PING_Reply = %d\r\n",req,rep);
- if(rep == req)
- printf( "PING SUCCESS\r\n " );
- else
- printf( "REPLY_ERROR\r\n " );
- }
- else{}
- #endif
- }
-
- }
3.3 功能展示
图3-1 PC端Ping主板成功图
图3-2 主控板Ping互联网成功串口输出图
四、基础任务二
4.1 任务介绍
主板W5500-EVB-Pico做UDP服务器,并能将PC端的UDP客户端发送内容显示在显示屏上,再抓包对比报文。同时使用SEEED XIAO ESP32 C3做UDP客户端进行测试。
4.2 核心代码片段
正常初始化网络即可,UDP主要涉及Socket,包含头文件 #include "socket.h" 即可,然后轮询状态(判断是否有数据传输等)即可,代码如下:
- int32_t udps_2(uint8_t sn, uint8_t* buf, uint16_t port)
- {
- int32_t ret;
- uint16_t size, sentsize;
- uint8_t destip[4];
- uint16_t destport;
-
- switch(getSn_SR(sn))
- {
- case SOCK_UDP :
- if((size = getSn_RX_RSR(sn)) > 0)
- {
- if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
- ret = recvfrom(sn, buf, size, destip, (uint16_t*)&destport);
- buf[ret]=0x00;
- // printf("recv from[%d.%d.%d.%d][%d]: %s\n", destip[0],destip[1],destip[2],destip[3],destport,buf);
- sprintf(RecvIP[RecvCnt], "> %d.%d.%d.%d:%d", destip[0],destip[1],destip[2],destip[3],destport);
- sprintf(RecvBuf[RecvCnt], "> %s", buf);
- ddebug(RecvIP[RecvCnt]);
- ddebug(RecvBuf[RecvCnt]);
- if(++RecvCnt >= 10) RecvCnt = 0;
- if(ret <= 0)
- {
- return ret;
- }
- size = (uint16_t) ret;
- sentsize = 0;
- while(sentsize != size)
- {
- ret = sendto(sn, buf+sentsize, size-sentsize, destip, destport);
- if(ret < 0)
- {
- return ret;
- }
- sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
- }
- }
- break;
- case SOCK_CLOSED:
- if((ret = socket(sn, Sn_MR_UDP, port, 0x00)) != sn)
- return ret;
- printf("local port:%d\n",port);
- break;
- default :
- break;
- }
- return 1;
- }
4.3 成果展示
先是用PC端的UDP(192.168.1.22:3333)发送Follow Me 4!到到主控板(192.168.1.31:8000),并用WireShark抓包(过滤条件为<ip.addr == 192.168.1.31 and udp>),显示如下:
图4-1 PC和主控板UDP通信抓包显示
再用SEED XIAO ESP32C3做UDP的客户端(192.168.1.45:8000)去测试主控板的UDP服务器功能,每3秒发送一次Follow Me 4!;同时通过显示屏展示收到的内容,完成情况如下:
图4-2 主控板显示屏显示UDP接收内容(包含主机和XIAOESP32C3)
五、进阶任务
5.1 任务内容
从NTP服务器同步时间,获取时间送显示屏显示。
5.2 核心代码片段
本质上还是UDP,这里选择用tx的NTP服务器,测试期间其地址为106.55.184.199;NTP及格式解析核心代码如下:
- // NTP
- int8_t SNTP_run(datetime *time)
- {
- uint16_t RSR_len;
- uint32_t destip = 0;
- uint16_t destport;
- uint16_t startindex = 40;
-
- switch(getSn_SR(NTP_SOCKET))
- {
- case SOCK_UDP:
- if ((RSR_len = getSn_RX_RSR(NTP_SOCKET)) > 0)
- {
- if (RSR_len > MAX_SNTP_BUF_SIZE) RSR_len = MAX_SNTP_BUF_SIZE;
- recvfrom(NTP_SOCKET, data_buf, RSR_len, (uint8_t *)&destip, &destport);
- get_seconds_from_ntp_server(data_buf,startindex);
- time->yy = Nowdatetime.yy;
- time->mo = Nowdatetime.mo;
- time->dd = Nowdatetime.dd;
- time->hh = Nowdatetime.hh;
- time->mm = Nowdatetime.mm;
- time->ss = Nowdatetime.ss;
-
- ntp_retry_cnt=0;
- close(NTP_SOCKET);
-
- return 1;
- }
-
- if(ntp_retry_cnt<0xFFFF)
- {
- if(ntp_retry_cnt==0)//first send request, no need to wait
- {
- sendto(NTP_SOCKET,ntpmessage,sizeof(ntpmessage),NTPformat.dstaddr,ntp_port);
- ntp_retry_cnt++;
- }
- else // send request again? it should wait for a while
- {
- if((ntp_retry_cnt % 0xFFF) == 0) //wait time
- {
- sendto(NTP_SOCKET,ntpmessage,sizeof(ntpmessage),NTPformat.dstaddr,ntp_port);
- ntp_retry_cnt++;
- }
- }
- }
- else //ntp retry fail
- {
- ntp_retry_cnt=0;
- close(NTP_SOCKET);
- }
- break;
- case SOCK_CLOSED:
- socket(NTP_SOCKET,Sn_MR_UDP,ntp_port,0);
- break;
- }
- return 0;
- }
- // 送显示
- sprintf(time_str[count], "> %d-%02d-%02d %02d:%02d:%02d", time.yy, time.mo, time.dd, time.hh, time.mm, time.ss);
- ddebug(time_str[count]);
5.3 成果展示
NTP实验内容较好展示,直接百度上搜索北京时间,然后对比即可,显示每1s才刷新一次,会存在误差,对比如下:
图5-1 左为浏览器显示北京时间 右为主控板每秒输出时间
六、最终任务
6.1 任务内容
使用外部SD卡存储器,组建简易FTP文件服务器,并能正常上传下载文件。同时因SD卡需占用一路SPI,故舍弃LCD,采用UDP传输给AtomS3用于显示FTP服务器相关内容。
6.2 核心代码片段
主要是SD卡和FatFs的移植,有现成的库,地址为 ;
设置静态IP,并修改并记住FTP的ID和密码,再开启Fatfs功能,需要修改部分代码,主要添加两个接口函数,scan_files和get_filesize,分别是扫描和获取大小,内容如下
- long get_filesize(const char *dirPath, const char *filename) {
- char fullPath[256];
- FILINFO fno;
- FRESULT fr;
-
-
- snprintf(fullPath, sizeof(fullPath), "%s/%s", dirPath, filename);
-
-
- fr = f_stat(fullPath, &fno);
- if (fr == FR_OK) {
- return (long)fno.fsize;
- } else {
- return -1;
- }
- }
-
- FRESULT scan_files (
- char *path,
- char *files,
- uint16_t *num)
- {
- FRESULT res;
- DIR dir;
- UINT i;
- static FILINFO fno;
- uint16_t _num = 0;
- *num = 0;
- res = f_opendir(&dir, path);
- if (res == FR_OK) {
- for (;;) {
- res = f_readdir(&dir, &fno);
- if (res != FR_OK || fno.fname[0] == 0) break;
- i = strlen(path);
- uint8_t isdir = (fno.fattrib & AM_DIR);
- char size[32];
- sprintf(size, "%ld", (fno.fattrib & AM_DIR) ? 0 : fno.fsize);
- files += sprintf(files, "%crwxr-xr-x 1 pomin pomin %s Jan 19 2024 %s\r\n", (fno.fattrib & AM_DIR) ? 'd' : '-', size, fno.fname);
- _num++;
- }
- f_closedir(&dir);
- }
- *num = _num;
- return res;
- }
6.3 成果展示
PC端使用Filezilla做FTP客户端,W5500烧录代码后,使用Filezilla连接,地址为192.168.1.31,ID为DIgikey,密码为Followme4,端口不用选择,默认为21,连接成功,并能上传下载文件,上传过程截图如下:
图6-1 PC向W5500主控板传输图片(速度200K/s)
虽说无法使用LCD了,但是怎么能没有显示屏呢?所以还用了AtomS3做UDP服务器,将W5500主控板通过UDP发送来的内容进行显示,当作W5500的显示屏,展示如下:
图6-2 AtomS3做主控板的显示器(演示中,上传了两张图片,下载了文本)
七、心得体会
首先是学到了不少东西,接触了RP2040、W5500、ESP32,对Cmake、Ethernet、WIFI等都有了更深的理解,然后最大的感悟还是,没想到嵌入式开发还能如此简单,很多库都是别人写好的,而rp2040引脚又少,调用起来非常简单,觉得嵌入式就该往这个方向发展,更多耗费时间的还得是逻辑与算法。再者就是群里的大佬太多了,见识到了很多,自己仍需努力,向大佬看齐,最后当然是感谢得捷,感谢EEWORLD,谢谢你们提供了这个宝贵的机会,也希望今后多多出这些活动,也祝你们越来越好!
八、附件
这里就是内容三了,已将全部源码打包并上传至:https://download.eeworld.com.cn/detail/Alohaq/631392 ;如果你也安装了Pico-sdk,那么只需要添加到pcio的vscode环境里,即可编译下载全部内容。
|