【得捷Follow me第4期】+小白手把手带你学习rp2040+w5500(所有任务)
[复制链接]
总结视频:
【得捷Follow me第4期】+小白手把手带你学习rp2040+w5500(所有任务)
可编译下载的代码:
download.eeworld.com.cn/detail/lihuahua/631259
一、入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld)
0.1 开发环境搭建(在ubuntu环境下使用clion进行C开发)
1、更新软件包列表,不进行实际升级操作:
book@100ask:~$ sudo apt-get update
2、安装git工具:
book@100ask:~$ sudo apt-get install git
3、安装python:
book@100ask:~$ sudo apt-get install python-tk python3-tk
4、拉取树莓派sdk文件:
book@100ask:~$ git clone
5、进入pico-setup路径,并修改文件“pico-setup.sh”,需要注释一些代码:
book@100ask:~/rp2040/pico-setup$ vi pico-setup.sh
6、安装“pico_setup.sh “:
book@100ask:~/rp2040/pico-setup$ ./pico_setup.sh
7、安装clion-IDE:
book@100ask:~/rp2040/pico-setup$ sudo snap install clion –classic
8、拉取树莓派工程生成软件包:
book@100ask:~/rp2040/pico-setup$ cd ..
book@100ask:~/rp2040$ git clone
9、重新打开终端,修改sdk的路径:
book@100ask:~/rp2040/pico-setup$ ls
pico pico-project-generator pico_setup.sh
book@100ask:~/rp2040/pico-setup$ pwd
/home/book/rp2040/pico-setup
book@100ask:~/rp2040/pico-setup$ echo "export PICO_SDK_PATH=/home/book/rp2040/pico-setup" >> .bashrc
10、安装树莓派工程生成软件:
book@100ask:~/rp2040/pico-setup$ cd pico-project-generator
11、打开树莓派工程生成软件:
book@100ask:~/rp2040/pico-setup/pico-project-generator$ ./pico_project.py --gui
12、通过clion打开刚刚生成的工程:
12.1将工程路径中的头文件所在文件夹告诉编译器:
12.2将工程路径中的源文件告诉cmake:被编译的c文件左上角有蓝色方块标记
12.3工程编译:
13、程序烧录
按下BOOT和RESET,然板子复位
松开RESET(BOOT仍按下),然板子进入BOOT
等电脑上弹出RPI-RP2的盘符(文件夹)后,可松开BOOT
然后把编译后的uf2固件拖拽到这个盘中即可
拖拽成功后,盘符会自动消失,此时固件烧录工作即完成
Pico会重新启动,开始运行程序
14、安装网络数据检测软件:
book@100ask:~$ sudo add-apt-repository ppa:wireshark-dev/stable
book@100ask:~$ sudo apt update
book@100ask:~$ sudo apt install
book@100ask:~$ sudo usermod -aG wireshark $USER
0.2 BLINK:GPIO25
0.3 串口HelloWorld:
将rp2040开发板的GP0引脚连接到串口调试助手的RXD引脚
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
int main()
{
stdio_init_all();
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
while(1){
gpio_put(LED_PIN, 1);
sleep_ms(500);
gpio_put(LED_PIN, 0);
sleep_ms(250);
printf("hello world!\n")
}
}
二、基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。
将笔记本wifi的因特网共享给有线网卡:
通过网线连接W5100和PC的网口。
Rp2040的ip设置为:192.168.137.110
虚拟机中的Ubuntu ping树莓派rp2040结果:
主机PC ping树莓派:
使用抓包软件Wireshark抓取ubuntu的ping报文:
使用过滤器找到需要的数据包:
输入icmp协议找到ping包:
通过ip地址筛选:ip.addr==192.168.137.110
第一行:物理层
第二行:数据链路层,数据来源于什么设备,发往什么设备
第三行:网络层ipv4协议
第四行:icmp应用层协议
根据type和code获得当前数据包的类型,下图为ping请求数据包
树莓派dns转换:
树莓派ping百度:
本任务需要官方sdk包的支持:
将sdk包中的以下文件放入工程文件中:
主函数:
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/spi.h"
#include "hardware/i2c.h"
#include "inc/raspberry26x32.h"
#include "inc/ssd1306_font.h"
#include "inc/ssd1306_i2c.h"
#include "inc/wizchip_conf.h"
#include "inc/w5500.h"
#include "inc/w5500_spi.h"
#include "inc/dns.h"
#include "inc/loopback.h"
#include "inc/ping.h"
//定义了一个全局变量net_info来存储网卡地址信息
static wiz_NetInfo net_info = {
.mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},//mac地址
.ip = {192, 168, 137, 110}, //IP地址
.sn = {255, 255, 255, 0}, //子网掩码
.gw = {192, 168, 137, 1}, //默认网关
.dns = {8, 8, 8, 8}, //dns信息
.dhcp = NETINFO_STATIC}; //DHCP模式为静态地址模式
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
#define SOCKET_ID 0
int dns_test(void);
bool repeating_timer_callback(struct repeating_timer *t);
void do_ping(void);
wiz_NetInfo get_info;
static uint8_t ethernet_buf_dns[ETHERNET_BUF_MAX_SIZE] = {0,};
uint8_t DNS_2nd[4] = {114,114,114,114};
uint8_t Domain_name[] = "www.baidu.com"; //需要的解析域名
uint8_t Domain_IP[4] = {0,}; //域名IP地址
uint8_t g_msec_cnt = 0;
static uint8_t ethernet_buf_ping[ETHERNET_BUF_MAX_SIZE] = {0,};
static uint8_t destip[4]={192, 168, 137, 1};
static uint16_t destport = 8080;
static uint16_t local_port =8000;
int main()
{
/*---------------------------------LED-GPIO-CONFIGURATION---------------------------------------*/
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
/*---------------------------------W5500-CONFIGURATION---------------------------------------*/
struct repeating_timer timer;
stdio_init_all(); //串口重定义到printf函数
sleep_ms(2000);
wizchip_initialize(); //初始化
sleep_ms(5000);
printf("W5500 network install example.\r\n");
wizchip_setnetinfo(&net_info); //设置网卡信息
print_network_information(get_info);
printf("W5500 dns test example.\r\n");
DNS_init(0,ethernet_buf_dns); //传入一个socket端口号和dns信息的接收缓存buff地址
add_repeating_timer_ms(1000, repeating_timer_callback, NULL, &timer);
while (true) {
if (dns_test()){
while(true){
do_ping();
if(req>=4)
{
while (true) {
gpio_put(LED_PIN, 1);
sleep_ms(500);
gpio_put(LED_PIN, 0);
sleep_ms(250);
}
}
}
}
sleep_ms(2000);
}
}
int dns_test(void)
{
int ret;
printf("\r\n===== DNS Client Example =====\r\n");
printf("> DNS 1st: %d.%d.%d.%d\r\n",net_info.dns[0],net_info.dns[1],net_info.dns[2],net_info.dns[3]);
printf("> DNS 2nd: %d.%d.%d.%d\r\n",DNS_2nd[0],DNS_2nd[1],DNS_2nd[2],DNS_2nd[3]);
printf("==============================\r\n");
printf("> Example Domain Name : %s\r\n",Domain_name);
//dns服务器ip,请求解析的域名,以及解析后ip存放的地址
if((ret = DNS_run(net_info.dns, Domain_name, Domain_IP)) > 0)
{
printf("> 1st DNS Reponsed\r\n");
}
else if((ret != -1) && ((ret = DNS_run(DNS_2nd, Domain_name, Domain_IP)) > 0))
{
printf("> 2nd DNS Responsed\r\n");
}
else if(ret == -1)
{
printf("> MAX_DOMAIN_NAME is too small. Should be redefined it. \r\n");
}
else
{
printf("> DNS Failed\r\n");
}
if(ret > 0)
{
printf("> Translated %s to %d.%d.%d.%d\r\n",Domain_name,Domain_IP[0],Domain_IP[1],Domain_IP[2],Domain_IP[3]);
return 1;
}
return 0;
}
/* Timer */
bool repeating_timer_callback(struct repeating_timer *t)
{
DNS_time_handler();
return true;
}
void do_ping(void)
{
printf("------------PING_TEST_START-----------------------\r\n");
sleep_ms(1000); // wait 1000ms
//ping_auto(0,destip); //传入一个socket端口号和需要Ping的对象IP信息,成功则返回Ping的信息,Ping失败则打印失败的信息
ping_auto(0,Domain_IP);
}
三、基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)
更改笔记本电脑有线网口ip为:192.168.0.18
rp2040+w5500的ip设置为:192.168.0.110
报文分析:
主函数:
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
#include "inc/wizchip_conf.h"
#include "inc/w5500_spi.h"
#include "inc/loopback.h"
//定义了一个全局变量net_info来存储网卡地址信息
static wiz_NetInfo net_info = {
.mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},//mac地址
.ip = {192, 168, 0, 110}, //IP地址
.sn = {255, 255, 255, 0}, //子网掩码
.gw = {192, 168, 0, 1}, //默认网关
.dns = {8, 8, 8, 8}, //dns信息
.dhcp = NETINFO_STATIC}; //DHCP模式为静态地址模式
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
#define SOCKET_ID 0
wiz_NetInfo get_info;
static uint8_t ethernet_buf_tcpclient[ETHERNET_BUF_MAX_SIZE] = {0,};
static uint16_t local_port_tcpclient = 8080;
int main()
{
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
struct repeating_timer timer;
stdio_init_all(); //串口重定义到printf函数
wizchip_initialize(); //初始化
printf("W5500 network install example.\r\n");
wizchip_setnetinfo(&net_info); //设置网卡信息
print_network_information(get_info);
sleep_ms(200);
printf("W5500 tcp server example.\r\n");
while(true)
{
//tcp服务端的回环测试函数:socket端口号、收发数据的缓存和端口
loopback_tcps(SOCKET_ID, ethernet_buf_tcpclient, local_port_tcpclient);
gpio_put(LED_PIN, 1);
sleep_ms(250);
gpio_put(LED_PIN, 0);
sleep_ms(250);
}
}
三、进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。
NTP报文格式
NTP报文格式如上图所示,它的字段含义参考如下:
LI 闰秒标识器,占用2个bit
VN 版本号,占用3个bits,表示NTP的版本号,现在为3
Mode 模式,占用3个bits,表示模式
stratum(层),占用8个bits
Poll 测试间隔,占用8个bits,表示连续信息之间的最大间隔
Precision 精度,占用8个bits,,表示本地时钟精度
Root Delay根时延,占用8个bits,表示在主参考源之间往返的总共时延
Root Dispersion根离散,占用8个bits,表示在主参考源有关的名义错误
Reference Identifier参考时钟标识符,占用8个bits,用来标识特殊的参考源
参考时间戳,64bits时间戳,本地时钟被修改的最新时间。
原始时间戳,客户端发送的时间,64bits。
接受时间戳,服务端接受到的时间,64bits。
传送时间戳,服务端送出应答的时间,64bits。
认证符(可选项)
主函数:
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "inc/wizchip_conf.h"
#include "inc/w5500_spi.h"
#include "inc/sntp.h"
//定义了一个全局变量net_info来存储网卡地址信息
static wiz_NetInfo net_info = {
.mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},//mac地址
.ip = {192, 168, 137, 110}, //IP地址
.sn = {255, 255, 255, 0}, //子网掩码
.gw = {192, 168, 137, 1}, //默认网关
.dns = {8, 8, 8, 8}, //dns信息
.dhcp = NETINFO_STATIC}; //DHCP模式为静态地址模式
wiz_NetInfo get_info;
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
#define SOCKET_SNTP 0
#define TIMEZONE 39 // China
static uint8_t ethernet_buf_ntp[ETHERNET_BUF_MAX_SIZE] = {0,};
static uint8_t g_sntp_server_ip[4] = {203, 107, 6, 88};
datetime time={0};
int main()
{
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
struct repeating_timer timer;
stdio_init_all(); //串口重定义到printf函数
sleep_ms(2000);
wizchip_initialize(); //初始化
sleep_ms(5000);
printf("W5500 network install example.\r\n");
wizchip_setnetinfo(&net_info); //设置网卡信息
print_network_information(get_info);
sleep_ms(200);
printf("W5500 ntp example.\r\n");
SNTP_init(SOCKET_SNTP,g_sntp_server_ip,TIMEZONE,ethernet_buf_ntp);
while(true)
{
//tcp服务端的回环测试函数:socket端口号、收发数据的缓存和端口
SNTP_run(&time);
printf(" %d-%d-%d, %d:%d:%d\n", time.yy, time.mo, time.dd, time.hh, time.mm, time.ss);
gpio_put(LED_PIN, 1);
sleep_ms(200);
gpio_put(LED_PIN, 0);
sleep_ms(800);
}
}
四、终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。
硬件连线:
软件架构:
终极任务在thonny环境下使用python完成:
1、首先安装thonny开发环境(建议下载最新版本,否则有些插件搜不到):https://thonny.org/
2、然后下载固件:https://micropython.org/download/W5500_EVB_PICO/
3、线路连接:将tf卡模块的3v3、GND、cs、MOSI、CLK、MISO引脚分别连接到rp2040开发板的3v3、GND、GP13、GP11、GP10、GP12引脚。
4、Thonny安装sdcard库:工具-管理包
5、参考链接 ,使用库中的uftpd.py文件,更改标签为“start”的代码:
# start listening for ftp connections on port 21
def start(host='0.0.0.0',port=21, verbose=0, splash=True):
global ftpsockets, datasocket
global verbose_l
global client_list
global client_busy
alloc_emergency_exception_buf(100)
verbose_l = verbose
client_list = []
client_busy = False
addr = socket.getaddrinfo(host, port)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr[0][4])
sock.listen(1)
sock.setsockopt(socket.SOL_SOCKET,
_SO_REGISTER_HANDLER,
lambda s : accept_ftp_connect(s,host))
ftpsockets.append(sock)
if splash:
print("FTP server started on {}:{}".format(host, port))
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
datasocket.bind(('0.0.0.0', _DATA_PORT))
datasocket.listen(1)
datasocket.settimeout(10)
6、主函数代码为:
import network,time
from machine import Pin,SPI
#w5500 初始化
def w5x00_init():
spi=SPI(0,2_000_000, mosi=Pin(19),miso=Pin(16),sck=Pin(18))#初始化SPI外设接口,用于wiznet芯片通信与控制
nic = network.WIZNET5K(spi,Pin(17),Pin(20)) #spi,cs,reset pin
nic.active(True)#网络激活
#配置静态网络信息
nic.ifconfig(('192.168.137.110','255.255.255.0','192.168.137.1','8.8.8.8'))
while not nic.isconnected():#当网络未配置成功时
time.sleep(1)
print(nic.ifconfig())#打印IP、子网掩码、网关、DNS
def sdcard_init():
import os
from sdcard import SDCard
from machine import Pin,SPI
#sd卡模块连接到rp2040的spi1外设
spi = SPI(1,2_000_000,sck=Pin(10), mosi=Pin(11), miso=Pin(12))
#spi,cs
sd = SDCard(spi, Pin(13))
# 挂载SD卡到/sd目录
os.mount(sd, '/sd')
print(f'success mounted sdcard in /sd')
if __name__ == "__main__":
# 初始化网络
w5x00_init()
# 初始化并挂在sd卡
sdcard_init()
import uftpd
uftpd.start(host = '192.168.137.110',port = 21,verbose = 0)
7、实验结果
五、对本次活动的心得体会:
本人接触嵌入式有5年时间,大多偏向于单片机底层,对网络协议一知半解,故很高兴能有机会参加本次活动。通过本次活动,我学习了rp2040在linux环境下的开发、windows-thonny环境下的开发,学习了ubuntu的基本命令、python的基本语法、基本网络拓扑结构、ping操作、dns的功能、tcp服务器的原理、从ntp服务器同步时间、基于tf卡建立ftp服务器。
刚接触任务时,我采用thonny开发,但我不太熟悉python,故有些吃力,看到w5500官方有专门的c-sdk,所以我最后采用了linux环境下的clion开发,这对熟悉c语言的同学很友好。前几个任务w5500官方基本都有sdk例程参考,所以我很轻松的完成了任务。终极任务因为python环境下有github参考例程,故终极任务采用python语言开发。
六、参考链接:
eeworld follow me4教程:W5500-EVB-Pico 使用入门-直播回放: FollowMe 4 W5500-EVB-Pico 使用入门-EEWORLD大学堂
w5500官方csdn教程:WIZnet W5500-EVB-Pico C/C++教程_WIZnet的博客-CSDN博客
w5500官方c-sdk:
|