Harmony鸿蒙南向驱动开发-PWM

PWM(Pulse Width Modulation)即脉冲宽度调制,是一种对模拟信号电平进行数字编码并将其转换为脉冲的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。通常情况下,在使用马达控制、背光亮度调节时会用到PWM模块。

基本概念

脉冲是“电脉冲”的简称,指电路中电流或电压短暂起伏的现象,其特点是突变和不连续性。脉冲的种类很多,常见的脉冲波形有:三角脉冲、尖脉冲、矩形脉冲、方形脉冲、梯形脉冲及阶梯脉冲等。脉冲的主要参数包括重复周期T(T=1/F,F为重复频率)、脉冲幅度U、脉冲前沿上升时间ts、后沿下降时间t、脉冲宽度tk等。

运作机制

在HDF框架中,PWM接口适配模式采用独立服务模式(如图1所示)。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDF设备管理器的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。

独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为:

  • 驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。

  • device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。

PWM模块各分层作用:

  • 接口层提供打开PWM设备、设置PWM设备周期、设置PWM设备占空时间、设置PWM设备极性、设置PWM设备参数、获取PWM设备参数、使能PWM设备、禁止PWM设备、关闭PWM设备的接口。

  • 核心层主要提供PWM控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互。

  • 适配层主要是将钩子函数的功能实例化,实现具体的功能。

图 1 PWM独立服务模式结构图

PWM独立服务模式结构图

开发指导

场景介绍

PWM用于脉冲宽度调制,当驱动开发者需要将PWM设备适配到OpenHarmony时,需要进行PWM驱动适配。下文将介绍如何进行PWM驱动适配。

接口说明

为了保证上层在调用PWM接口时能够正确的操作PWM控制器,核心层在//drivers/hdf_core/framework/support/platform/include/pwm/pwm_core.h中定义了以下钩子函数,驱动适配者需要在适配层实现这些函数的具体功能,并与钩子函数挂接,从而完成适配层与核心层的交互。

PwmMethod定义:

struct PwmMethod {int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config);int32_t (*open)(struct PwmDev *pwm);int32_t (*close)(struct PwmDev *pwm);
};

表 1 PwmMethod结构体成员的钩子函数功能说明

成员函数入参返回值功能
setConfigpwm:结构体指针,核心层PWM控制器
config:结构体指针,传入设置得设备属性
HDF_STATUS相关状态配置属性
openpwm:结构体指针,核心层PWM控制器HDF_STATUS相关状态打开PWM设备
closepwm:结构体指针,核心层PWM控制器HDF_STATUS相关状态关闭PWM设备

开发步骤

PWM模块适配包含以下四个步骤:

  • 驱实例化驱动入口

  • 配置属性文件

  • 实例化PWM控制器对象

  • 驱动调试

开发实例

下方将基于Hi3516DV300开发板以//device/soc/hisilicon/common/platform/pwm/pwm_hi35xx.c驱动为示例,展示需要驱动适配者提供哪些内容来完整实现设备功能。

  1. 驱实例化驱动入口

    驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。

    一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。

    PWM驱动入口开发参考:

    struct HdfDriverEntry g_hdfPwm = {.moduleVersion = 1,.moduleName = "HDF_PLATFORM_PWM",    // 【必要且与HCS文件中里面的moduleName匹配】.Bind = HdfPwmBind,                  // 挂接PWM模块Bind实例化.Init = HdfPwmInit,                  // 挂接PWM模块Init实例化.Release = HdfPwmRelease,            // 挂接PWM模块Release实例化
    };
    HDF_INIT(g_hdfPwm);                      // 调用HDF_INIT将驱动入口注册到HDF框架中
  2. 配置属性文件

    完成驱动入口注册之后,需要在device_info.hcs文件中添加deviceNode信息,deviceNode信息与驱动入口注册相关。本例以两个PWM控制器为例,如有多个器件信息,则需要在device_info.hcs文件增加对应的deviceNode信息,以及在pwm_config.hcs文件中增加对应的器件属性。器件属性值与核心层PwmDev成员的默认值或限制范围有密切关系,比如PWM设备号,需要在pwm_config.hcs文件中增加对应的器件属性。

    独立服务模式的特点是device_info.hcs文件中设备节点代表着一个设备对象,如果存在多个设备对象,则按需添加,注意服务名与驱动私有数据匹配的关键字名称必须唯一。其中各项参数如表2所示:

    表 2 device_info.hcs节点参数说明

    成员名
    policy驱动服务发布的策略,PWM控制器具体配置为2,表示驱动对内核态和用户态都发布服务
    priority驱动启动优先级(0-200),值越大优先级越低。PWM控制器具体配置为80
    permission驱动创建设备节点权限,PWM控制器具体配置为0664
    moduleName驱动名称,PWM控制器固定为HDF_PLATFORM_PWM
    serviceName驱动对外发布服务的名称,PWM控制器服务名设置为HDF_PLATFORM_PWM_X,X代表PWM控制器编号
    deviceMatchAttr驱动私有数据匹配的关键字,PWM控制器设置为hisilicon_hi35xx_pwm_X,X代表PWM控制器编号
    • device_info.hcs 配置参考:

      在//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode描述。

      root {device_info { platform :: host {hostName = "platform_host";priority = 50;device_pwm :: device {                                 // 为每一个PWM控制器配置一个HDF设备节点device0 :: deviceNode {policy = 2;                                    // policy字段是驱动服务发布的策略,如果需要面向用户态,则为2priority = 80;                                 // 驱动启动优先级permission = 0644;                             // 驱动创建设备节点权限moduleName = "HDF_PLATFORM_PWM";               // 【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致serviceName = "HDF_PLATFORM_PWM_0";            // 【必要且唯一】驱动对外发布服务的名称deviceMatchAttr = "hisilicon_hi35xx_pwm_0";    // 【必要】用于配置控制器私有数据,要与pwm_config.hcs中对应控制器保持一致,具体的控制器信息在pwm_config.hcs中}device1 :: deviceNode {policy = 2;priority = 80;permission = 0644;moduleName = "HDF_PLATFORM_PWM";serviceName = "HDF_PLATFORM_PWM_1";deviceMatchAttr = "hisilicon_hi35xx_pwm_1";}......                                                 // 如果存在多个PWM设备时【必须】添加节点,否则不用}}}
      }
    • pwm_config.hcs 配置参考

      在//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs文件配置器件属性,其中配置参数如下:

      root {platform {pwm_config {template pwm_device {                       // 【必要】配置模板,如果下面节点使用时继承该模板,则节点中未声明的字段会使用该模板中的默认值serviceName = "";match_attr = "";num = 0;                                // 【必要】设备号base = 0x12070000;                      // 【必要】地址映射需要}device_0x12070000 :: pwm_device {           // 存在多个设备时,请逐一添加相关HDF节点和设备节点信息。match_attr = "hisilicon_hi35xx_pwm_0";  // 【必要】需要和device_info.hcs中的deviceMatchAttr值一致}device_0x12070020 :: pwm_device {match_attr = "hisilicon_hi35xx_pwm_1";num = 1;base = 0x12070020;                      // 【必要】地址映射需要}......                                      // 如果存在多个PWM设备时【必须】添加节点,否则不用}}
      }

      需要注意的是,新增pwm_config.hcs配置文件后,必须在产品对应的hdf.hcs文件中将其包含如下语句所示,否则配置文件无法生效。

      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs" // 配置文件相对路径
  3. 实例化PWM控制器对象

    完成驱动入口注册之后,下一步就是以核心层PwmDev对象的初始化为核心,包括驱动适配者自定义结构体(传递参数和数据),实例化PwmDev成员PwmMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind、Init、Release)。

    • 驱动适配者自定义结构体参考。

      从驱动的角度看,驱动适配者自定义结构体是参数和数据的载体,而且pwm_config.hcs文件中的数值会被HDF读入并通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如PWM设备号。

      struct HiPwm {struct PwmDev dev;                // 【必要】 核是核心层控制对象volatile unsigned char *base;     // 【必要】地址映射需要,寄存器基地址struct HiPwmRegs *reg;            // 设备属性结构体,可自定义。bool supportPolarity;             // 是否支持极性
      };struct PwmDev {                       // PwmDev是核心层控制器结构体,其中的成员在Init函数中会被赋值。struct IDeviceIoService service;  // 驱动服务struct HdfDeviceObject *device;   // 驱动设备对象struct PwmConfig cfg;             // 设备属性结构体,相关定义见下。struct PwmMethod *method;         // 钩子函数bool busy;                        // 是否繁忙uint32_t num;                     // 设备号OsalSpinlock lock;                // 自旋锁void *priv;                       // 私有数据
      };struct PwmConfig {                    // PWM设备属性uint32_t duty;                    // 占空时间 nanosecondsuint32_t period;                  // pwm 周期 nanosecondsuint32_t number;                  // pwm 连续个数uint8_t polarity;                 // Polarity// ------------------- | --------------// PWM_NORMAL_POLARITY | Normal polarity// PWM_INVERTED_POLARITY | Inverted polarity//uint8_t status;                   // 运行状态// ------------------ | -----------------// PWM_DISABLE_STATUS | Disabled// PWM_ENABLE_STATUS  | Enabled
      };
    • PwmDev成员钩子函数结构体PwmMethod的实例化,其他成员在Init函数中初始化。

      struct PwmMethod g_pwmOps = {         // pwm_hi35xx.c中的示例:钩子函数实例化.setConfig = HiPwmSetConfig,      // 配置属性
      };
    • Init函数开发参考

      入参:

      HdfDeviceObject:HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。

      返回值:

      HDF_STATUS相关状态(表3为部分展示,如需使用其他状态,可参考//drivers/hdf_core/interfaces/inner_api/utils/hdf_base.h中HDF_STATUS定义)。

      表 3 HDF_STATUS相关状态说明

      状态(值)问题描述
      HDF_ERR_INVALID_OBJECT控制器对象非法
      HDF_ERR_MALLOC_FAIL内存分配失败
      HDF_ERR_INVALID_PARAM参数非法
      HDF_ERR_IOI/O 错误
      HDF_SUCCESS初始化成功
      HDF_FAILURE初始化失败

      函数说明:

      初始化自定义结构体对象,初始化PwmDev成员,调用核心层PwmDeviceAdd函数,完成PWM控制器的添加。

      // 此处Bind函数为空函数,可与Init函数结合,也可根据驱动适配者需要实现相关操作。
      static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
      {(void)obj;return HDF_SUCCESS;
      }static int32_t HdfPwmInit(struct HdfDeviceObject *obj)
      {int ret;struct HiPwm *hp = NULL;......hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp));......ret = HiPwmProbe(hp, obj);                                 // 【必要】实现见下......return ret;static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj)
      {uint32_t tmp;struct DeviceResourceIface *iface = NULL;iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); // 初始化自定义结构体HiPwm......hp->reg = (struct HiPwmRegs *)hp->base;                    // 初始化自定义结构体HiPwmhp->supportPolarity = false;                               // 初始化自定义结构体HiPwmhp->dev.method = &g_pwmOps;                                // PwmMethod的实例化对象的挂载hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE;                 // 初始化PwmDevhp->dev.cfg.period = PWM_DEFAULT_PERIOD;                   // 初始化PwmDevhp->dev.cfg.polarity = PWM_DEFAULT_POLARITY;               // 初始化PwmDevhp->dev.cfg.status = PWM_DISABLE_STATUS;                   // 初始化PwmDevhp->dev.cfg.number = 0;                                    // 初始化PwmDevhp->dev.busy = false;                                      // 初始化PwmDevif (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {        // 【重要】调用核心层函数,初始化hp->dev的设备和服务。OsalIoUnmap((void *)hp->base);return HDF_FAILURE;}return HDF_SUCCESS;
      }
    • Release函数开发参考

      入参:

      HdfDeviceObject:HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口。

      返回值:

      无。

      函数说明:

      释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。

      static void HdfPwmRelease(struct HdfDeviceObject *obj)
      {struct HiPwm *hp = NULL;......hp = (struct HiPwm *)obj->service;        // 这里有HdfDeviceObject到HiPwm的强制转化......                                       PwmDeviceRemove(obj, &(hp->dev));         // 【必要】调用核心层函数,释放PwmDev的设备和服务,这里有HiPwm到PwmDev的强制转化。HiPwmRemove(hp);                          // 释放HiPwm
      }
  4. 驱动调试

    【可选】针对新增驱动程序,建议验证驱动基本功能,例如PWM控制状态等。

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/304315.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据降维方法-主成分分析(PCA)

目录 一、前言 二、向量的表示及基变换 三、基变换 四、协方差矩阵 五、协方差 六、优化目标 一、前言 主成分分析(Principal Component Analysis) 用途:降维中的常用手段 目标:提取最有价值的信息(基于方差) 问题&#x…

Acwing.4009 收集卡牌(期望dp)

题目 小林在玩一个抽卡游戏,其中有 n种不同的卡牌,编号为 1到 n。 每一次抽卡,她获得第 i种卡牌的概率为 pi。 如果这张卡牌之前已经获得过了,就会转化为一枚硬币。 可以用 k枚硬币交换一张没有获得过的卡。 小林会一直抽卡&…

最祥解决python 将Dataframe格式数据上传数据库所碰到的问题

碰到的问题 上传Datafrane格式的数据到数据库 会碰见很多错误 举几个很普遍遇到的问题(主要以SqlServer举例) 这里解释下 将截断字符串或二进制数据 这个是字符长度超过数据库设置的长度 然后还有字符转int失败 或者字符串转换日期/或时间失败 这个是碰到的需要解决的最多的问…

网站HTTP升级成为HTTPS的方法

将网站从HTTP免费升级为HTTPS,您可以按照以下步骤操作: 1. 选择证书颁发机构(CA): - 为了免费升级,您可以选择使用JoySSL这样的公益项目。JoySSL提供免费、自动化的SSL/TLS证书颁发服务,适用于各…

三、Mat、Bitmap和Image数据类型之间的转换(OpenCvSharp)

在OpenCV中可以通过ImRead方法读取照片,通过ImShow方法显示照片;但是无法在PictureBox控件中显示 PictureBox控件只能展示Bitmap和Image数据类型图片 为此查阅了网上很多篇博文,将三种数据类型之间的转换进行了归纳整理,感谢网上…

【Qt】:对话框(一)

对话框 一.基本的对话框二.自定义对话框三.通过图形化界面自定义对话框四.关于对话框mode 对话框是GUI程序中不可或缺的组成部分。一些不适合在主窗口实现的功能组件可以设置在对话框中。对话框通常是一个顶层窗口,出现在程序最上层,用于实现短期任务或者…

【mT5多语言翻译】之一——实战项目总览

[1] 总览 【mT5多语言翻译】系列共六篇文章: 【mT5多语言翻译】之一——实战项目总览   【mT5多语言翻译】之二——模型:T5模型与mT5模型与前置知识   【mT5多语言翻译】之三——数据集:多语言翻译数据集与预处理   【mT5多语言翻译】之…

cesium 添加动态波纹效果 圆形扩散效果 波纹材质

一、扩展材质 /*** 水波纹扩散材质* param {*} options* param {String} options.color 颜色* param {Number} options.duration 持续时间 毫秒* param {Number} options.count 波浪数量* param {Number} options.gradient 渐变曲率*/function CircleWaveMaterialProperty(opt…

代码随想录--数组--移除元素

题目 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度…

Win11 使用 WSL2 安装 linux 子系统 ubuntu

Win11 使用 WSL2 安装 linux 子系统 ubuntu 段子手168 1、用 部署映像服务和管理工具 dism.exe 命令,开启 WSL2 按【WIN R】,打开【运行】,输入:【cmd】,管理员打开【命令行提示符】。 启用适用于 Linux 的 Windo…

PHP自助建站系统,小白也能自己搭建网站

无需懂代码,用 自助建站 做企业官网就像做PPT一样简单,您可以亲自操刀做想要的效果! 自助建站是一款简单、快捷、高效的工具,可以帮助您制作响应式网站。我们的自助建站系统,将传统的编码工作转化为直观的拖拽操作和文…

python 有哪些函数

Python内置的函数及其用法。为了方便记忆,已经有很多开发者将这些内置函数进行了如下分类: 数学运算(7个) 类型转换(24个) 序列操作(8个) 对象操作(7个) 反射操作(8个) 变量操作(2个) 交互操作(2个) 文件操作(1个) 编译执行(4个) 装饰器(3个) …

STM32H7通用定时器计数功能的使用

目录 概述 1 STM32定时器介绍 1.1 认识通用定时器 1.2 通用定时器的特征 1.3 递增计数模式 1.4 时钟选择 2 STM32Cube配置定时器时钟 2.1 配置定时器参数 2.2 配置定时器时钟 3 STM32H7定时器使用 3.1 认识定时器的数据结构 3.2 计数功能实现 4 测试案例 4.1 代码…

3D Matching:实现halcon中的find_surface_model

halcon中的三维匹配大致分为两类,一类是基于形状的(Shape-Based),一类是基于表面的(Surface-Based)。基于形状的匹配可用于单个2D图像中定位复杂的3D物体,3D物体模型必须是CAD模型,且几何边缘清晰可见,使用的相机也要预…

废品回收 小程序+APP

用户实名认证、回收员实名认证、后台审核、会员管理、回收员管理、订单管理、提现管理、地图、档案管理。 支持,安卓APP、苹果APP、小程序 流程: 一、用户端下单,地图选择上门位置、填写具体位置、废品名称、预估重量、选择是企业废旧、家…

嵌入式ARM版本银河麒麟操作系统V10SP1安装OPenGauss数据库

前言: 官网提供了非常完整的openGauss安装步骤。 https://opengauss.org/zh/download/archive/列举一下个人的使用环境: 麒麟V10 rk3588工控板(ARM) openGauss-3.0.5(极简版)浏览一下官网,可以…

14款DevOps/SRE工具,助力提升运维效率

简介 随着平台工程的兴起,DevOps 和 SRE 不断发展,带来了新一代工具,旨在提高软件开发和运维的效率、可扩展性和可靠性。 在本篇文章中,我们将深入探讨一些最具发展前景的工具,它们正在塑造持续集成与部署、监控与可观…

特征融合篇 | YOLOv8改进之将Neck网络更换为多级特征融合金字塔HS-FPN | 助力小目标检测

前言:Hello大家好,我是小哥谈。HS-FPN(Hierarchical Scale Feature Pyramid Network)是一种用于目标检测任务的网络结构。它是在传统的Feature Pyramid Network(FPN)基础上进行改进的。HS-FPN的主要目标是解决目标检测中存在的多尺度问题。在传统的FPN中,通过在不同层级…

【网站项目】校园失物招领小程序

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…

上线数日暴涨600%市值直逼节点猴,Runestone符石为何成第二大比特币NFT?

NodeMonkes(节点猴)市值超越BAYC成为第二大NFT之际,凭借着不断上涨的市场热度和人气,符文项目Runestone在空投数日后也成功跻身为比特币生态市值第二大NFT。Runestone高共识背后的动因有哪些?又有哪些策略具有借鉴意义…