Autosar --- CAN Driver标准解读

前言

        本文是对Autosar文档的翻译与解读,通过对规范的理解,加上实际的应用来一一对应,方便大家更好的理解。

        注意:本文并非完全的按照【AUTOSAR_SWS_CANDriver.pdf】来进行翻译的。文章内容的标题与【AUTOSAR_SWS_CANDriver.pdf】保持一致。

一、导言和功能描述

1.CAN模块是最底层的一部分,负责硬件访问,并为上层提供独立于硬件的应用程序接口。

2.能访问CAN Driver模块的上层是CANIF模块

3.CAN模块提供启动传输的服务,并调用CanIf模块的回调函数来通知事件,与硬件无关,

五、与其他模块的依赖关系

5.5 文件结构

        Can_GeneralTypes.h应包含AUTOSAR CAN 模块 Can、CanIf 和 CanTrcv 共享的所有类型和常量。

        下图截取了一部分与CAN相关的内容,主要为CAN控制器状态的一些枚举值,以及数据传输的结构,还有故障状态的一些值。可以在这个头文件中查找到。

七、功能规格

7.2 驱动程序状态机

Can 模块的状态机非常简单,只有 CAN_UNINIT 和 CAN_READY 两种状态。

上电/复位后,Can 模块应处于 CAN_UNINIT 状态。

在初始化硬件单元内的所有控制器后,函数 Can_Init 应将模块状态更改为CAN_READY。

必须通过调用函数 Can_SetControllerMode(CAN_CS_STARTED)来分别启动每个 CAN 控制器。

即:在执行完Can_Init初始化之后,我们想要使用哪一个CAN硬件单元(CAN1,CAN2,CAN3等等),必须调用Can_SetControllerMode(CANn,CAN_CS_STARTED)来使能这个硬件单元。

7.3 CAN控制器状态机

CAN控制器有四种基本状态:未启动(UNINIT)、停止(STOPPED)、启动(STARTED)和休眠(SLEEP)。

7.3.1 CAN 控制器状态说明

UNINIT:CAN 控制器未初始化。CAN 模块的所有寄存器均处于复位状态,CAN 中断被禁用。

STOPPED:CAN 控制器被初始化,但不参与总线。此外,不得发送错误帧和确认信息。

STARTED:控制器处于具有完整功能的正常运行模式,这意味着它参与了网络。对于许多控制器
来说,离开 "初始化 "模式会导致控制器启动

SLEEP:当 CAN 硬件支持睡眠模式并被触发过渡到 SLEEP 状态时,Can 模块应将控制器设置为 SLEEP 状态,并可通过 CAN 总线从该状态唤醒硬件。(一般外部CAN控制器都支持休眠)

                当 CAN 硬件不支持睡眠模式并被触发过渡到 SLEEP 状态时,CAN 模块应模拟逻辑 SLEEP 状态,只有当它被软件触发过渡到 STOPPED 状态时,才会从该状态返回。

7.3.2 CAN 控制器状态转换

        这些状态的切换,都可以通过函数Can_SetControllerMode()来控制。回调函数(CanIf_ControllerModeIndication)会通知软件触发的成功状态转换。监控是否达
到所要求的状态是上层模块的一部分,而不是 Can 模块的一部分。

7.3.3 函数 Can_Init 引起的状态转换

        函数 Can_Init 应将所有 CAN 控制器设置为 STOPPED 状态

        当进入函数 Can_Init 时,如果 Can 模块未处于 CAN_UNINIT 状态,或者 CAN 控制器未处于 UNINIT 状态,则会出现 CAN_E_TRANSITION 错误。

7.3.4 函数 Can_SetBaudrate 引起的状态转换

        如果调用 Can_SetBaudrate()会导致 CAN 控制器重新初始化,且 CAN 控制器未处于 STOPPED 状态,则应返回 E_NOT_OK

        如果需要重新初始化,函数 Can_SetBaudrate 应将 CAN控制器保持在 STOPPED 状态。

7.3.5 函数 Can_SetControllerMode 引起的状态转换

        软件可以通过函数 Can_SetControllerMode 触发 CAN 控制器状态转换,过渡到新的 CAN 控制器状态可能需要延迟一段时间。Can 模块会在状态转换成功后将新状态通知上层(
CanIf_ControllerModeIndication)。

         Can_SetControllerMode (CAN_CS_STARTED) 引起的状态转换: ▪ 停止 🡪 开始 ▪ 软件触发

当进入 Can_SetControllerMode (CAN_CS_STARTED) 功能且CAN 控制器未处于 STOPPED 状态时,应检测到无效的状态转换​​​, 引发错误 CAN_E_TRANSITION,返回E_NOT_OK.

        Can_SetControllerMode (CAN_CS_STOPPED) 引起的状态转换:

 ▪ 开始 🡪 停止         ▪ 睡眠 🡪 停止        ▪ 软件触发

        Can_SetControllerMode(CAN_CS_SLEEP)引起的状态转换:▪ 停止了 🡪睡眠      ▪ 软件触发

当进入 Can_SetControllerMode(CAN_CS_SLEEP)函数时,CAN 控制器既没有处于 STOPPED 状态,也没有处于 SLEEP 状态,它应检测到无效的状态转换,引发错误 CAN_E_TRANSITION,返回E_NOT_OK.

7.3.6 硬件事件导致的状态转换

        硬件唤醒(支持改功能)引起的状态转换(由 CAN 总线的唤醒事件触发):▪ 睡眠 🡪 停止

7.3.7 函数 Can_DeInit 引起的状态转换

- STOPPED -> UNINIT;SLEEP -> UNINIT(适用于硬件单元中的所有控制器)

7.5 L-PDU 传输

        在传输 L-PDU 时,Can 模块会将 L-PDU 内容 ID 和数据长度转换为硬件特定格式(如有必要),并触发传输。最先发送的CAN数据字节是数组元素0,最后发送的CAN数据字节是数组元素7,如果是CAN FD,则是数组元素63。

        Can 模块应调用 CanIf_TxConfirmation 来表示传输成功。它应由相应硬件资源的 TX 中断服务例程调用,或在轮询模式下由Can_MainFunction_Write 内部调用。

下面为代码示例↓↓↓


在这个函数里,我们可以单独创立一个flag,并将传输的结果赋值给这个flag, 上层通过判断这个flag来确认CAN数据传输是否完成。

详细的关于【CanIf_TxConfirmation 】内容,会在【AUTOSAR_SWS_CANInterface】章节中有讲解。

7.5.1 优先级反转

内部优先级反转

"如果只使用一个发送缓冲器,可能会出现内部优先级倒置。由于优先级较低,存储在缓冲器中的信息需要等待 "总线上的流量平静下来"。在等待期间,该信息可能会阻止同一微控制器生成的优先级更高的信息通过总线传输"

外部优先级反转

"在某些 CAN 实现中可能会出现外部优先级倒置的问题。假设一个 CAN 节点希望传输一包具有高优先级的连续报文,这些报文存储在不同的报文缓冲区中。如果 CAN 网络上这些报文之间的帧间距长于 CAN 标准规定的最小间距,第二个节点就会开始传输优先级较低的报文。最小帧间距由 Intermission 字段决定,该字段由 3 个隐性比特组成。在传输另一条报文期间待处理的报文将在总线空闲期间启动,最早启动时间为 "中场休息 "字段后面的位。例外情况是,有等待传输报文的节点会将 Intermission 字段第三位的显性位理解为帧开始位,并从第一个标识符位开始传输,而不首先传输 SOF 位。CAN 模块的内部处理时间必须足够短,以便以最小的帧间空间发送连续报文,从而避免上述所有情况下的外部优先级倒置。

7.6 接收 L-PDU

        接收到 L-PDU 时,Can 模块应调用 RX 指示回调函数CanIf_RxIndication,参数 Mailbox 中包含 ID、Hoh 和抽象 CanIf ControllerId,参数 PduInfoPtr 中包含数据长度和 L-SDU 缓冲区指针

        如果是扩展 CAN 帧,Can 模块应将 ID 转换为标准格式,因为上层(CANIF)不知道接收到的 CAN 帧是标准 CAN 帧还是扩展 CAN 帧。如果是扩展 CAN 帧,接收到的 CAN 帧 ID 的 MSB 必须为 "1",以将接收到的 CAN 帧标记为扩展 CAN 帧。

        在轮询模式下,相应硬件资源的 RX 中断服务例程或函数Can_MainFunction_Read 应调用回调函数 CanIf_RxIndication。这个跟【7.5】章节的类似。

        CAN到内存的数据映射定义为:最先接收到的CAN数据字节是数组元素0,最后接收到的CAN数据字节是数组元素7或63(如果是CAN FD)。

7.7 唤醒概念

        Can 模块可处理 Can 控制器本身而非通过 Can 收发器检测到的唤醒。通过中断唤醒或者通过轮询唤醒。对于中断唤醒,当硬件检测到唤醒时,会调用 Can 模块的 ISR。

        如果调用了唤醒事件的 ISR,则应依次调用EcuM_CheckWakeup。传递给 EcuM_CheckWakeup 的参数应是CanWakeupSourceRef 配置参数引用的唤醒源的 ID。然后,ECU 状态管理器将设置 MCU,并通过 Can 接口回调 Can 模块,从而调用Can_CheckWakeup。

7.8 通知概念

        Can 模块只为 CanIf 模块提供了一个事件触发通知接口。每个通知都由一个回调函数表示。

        Can 模块轮询和不轮询的配置在驱动程序内部进行,模块外部看不到。轮询在 CAN主函数 (Can_MainFunction_xxx) 内部进行。此外,轮询事件会通过相应的回调函数进行通知。因此,调用上下文不是 ISR,而是 CAN 主函数。所有回调函数的实现都应按照调用上下文为 ISR 的方式进行。

7.11 错误分类

        Can 模块应能检测下列错误和异常,具体取决于其配置

7.11.1 开发错误

7.11.2 运行时错误

 Can 模块应指出因错误使用 Can 模块 API 而导致的错误。这包括 API 参数检查和调用顺序错误。

Can 模块的环境应仅在 DET 接通且函数提供返回值时,在Can 模块函数的返回值中显示开发错误。返回值为 E_NOT_OK。

7.11.3 瞬态故障

        没有瞬时故障。

7.11.4 生产错误

        CAN模块不会调用诊断事件管理器,因为没有为CAN模块定义生产错误代码。

7.11.5 返回值

        CAN_BUSY 通过函数 Can_Write 的返回值报告。总线关闭和唤醒事件通过通知回调函数进行转发。

八、API 规格

8.2 类型定义

8.2.1 Can_ConfigType

8.2.2 Can_PduType

8.2.3 Can_IdType

8.2.4 Can_HwHandleType

8.2.5 Can_HwType

8.2.6 对 Std_ReturnType

8.2.7 Can_ErrorStateType

8.2.8 Can_ControllerStateType

8.3 功能定义

        这是为上层模块提供的功能函数。

8.3.1 影响整个硬件设备的服务

8.3.1.1 Can_Init

        如果启用了 Can 模块的开发错误检测:如果驱动程序未处于CAN_UNINIT 状态,函数 Can_Init 应引发 CAN_E_TRANSITION 错误。

        如果启用了 Can 模块的开发错误检测功能:如果 CAN 控制器未处于 UNINIT 状态,函数 Can_Init 将引发 CAN_E_TRANSITION 错误。

8.3.1.2 Can_GetVersionInfo

        如果 Can 模块的开发错误检测功能已启用:如果参数versionInfo 为空指针,函数 Can_GetVersionInfo 将引发错误CAN_E_PARAM_POINTER。

8.3.1.3 Can_DeInit

        Can_DeInit 函数的调用者必须确保没有 CAN 控制器处于 STARTED 状态。

        如果启用了 Can 模块的开发错误检测:如果驱动程序未处于CAN_READY 状态,函数 Can_DeInit 应引发错误 CAN_E_TRANSITION

        如果启用了 Can 模块的开发错误检测:如果任何 CAN 控制器处于 STARTED 状态,函数 Can_DeInit 应引发 CAN_E_TRANSITION 错误

8.3.2 影响单个 CAN 控制器的服务

8.3.2.1 Can_SetBaudrate

        可能有多种波特率配置可供选择。可以使用函数 Can_SetBaudrate 在不同配置之间进行切换。在运行期间,根据新旧波特率配置的不同,只有部分参数会发生变化,因此可以避免重新初始化 CAN 控制器。如果调用 Can_SetBaudrate 会导致 CAN 控制器重新初始化,则调用该函数时
CAN 控制器必须处于停止状态。

        如果 Can 模块的开发错误检测功能已启用:如果驱动程序尚未初始化,函数 Can_SetBaudrate 应引发错误 CAN_E_UNINIT,并返回 E_NOT_OK

        如果 Can 模块的开发错误检测功能已启用:如果参数BaudRateConfigID 的值无效,函数 Can_SetBaudrate 应引发错误CAN_E_PARAM_BAUDRATE,并返回 E_NOT_OK。        

        如果 Can 模块的开发错误检测功能已启用,函数Can_SetBaudrate 将引发错误 CAN_E_PARAM_CONTROLLER,如果参数Controller 超出范围,则返回 E_NOT_OK。

        如果在不重新初始化 CAN 控制器的情况下无法执行所请求的波特率更改,则应返回 E_NO_OK。

8.3.2.2 Can_SetControllerMode

        每次 CAN 控制器状态机被状态转换值 CAN_CS_STARTED 触发时,函数 Can_SetControllerMode应使用之前在函数 Can_SetBaudrate 或 Can_Init 中使用的控制器配置集重新初始化CAN 控制器。

        在检查唤醒状态时,函数 Can_SetControllerMode 应禁用唤醒中断。

        如果启用了 Can 模块的开发错误检测:如果模块尚未初始化,函数 Can_SetControllerMode 将引发开发错误 CAN_E_UNINIT,并返回 E_NOT_OK

        如果启用了 Can 模块的开发错误检测:如果参数 Controller超出范围,函数 Can_SetControllerMode 将引发 CAN_E_PARAM_CONTROLLER 开发错误,并返回 E_NOT_OK。

        如果启用了 Can 模块的开发错误检测:如果请求了无效的转换,函数 Can_SetControllerMode 应引发错误 CAN_E_TRANSITION,并返回E_NOT_OK。

8.3.2.3 Can_DisableControllerInterrupts

        如果 CAN 控制器的中断已启用,函数Can_DisableControllerInterrupts 应访问 CAN 控制器寄存器,以禁用该 CAN 控制器的所有中断。

        当 Can_DisableControllerInterrupts 被多次调用时,在重新启用中断之前,必须同样多次调用 Can_EnableControllerInterrupts。函数 Can_DisableControllerInterrupts 可以在每次执行时增加一个计数器,该计数器显示需要调用多少次 Can_EnableControllerInterrupts 才能启用中断(增量禁用)

        如果 Can 模块的开发错误检测功能已启用:如果驱动程序尚未初始化,函数 Can_DisableControllerInterrupts 将引发错误 CAN_E_UNINIT

        如果 Can 模块的开发错误检测功能已启用:如果参数Controller 超出范围,函数 Can_DisableControllerInterrupts 将引发错误CAN_E_PARAM_CONTROLLER。

8.3.2.4 Can_EnableControllerInterrupts
8.3.2.5 Can_CheckWakeup

        函数 Can_CheckWakeup 应检查所请求的 CAN 控制器是否检测到唤醒。如果成功检测到唤醒事件,则应通过 API EcuM_SetWakeupEvent. ⌋() 向EcuM 报告。

        Can_CheckWakeup 功能应在编译前通过配置参数进行开/关配置:CanWakeupFunctionalityAPI

8.3.2.6 Can_GetControllerErrorState

8.3.2.7 Can_GetControllerMode

8.3.2.8 Can_GetControllerRxErrorCounter

        当调用以控制器 ID 为输入参数的 APICan_GetControllerRxErrorCounter 时,Can 驱动程序应读取 Rx 错误计数器。并应将 Rx 错误计数返回给上层。

8.3.2.9 Can_GetControllerTxErrorCounter

8.3.3 影响硬件处理的服务

8.3.3.1 Can_Write

        函数 Can_Write 首先会检查 HTH 标识的硬件传输对象是否空闲,以及同一 HTH 是
否正在进行另一次 Can_Write
        如果硬件发送对象是空闲的,函数 Can_Write 应执行以下操作:
▪ 该 HTH 的互斥设置为 "已发出信号"。
▪ 将 ID、数据长度和 SDU 转换成适合硬件的格式(如有必要),并复制到相应的硬件寄存器/缓冲器中。
▪ 启动发射的所有必要控制操作均已完成
▪ 该 HTH 的互斥已被释放
▪ 函数返回 E_OK⌋

        如果硬件发送对象忙于处理另一个 L-PDU 的发送请求,函数Can_Write 不应执行任何操作:
1. 其他 L-PDU 的传输不会被取消,函数 Can_Write 也不会有任何操作。
2. 函数 Can_Write 应返回 CAN_BUSY。

        如果已发出 Can_Write 的抢占式调用,但无法进行可重入处理(即具有相同 HTH 的调用),则函数 Can_Write 应返回 CAN_BUSY。

8.5 预定功能

        这些函数由基本软件调度程序直接调用。下列函数应没有返回值和参数。所有函数均
为非可重入函数。对 CAN 主要处理功能的执行顺序没有要求

8.5.1.1 Can_MainFunction_Write

        当 CanTxProcessing 执行时,函数 Can_MainFunction_Write应执行 TX 确认轮询。设置为 POLLING 或 MIXED。在 MIXED 处理情况下,只有CanHardwareObjectUsesPolling 设置为 "true "的硬件对象才会被轮询。

8.5.1.2 Can_MainFunction_Read

        当 CanRxProcessing 设置为 POLLING 或 MIXED 时,函数Can_MainFunction_Read 应执行 RX 指示的轮询。在 MIXED 处理情况下,只轮询CanHardwareObjectUsesPolling 设置为 "true "的硬件对象。

8.5.1.3 Can_MainFunction_BusOff

8.5.1.4 Can_MainFunction_Wakeup

8.5.1.5 Can_MainFunction_Mode

九、顺序图

9.1 Can 和 CanIf 模块之间的互动

有关序列图,请参阅 CanIf 模块规范

9.2 唤醒顺序

有关唤醒序列图,请参阅《ECU 状态管理器规范》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记录setData报错TypeError: [object Array] is not a function

小程序调用setData控制台显示报错.但是功能正常 同样的各个地方调setData都报错,经过一轮排除法后发现是自定义组件写法有问题 修改正确之后就没问题了

精品jsp+ssm健身器材管理系统-教练开发与设计

《[含文档PPT源码等]精品jspssm健身管理系统开发与设计[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功! 使用技术: 开发语言:Java 框架:ssm 技术:JSP JDK版本&…

VUE3 中导入VISO 图形

微软的VISO是一个功能强大的图形设计工具,它能够绘制流程图,P&ID,UML 类图等工程设计中常用的图形。它要比其它图形设计软件要简单许多。以后我的博文中将更多地使用VISO 来绘制图形。之前我一直使用的是corelDraw。 VISO 已经在工程设计…

AbstractQueuedSynchronizer

重要类 Node Node中的属性:prev next 重要方法 这个方法主要有两种实现 一个是公平 一个是非公平 公平: /*** Fair version of tryAcquire. Dont grant access unless* recursive call or no waiters or is first.*/protected final boolean tryAcq…

IOC理解总结

IOC 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI&#xff09…

[深度学习] 卷积神经网络“卷“在哪里?

​ 🌈 博客个人主页:Chris在Coding 🎥 本文所属专栏:[深度学习] ❤️ 热门学习专栏:[Linux学习] ⏰ 我们仍在旅途 目录 1.卷积的定义 2.卷积的"卷"在哪里 3.什么又是卷积神…

⭐北邮复试刷题589. N 叉树的前序遍历__DFS (力扣每日一题)

589. N 叉树的前序遍历 给定一个 n 叉树的根节点 root ,返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。 示例 1: 输入:root [1,null,…

【干货分享】测试开发必须要知道的Python面试题!

互联网寒冬,大家过得还好吗?年终奖发了多少? 最近感觉不少朋友都在刷 leetcode 了,年后打算看机会的,应该都蠢蠢欲动了吧。 我这里有一份精选的python面试题,测试开发方向的,由我和同行们在实…

云原生概念

云原生是一条使用户能: 1.低运维、 2.敏捷的、 3.以可扩展、可复制的方式, 最大化的利用”云“的能力、发挥”云“的价值的最 佳路径 云原生,是一条最佳路径或实践 参考:https://edu.aliyun.com/course/314164/lesson/7815

Spring MVC(基于 Spring4.x)基础学习

一、SpringMVC概述 二、SpringMVC的HelloWorld 三、使用RequestMapping映射请求 四、映射请求参数&请求头 五、处理模型数据 六、视图和视图解析器 七、RESTful CRUD 八、SpringMVC表单标签&处理静态资源 九、数据转换&数据格式化&数据校验 十、处理JSON:使用…

用过才知道,X5真的是移动办公的天花板 !

春节过后,我们又重新投入到工作的热情中,继续出发。新的一年,新的奋斗目标,新的开始。自从用过华为Mate X5办公后,不得不说,大屏幕办公就很友好,而且操作更快捷,成为了我高效办公的新…

微信小程序启动自动检测版本更新,检测到新版本则提示更新

UpdateManager 对象,用来管理更新,可通过 wx.getUpdateManager 接口获取实例在app.js中的示例代码onShow() {// 获取小程序更新机制的兼容,由于更新的功能基础库要1.9.90以上版本才支持,所以此处要做低版本的兼容处理if (wx.canIU…

AIGC专题:生成式人工智能在能源和材料领域中的新机遇

今天分享的是AIGC系列深度研究报告:《AIGC专题:生成式人工智能在能源和材料领域中的新机遇》。 (报告出品方:McKinsey & Company) 报告共计:11页 来源:人工智能学派 利用人工智能的力量…

Terminus:介绍+使用教程+技巧【全网保姆级教程】

一、起因 当我把电脑从win系统换成mac系统时候,我知道XShell已经不能在使用了,我需要找到最好的s sh客户端去登陆服务器 二、心路历程 我找了很多的软件: SSH Config Editor ProZOCVanDyke SecureCRTFinalShell 每个下载都试用了几天&#xf…

FL Studio Producer Edition v21.2.3.4004 最新版本作为 Windows 离线安装程序2024免费下载

Fl Studio 21.2.3.4004最新中文版直装版是最新的音乐制作工具。它可以与各种音乐制作令人惊叹的音乐工作。它提供了一个相当简单和用户友好的集成开发环境工作。这整个音乐工作站是由比利时公司图像线开发的。其先进的理念帮助初学者和专业人士创作、安排、录制、编辑和混合音乐…

【知识整理】PHP研发组代码规范要求

一、目标 统一代码风格、命名规范,增强代码可读性和可维护性,供日常开发工作中时参考,以提高团队协作的开发效率。 二、编程规约 PHP代码规范[PSR-12] 特别注意: 1、业务代码内对 常量、变量(分页值、版本号、向下参数等)、魔法值…

AI嵌入式K210项目(29)-模型加载

文章目录 前言一、下载部署包二、C部署三、搭建文件传输环境四、文件传输五、调试六、MicroPython部署总结 前言 上一章节介绍了如何进行在线模型训练,生成部署包后,本章介绍加载模型; 一、下载部署包 训练结束后,在训练任务条…

Python Django路由详解

1.路由Router 在实际开发过程中,一个Django 项目会包含很多的 app,这时候如果我们只在主路由里进行配置就会显得杂乱无章,所以通常会在每个app 里,创建各自的 urls.py 路由模块,然后从根路由出发,将 app 所…

idea快捷键使用

文章目录 快捷键的使用通用型编码源文件时快捷键使用操作文件类结构、查找和查看源码查找、替换与关闭调整格式Debug快捷键 查看快捷键已知快捷键操作名,未知快捷键已知快捷键,不知道对应的操作名自定义快捷键 切换其它平台快捷键 快捷键的使用 通用型 …

《白话C++》第10章 STL和boost,Page85 std::shared_ptr常用功能

std::shared_ptr基本用法包括&#xff1a; &#xff08;1&#xff09;取裸指针 //get()成员取回裸指针 std::shared_ptr <int> pa(new int(5)); int* p pa.get(); /**< 取回裸指针 */ &#xff08;2&#xff09;判断是否为空 肯定可以这样写&#xff1a; std::s…