Zynq 裸机 PS + PL 双网口实现之 lwip 库文件修改
基于 xilinx vivado 2017.4 库文件 lwip141_v2_0 的修改:
-
添加对 PHY 芯片 ksz9031 的支持;
-
添加 SDK 中 LWIP 参数设置对话框 emio_options 选项;
-
添加
XPAR_GMII2RGMIICON_0N_ETH0_ADDR和XPAR_GMII2RGMIICON_0N_ETH1_ADDR宏配置; -
支持 Zynq 裸机双网口通信实现
测试环境:
-
Vivado 2017.4
-
黑金 Zynq 7035 板卡,芯片型号:XC7Z035-2FFG676I
-
ETHERNET0 连接 PS 端网口,ETHERNET1 通过 EMIO 连接 PL端网口
修改内容:
1. 修改 lwip141_v2_0\src\contrib\ports\xilinx\netif\xaxiemacif_physpeed.c 文件
添加宏定义:
#define MICREL_PHY_IDENTIFIER 0x22
#define MICREL_PHY_KSZ9031_MODEL 0x220
添加 phy 芯片 ksz9031 速度获取函数:
unsigned int get_phy_speed_ksz9031(XAxiEthernet *xaxiemacp, u32 phy_addr)
{u16 control;u16 status;u16 partner_capabilities;xil_printf("Start PHY autonegotiation \r\n");XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, &control);//control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;control &= ~(0x10);XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, control);XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);control |= IEEE_ASYMMETRIC_PAUSE_MASK;control |= IEEE_PAUSE_MASK;control |= ADVERTISE_100;control |= ADVERTISE_10;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,&control);control |= ADVERTISE_1000;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,control);XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,&control);control |= (7 << 12); /* max number of gigabit attempts */control |= (1 << 11); /* enable downshift */XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,control);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;control |= IEEE_STAT_AUTONEGOTIATE_RESTART;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_RESET_MASK;XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);while (1) {XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);if (control & IEEE_CTRL_RESET_MASK)continue;elsebreak;}xil_printf("Waiting for PHY to complete autonegotiation.\r\n");XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {sleep(1);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET,&status);}xil_printf("autonegotiation complete \r\n");XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 0x1f, &partner_capabilities);if ( (partner_capabilities & 0x40) == 0x40)/* 1000Mbps */return 1000;else if ( (partner_capabilities & 0x20) == 0x20)/* 100Mbps */return 100;else if ( (partner_capabilities & 0x10) == 0x10)/* 10Mbps */return 10;elsereturn 0;
}
修改 get_IEEE_phy_speed 函数,添加对 ksz9031 的支持:
unsigned get_IEEE_phy_speed(XAxiEthernet *xaxiemacp)
{u16 phy_identifier;u16 phy_model;u8 phytype;#ifdef XPAR_AXIETHERNET_0_BASEADDRu32 phy_addr = detect_phy(xaxiemacp);/* Get the PHY Identifier and Model number */XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_1_REG, &phy_identifier);XAxiEthernet_PhyRead(xaxiemacp, phy_addr, PHY_IDENTIFIER_2_REG, &phy_model);/* Depending upon what manufacturer PHY is connected, a different mask is* needed to determine the specific model number of the PHY. */if (phy_identifier == MARVEL_PHY_IDENTIFIER) {phy_model = phy_model & MARVEL_PHY_MODEL_NUM_MASK;if (phy_model == MARVEL_PHY_88E1116R_MODEL) {return get_phy_speed_88E1116R(xaxiemacp, phy_addr);} else if (phy_model == MARVEL_PHY_88E1111_MODEL) {return get_phy_speed_88E1111(xaxiemacp, phy_addr);}} else if (phy_identifier == TI_PHY_IDENTIFIER) {phy_model = phy_model & TI_PHY_DP83867_MODEL;phytype = XAxiEthernet_GetPhysicalInterface(xaxiemacp);if (phy_model == TI_PHY_DP83867_MODEL && phytype == XAE_PHY_TYPE_SGMII) {return get_phy_speed_TI_DP83867_SGMII(xaxiemacp, phy_addr);}if (phy_model == TI_PHY_DP83867_MODEL) {return get_phy_speed_TI_DP83867(xaxiemacp, phy_addr);}}else if(phy_identifier == MICREL_PHY_IDENTIFIER){xil_printf("Phy %d is KSZ9031\n\r", phy_addr);return get_phy_speed_ksz9031(xaxiemacp, phy_addr);}else {LWIP_DEBUGF(NETIF_DEBUG, ("XAxiEthernet get_IEEE_phy_speed: Detected PHY with unknown identifier/model.\r\n"));}
#endif
#ifdef PCM_PMA_CORE_PRESENTreturn get_phy_negotiated_speed(xaxiemacp, phy_addr);
#endif
}
2. 修改 lwip141_v2_0\src\contrib\ports\xilinx\netif\xemacpsif_physpeed.c 文件
添加宏定义:
#define MICREL_PHY_IDENTIFIER 0x22
#define MICREL_PHY_KSZ9031_MODEL 0x220
添加 phy 芯片 ksz9031 速度获取函数:
static u32_t get_phy_speed_ksz9031(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t temp;u16_t control;u16_t status;u16_t status_speed;u32_t timeout_counter = 0;u32_t temp_speed;u32_t phyregtemp;xil_printf("Start PHY autonegotiation \r\n");XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);control |= IEEE_ASYMMETRIC_PAUSE_MASK;control |= IEEE_PAUSE_MASK;control |= ADVERTISE_100;control |= ADVERTISE_10;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,&control);control |= ADVERTISE_1000;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,control);XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,&control);control |= (7 << 12); /* max number of gigabit attempts */control |= (1 << 11); /* enable downshift */XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;control |= IEEE_STAT_AUTONEGOTIATE_RESTART;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);control |= IEEE_CTRL_RESET_MASK;XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);while (1) {XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);if (control & IEEE_CTRL_RESET_MASK)continue;elsebreak;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);xil_printf("Waiting for PHY to complete autonegotiation.\r\n");while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {sleep(1);XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);timeout_counter++;if (timeout_counter == 30) {xil_printf("Auto negotiation error \r\n");return;}XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);}xil_printf("autonegotiation complete \r\n");XEmacPs_PhyRead(xemacpsp, phy_addr,0x1f,&status_speed);if ( (status_speed & 0x40) == 0x40)/* 1000Mbps */return 1000;else if ( (status_speed & 0x20) == 0x20)/* 100Mbps */return 100;else if ( (status_speed & 0x10) == 0x10)/* 10Mbps */return 10;elsereturn 0;return XST_SUCCESS;
}
修改 get_IEEE_phy_speed 函数,添加对 ksz9031 的支持:
static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
{u16_t phy_identity;u32_t RetStatus;XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,&phy_identity);if(phy_identity == MICREL_PHY_IDENTIFIER){RetStatus = get_phy_speed_ksz9031(xemacpsp, phy_addr);}else if (phy_identity == PHY_TI_IDENTIFIER) {RetStatus = get_TI_phy_speed(xemacpsp, phy_addr);} else {RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);}return RetStatus;
}
修改 lwip141_v2_0\data\lwip141.mld 文件
添加如下字段:
BEGIN CATEGORY emio_optionsPARAM name = emio_options, desc = "Settings for ETH using EMIO in PL";PARAM name = use_gmii2rgmii_core_on_eth0, desc = "Settings for ETH0 using GMII to RGMII ip core in PL", type = bool, default = false;PARAM name = use_gmii2rgmii_core_on_eth1, desc = "Settings for ETH1 using GMII to RGMII ip core in PL", type = bool, default = false;PARAM name = gmii2rgmii_core_address_on_eth0, desc = "Settings for ETH0's PHY address of GMII to RGMII ip core in PL", type = int, default = 0;PARAM name = gmii2rgmii_core_address_on_eth1, desc = "Settings for ETH1's PHY address of GMII to RGMII ip core in PL", type = int, default = 0;END CATEGORY
SDK Bsp‘s Settins 效果如图所示:

3. 修改 lwip141_v2_0\data\lwip141.tcl 文件
在 proc generate_lwip_opts {libhandle} 所在的大括号内添加如下字段:
# EMIO optionsset use_gmii2rgmii_core_on_eth0 [common::get_property CONFIG.use_gmii2rgmii_core_on_eth0 $libhandle]set use_gmii2rgmii_core_on_eth1 [common::get_property CONFIG.use_gmii2rgmii_core_on_eth1 $libhandle]set gmii2rgmii_core_address_on_eth0 [common::get_property CONFIG.gmii2rgmii_core_address_on_eth0 $libhandle]set gmii2rgmii_core_address_on_eth1 [common::get_property CONFIG.gmii2rgmii_core_address_on_eth1 $libhandle]if { $use_gmii2rgmii_core_on_eth0 == true } {puts $lwipopts_fd "\#define XPAR_GMII2RGMIICON_0N_ETH1_ADDR $gmii2rgmii_core_address_on_eth0"}if { $use_gmii2rgmii_core_on_eth1 == true } {puts $lwipopts_fd "\#define XPAR_GMII2RGMIICON_0N_ETH1_ADDR $gmii2rgmii_core_address_on_eth1"}
GitHub 链接:链接
相关文章:
Zynq 裸机 PS + PL 双网口实现之 lwip 库文件修改
基于 xilinx vivado 2017.4 库文件 lwip141_v2_0 的修改: 添加对 PHY 芯片 ksz9031 的支持; 添加 SDK 中 LWIP 参数设置对话框 emio_options 选项; 添加 XPAR_GMII2RGMIICON_0N_ETH0_ADDR 和 XPAR_GMII2RGMIICON_0N_ETH1_ADDR 宏配置&#…...
金三银四丨黑蛋老师带你剖析-CTF岗
作者丨黑蛋二进制是个庞大的方向,对应着许许多多方向的岗位,除了之前说过的逆向岗位,漏洞岗位,病毒岗位,还有专门打CTF的岗位,CTF是网络安全领域的一种比赛。普遍来讲,大学生学习网络安全都会参…...
Linux find命令
哈喽,大家好,我是有勇气的牛排(全网同名)🐮 有问题的小伙伴欢迎在文末评论,点赞、收藏是对我最大的支持!!!。 1 介绍 find命令用来查找置顶目录下的文件。任何位于参数…...
vue项目实现会议预约(包含某天的某个时间段和某月的某几天)
一、一天的时间段预约 会议预约有以下操作: 1.点击预约按钮,弹窗最近一周的预约时间点(半小时一个点),预约时间为5:00到24:00; 2.超过当前时间的时间点不允许再预约,已经预约的时间不允许再预约,…...
javacv桌面推送 通过推送和拉取udp组播视频流实现
ffmpeg udp 推流拉流命令单播推流E:/工具/ffmpeg/ffmpeg -f gdigrab -r 23 -i desktop -pkt_size 1316 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f h264 udp://192.168.1.20:5001拉流ffplay -f h264 udp://192.168.1.20:5001 -fflags nobuffer -nofind_strea…...
2022年直播电商成交额,更是达到了24816亿元的成交额
近年来移动网络覆盖率、网速提升,直播行业不在是陌生的行业,直播也诞生了繁多的领域,游戏直播、户外直播等,当然还有今天的主题“直播带货”。直播带货是线上销售模式的一种,由衷是为了更好的把商品展示给用户观看&…...
【学习总结】2023寒假总结
写在前面时光匆匆,白驹过隙,转眼间寒假就过去了,这次寒假可以算的上是最长的一次假期,经历了从疫情到放开,从患病到阳康,在现实与虚幻的世界中玩耍,在痛苦的数据结构中徘徊,在每次早…...
宝塔搭建实战php源码人才求职管理系统后台端thinkphp源码(一)
大家好啊,我是测评君,欢迎来到web测评。 在开源社区里看到了这一套系统,骑士人才系统SE版,搭建测试了,感觉很不错。能够帮助一些想做招聘平台的朋友降低开发成本,就是要注意,想商业使用的话&…...
stk 根据六根数文件生成卫星轨迹(一)
先简单介绍下上面的参数。 Propagator预报轨道模型。 TwoBody为二体(开普勒运动模型)。HPOP为高精度轨道模型。目前只用到这两个。 下图为六根数参数 Orbit Epoch:为根数时间(UTC) Semimajor Axis:长半…...
深度学习算法面试常问问题(一)
博主秋招遇到的面试问题以及整理其他面经相关问题,无偿分享~ 项目叙述: 算法需求及应用场景算法的调研和初步方案的制定数据的准备(包括数据标注和数据增强)算法的介绍(包括输入和输出,loss、backbone、训…...
Spring 底层原理与解析 - 容器接口
Spring 底层原理与解析 - 容器接口 BeanFactory 能做哪些事 BeanFactory 与 ApplicaiotnContext 到底是谁提前做完了对象的加载 在之前的一篇关于 Spring 的文章Spring IoC 与容器的初始化中提到过,BeanFactory 接口与 ApplicationContext 接口之间的关系 可以看…...
Compose-Navigation简单案例上手
Navigation 快速上手 下面案例简要展示使用 Compose 版本的 Navigation 库来实现两个页面之间的跳转 这是完整的结构(忽略掉红线划过的那个包) 安装适用于 kotlin 的 navigation 依赖 dependencies {implementation("androidx.navigation:navigati…...
855. 考场就座
题目 考场就座 在考场里,一排有 N 个座位,分别编号为 0, 1, 2, …, N-1 。 当学生进入考场后,他必须坐在能够使他与离他最近的人之间的距离达到最大化的座位上。如果有多个这样的座位,他会坐在编号最小的座位上。(另外…...
k8s之ingress(二)
文章目录k8s之ingress1.1、Kubernetes 暴露服务的方式:1.2 基本概念1.3为什么需要Ingress资源1.4 Ingress的工作原理1.5ingress 暴露服务的方式总结k8s之ingress 1.1、Kubernetes 暴露服务的方式: Kubernetes暴露服务的方式目前只有三种:LoadBlancer Service、Nod…...
linux下监测串口数据
在编写上下位机通信代码时,需要分阶段测试,确保下位机,线路,上位机都OK. 一.检查设备数据传出 1.确定下位机的串口参数 如果波特率有问题,可能会…...
【面试之闭包】前端面试那些事(2)三分钟深入理解闭包(附详解实例)
目录1、什么是闭包,什么是作用域1.1 变量作用域1.2 闭包是啥?如何改变变量调用格局1.3 闭包的特性2、怎么用闭包,闭包实例应用2.1 常见闭包实例2.2 闭包异步函数的应用2.3 柯里化的应用3、闭包的优缺点3.1 优点3.2 缺点4、片尾彩蛋【写在前面…...
深入浅出带你学习WebSphere中间件漏洞
前言 上一篇文章给大家介绍了中间件glassfish的一些常见漏洞以及利用方法,今天我给大家带来的是WebSphere中间件的常见漏洞以及这些漏洞的利用方法,下面我们首先介绍一下WebSphere中间件是什么,然后展开来讲关于该中间件的漏洞。 WebSphere…...
如何一眼分辨是C还是C++
C语言的历史C语言是由贝尔实验室的Dennis Ritchie在20世纪70年代初开发的一种通用程序设计语言。在早期的计算机时代,许多计算机使用不同的汇编语言编写程序,这导致了程序的可移植性和代码的可重用性很低。因此,Dennis Ritchie在开发C语言时试…...
CMake系列:正确使用多配置编译系统
目录 常见错误 问题现象 正确做法 if指令应该什么时候使用 活学活用 把IF指令用于多配置编译系统是很多初学者容易犯下的错误。这篇文章启示性的教你如何正确理解、使用CMake的多配置编译系统。 常见错误 以Debug和Release配置有不同的宏定义为例,如下所示&a…...
PCB中的HDI板生产中的变化
关键词:HDI概述 HDI发展演变 HDI生产难点如果把一整个电子产业比作浩瀚的宇宙,那些智能电子设备就像宇宙中闪耀的星光,当你以“上帝”的视角手持放大镜去观察时,这些闪烁的星光点点其实都是一个个由精密的“自然规律”所“设计”好…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
