当前位置: 首页 > news >正文

linux驱动入门实验班——平台总线设备驱动模型和设备树

目录

前言

一、重要结构体

二、编程思路

1.platform_driver结构体

2.probe

三、使用设备树

1.步进电机

2.红外遥控

四、代码示例

 


前言

在这里主要记录学习韦东山老师Linux驱动人入门实验班的笔记,韦东山老师的驱动课程讲的非常好,想要学习驱动的小伙伴可以去b站学习他的课程。

一、重要结构体

platfrom_driver结构体:

platform_driver 结构体是在 Linux 内核中定义的一个结构体,用于在驱动程序中注册和管理平台设备驱动。它包含以下字段:

  1. struct device_driver driver:指向 struct device_driver 结构体的指针,表示该平台驱动程序所属的设备驱动。

  2. const struct platform_device_id *id_table:一个指向 struct platform_device_id 结构体数组的指针,用于匹配与该平台驱动程序相匹配的设备。

  3. int (*probe)(struct platform_device *pdev):一个函数指针,指向设备的探测函数,用于在设备被注册到系统后执行特定的操作。

  4. int (*remove)(struct platform_device *pdev):一个函数指针,指向设备的移除函数,用于在设备被注销时执行特定的操作。

  5. void (*shutdown)(struct platform_device *pdev):一个函数指针,指向设备的关机函数,用于在系统关机时执行特定的操作。

  6. struct device_driver driver:用于表示该平台驱动程序的设备驱动。

  7. struct list_head driver_entry:用于将平台驱动程序添加到全局驱动程序链表中的链表节点。

二、编程思路

在原来第一个模板的基础上

1.platform_driver结构体

还需要构造platform_driver结构体和of_device_id结构体

static struct platform_driver gpio_platfrom_drive = {.driver = {.name = "100ask_gpio_plat_drv",.of_match_table = gpio_dt_ids,},.probe = gpio_drv_probe,.remove = gpio_drv_remove,
};
struct of_device_id { char name[32]; char type[32]; char compatible[128]; const void *data; };在Linux内核中,of_device_id结构体用于存储设备树绑定信息,用于设备与驱动程序之间的匹配。它包含以下字段:name:设备树绑定的名称。
type:设备树绑定的类型。
compatible:设备树绑定的兼容字符串,用于指定设备与驱动程序之间的兼容关系。
data:指向附加数据的指针,可以在设备树绑定中使用。

gpio_drv_probe和gpio_drv_remove分别代替了原来init入口函数和exit出口函数的作用,而在原来的这两个函数中是注册和反注册platform_driver结构体。

使用的函数为:

platform_driver_register 是一个函数,用于注册平台设备驱动程序。它将驱动程序与平台设备进行绑定,使得驱动程序能够管理其对应的平台设备。函数原型为:int platform_driver_register(struct platform_driver *drv);参数说明:drv:指向平台驱动程序的指针,其类型为 struct platform_driver。平台驱动程序是一个结构体,包含了驱动程序的各种回调函数和其他属性。定义了平台设备和驱动程序之间的关联关系。
返回值:成功注册平台驱动程序时,返回 0;注册失败时,返回负数错误代码。
使用 platform_driver_register 函数可以将平台驱动程序注册到内核中,以便在加载平台设备时自动调用相应的驱动程序。注册平台驱动程序后,内核会通过设备树 (Device Tree) 或 ACPI (Advanced Configuration and Power Interface) 系统启动方法来查找并匹配平台设备,并自动加载和绑定对应的驱动程序。注册平台驱动程序时,需要确保驱动程序的结构体中的回调函数和其他属性正确设置,以便驱动程序能够正确地管理和操作平台设备。

2.probe

static int gpio_drv_probe(struct platform_device *pdev)

  gpio_drv_probe中使用到的结构体:

struct device_node *np = pdev->dev.of_node;
platform_device 结构体包含的重要成员包括:name:设备的名称,用于唯一标识设备。
id:设备的 ID,用于区分同一类型的不同设备。
num_resources:设备所需的资源数量。
resource:用于描述设备的资源信息,如内存范围、中断、I/O 端口等。
dev:指向设备所属的 struct device 结构体的指针,用于与设备的核心操作进行交互。
pdata:设备特定的数据,用于向设备驱动程序传递设备特定的信息。
driver_data:指向设备驱动程序特定数据的指针,用于与设备驱动程序交互。
struct device_node {const char *name;   // 设备节点名称const char *type;   // 设备节点类型const char *fullname;   // 设备节点完整路径名称struct device_node *parent;   // 父设备节点struct device_node *child;   // 子设备节点struct device_node *sibling;   // 兄弟设备节点void *data;   // 设备节点特定数据// 其他成员...
};
struct resource {resource_size_t start;   // 资源起始地址resource_size_t end;   // 资源结束地址(包含)resource_size_t flags;   // 资源标志const char *name;   // 资源名称struct resource *parent;   // 父资源struct resource *sibling;   // 兄弟资源struct resource *child;   // 子资源
};

 gpio_drv_probe中使用到的函数:

  • of_gpio_count
of_gpio_count 是一个函数,用于获取设备的GPIO数量。它是在Device Tree中使用的,用于解析设备节点中定义的GPIO信息。函数原型为:int of_gpio_count(struct device_node *np);参数说明:struct device_node *np:指向设备节点的指针。
返回值:返回设备节点中定义的GPIO数量。如果没有定义GPIO,则返回0。
使用 of_gpio_count 函数可以确定设备节点中定义的GPIO数量,从而在设备驱动程序中进行相应的GPIO初始化和管理操作。
  • kmalloc
kmalloc 是一个内核函数,用于动态分配内核空间的连续内存块。它可以用于分配任意大小的内存区域。函数原型为:void *kmalloc(size_t size, gfp_t flags);参数说明:size:要分配的内存块的大小,以字节为单位。
flags:分配内存的标志,用于指定分配内存的行为。
返回值:返回指向分配的内存块的指针,如果分配失败,则返回NULL。
  •  platform_get_resource
platform_get_resource 是一个函数,用于获取给定平台设备的资源信息。它可以用于获取平台设备上的寄存器地址、中断号、IO地址等资源的信息。函数原型为:struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);参数说明:dev:指向平台设备的指针。
type:要获取的资源类型,可以是 IORESOURCE_MEM、IORESOURCE_IO 或 IORESOURCE_IRQ。这些类型定义在 include/linux/ioport.h 和 include/linux/irq.h 头文件中。
num:要获取的资源号,资源号从 0 开始计数。
返回值:返回指向资源的 struct resource 结构体指针,如果获取失败,则返回 NULL。
使用 platform_get_resource 函数可以获取平台设备上的资源信息。例如,可以使用它来获取平台设备上的寄存器地址,以便进行寄存器访问。需要注意的是,资源的类型和编号需要事先了解,以便正确地调用 platform_get_resource 函数。

三、使用设备树

1.步进电机

  • 修改设备树:arch/arm/boot/dts/100ask_imx6ull-14x14.dts

添加节点: 

motor {compatible = "100ask,gpiodemo";gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>, <&gpio4 20 GPIO_ACTIVE_HIGH>,<&gpio4 21 GPIO_ACTIVE_HIGH>,<&gpio4 22 GPIO_ACTIVE_HIGH>;
};
  • 编译:make dtbs

  • 复制到单板上

    ubuntu:
    
    cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/
    开发板:
    
    mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
    cp /mnt/100ask_imx6ull-14x14.dtb  /boot
    reboot
  • 测试

    insmod gpio_drv.ko
    ./button_test /dev/motor ...

    2.红外遥控

  • 修改设备树:arch/arm/boot/dts/100ask_imx6ull-14x14.dts

添加节点: 

irda {compatible = "100ask,gpiodemo";gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;
};
  • 编译:make dtbs

  • 复制到单板上

    PC:
    cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/
    ​
    开发板:
    mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
    cp /mnt/100ask_imx6ull-14x14.dtb  /boot
    reboot
  • 测试

    insmod gpio_drv.ko
    ./button_test /dev/irda

四、代码示例

static int irda_drv_probe(struct platform_device *pdev)
{int err = 0;int i;struct device_node *np = pdev->dev.of_node;struct resource *res;if (np){count = of_gpio_count(np);if (!count){return -EINVAL;}gpios = kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL);for (i = 0; i < count; i++){gpios[i].gpio = of_get_gpio(np, i);sprintf(gpios[i].name, "%s_pin_%d", np->name, i);}}else{count = 0;while (1){res = platform_get_resource(pdev, IORESOURCE_IRQ, count);if (res){count++;}else{break;}}if(!count){return -EINVAL;}gpios = kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL);for (i = 0; i < count; i++){res = platform_get_resource(pdev, IORESOURCE_IRQ, count);gpios[i].gpio = res->start;sprintf(gpios[i].name, "%s_pin_%d", pdev->name, i);}}for (i = 0; i < count; i++){gpios[i].irq = gpio_to_irq(gpios[i].gpio);setup_timer(&gpios[i].irda_timer, irda_timer_expire, (unsigned long)&gpios[i]);err = request_irq(gpios[i].irq, irda_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, gpios[i].name, &gpios[i]);}major = register_chrdev(0, "irda_drv", &irda_drv);irda_class = class_create(THIS_MODULE, "irda_class");device_create(irda_class, NULL, MKDEV(major, 0), NULL, "irda_drv");return err;
}static int irda_drv_remove(struct platform_device *pdev)
{int i;device_destroy(irda_class, MKDEV(major, 0));class_destroy(irda_class);unregister_chrdev(major, "irda_drv");for (i= 0; i < count; i++){free_irq(gpios[i].irq, &gpios[i]);del_timer(&gpios[i].irda_timer);}return 0;
}static struct of_device_id irda_dt_ids[] = {{.compatible = "irda,demo",},
};static struct platform_driver irda_platform_driver = {.driver = {.name = "irda_plat_drive",.of_match_table = irda_dt_ids,},.probe = irda_drv_probe,.remove = irda_drv_remove,
};

相关文章:

linux驱动入门实验班——平台总线设备驱动模型和设备树

目录 前言 一、重要结构体 二、编程思路 1.platform_driver结构体 2.probe 三、使用设备树 1.步进电机 2.红外遥控 四、代码示例 前言 在这里主要记录学习韦东山老师Linux驱动人入门实验班的笔记&#xff0c;韦东山老师的驱动课程讲的非常好&#xff0c;想要学习驱动…...

零基础学习Python(六)

1. 元类的应用 使用元类给对象添加一个固有属性author: 对类名进行限定&#xff0c;要求类名必须是大写字母开头&#xff1a; class MetaC(type):def __init__(cls, name, bases, attrs):if not name.istitle():raise TypeError("类名必须是大写字母开头~")return …...

微信小程序--31(todolist案例)

一.功能 输入待办事件添加代办事件删除代办事件 二、步骤 1.添加输入框 .wxml代码&#xff1a; <!-- 1.输入框 --><input type"text" bindinput"handleInput" value"{{text}}" /> .wxss代码&#xff1a; /* 1.输入框样式 */ i…...

springboot项目使用本地依赖项,打包后出现NoClassDefFoundError的一种解决方法

可以把本地依赖项上传到本地仓库后再引用 建立 Maven 本地仓库并将依赖上传到本地仓库 要建立 Maven 本地仓库并将依赖上传到本地仓库&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 配置 Maven 本地仓库路径 Maven 默认会在用户的主目录下的 .m2/repository 目录创…...

Maven高级使用指南

在开发大型项目时&#xff0c;Maven作为一个强大的构建和项目管理工具&#xff0c;能显著提升项目管理和构建的效率。然而&#xff0c;随着项目的扩大&#xff0c;维护和管理的复杂性也随之增加。本文将探讨一些高级的Maven用法和解决方案&#xff0c;以帮助你更好地管理大型项…...

windows docker 执行apt-get 权限问题

今天在windows下安装的docker 部署的容器执行apt-get遇到权限问题 PS C:\Users\xiaok> docker exec -it jenkins sh $ apt-get update Reading package lists... Done E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied) E: Unable to l…...

Linux系统信息排查

目录 介绍步骤 介绍 1、熟悉查看CPU信息、操作系统信息、用户信息、特殊权限账户、启动项和任务计划的排查命令 2、在进行受害主机排查时&#xff0c;首先要对主机系统进行基本排查&#xff0c;方便对受害主机有一个初步的了解。 3、利用lscpu和uname -a查看系统硬件软件基本…...

《图解设计模式》笔记(四)分开考虑

九、Bridge模式&#xff1a;将类的功能层次结构与实现层次结构分离 类的两个层次结构和作用 类的功能层次结构&#xff1a;希望增加新功能时 父类有基本功能&#xff0c;在子类中增加新功能 Something父类 …├─SomethingGood子类 想要再增加新功能 Something父类 …├─So…...

Linux shell编程学习笔记74:sed命令——沧海横流任我行(中)

0 前言 自 60 年代末以来&#xff0c;sed 一直是 Unix 标准工具箱的一部分。 Sed在以下三种情况下特别有用&#xff1a; 编辑太大的文件&#xff0c;无法进行舒适的交互式编辑&#xff1b; 当编辑命令序列过于复杂而无法在交互模式下轻松键入时&#xff0c;可以编辑任何大小的…...

[数据集][目标检测]道路积水检测数据集VOC+YOLO格式2699张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2699 标注数量(xml文件个数)&#xff1a;2699 标注数量(txt文件个数)&#xff1a;2699 标注…...

不同路径

不同路径 思路&#xff1a; 法一&#xff1a;动态规划 const int N 110; class Solution { int dp[N][N];//dp[i][j]&#xff1a;从起点走到 i j的路径个数。 public:int uniquePaths(int m, int n) {for(int i1;i<n;i){dp[1][i]1;} for(int i1;i<m;i) dp[i][1]1;f…...

【HTML】HTML学习之引入CSS样式表

1、CSS样式规则 选择器{属性1:属性值1; 属性2:属性值2; 属性3:属性值3;}2、HTML引入CSS样式表 2.1、行内式 行内式也称为内联样式&#xff0c;是通过标签的style属性来设置元素的样式&#xff0c;其基本语法格式如下: <标签名 style"属性1:属性值1; 属性2:属性值2;…...

shaushaushau1

CVE-2023-7130 靶标介绍&#xff1a; College Notes Gallery 2.0 允许通过“/notes/login.php”中的参数‘user’进行 SQL 注入。利用这个问题可能会使攻击者有机会破坏应用程序&#xff0c;访问或修改数据. 已经告诉你在哪里存在sql注入了&#xff0c;一般上来应该先目录扫…...

揭秘面试必备:高频算法与面试题全面解析

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…...

设计模式-visit模式-在语法树的实践

文章目录 背景示例代码分析灵活性双重分派 总结 背景 很多项目代码有accept()用法&#xff0c;在calcite 里也看到了这种&#xff0c;深入了解一下 语法树遍历&#xff1a;编译器通常会将源代码解析成抽象语法树&#xff08;AST&#xff09;。为了实现不同的编译阶段&#xff…...

ZK-Rollups测评

1. 引言 Matter Labs团队和多个高校研究人员一起&#xff0c;发布2024年论文《Analyzing and Benchmarking ZK-Rollups》&#xff0c;开源代码见&#xff1a; https://github.com/StefanosChaliasos/zkrollup-benchmarking&#xff08;Python&#xff09; 其中&#xff1a; …...

redis生产使用场景(一):并行流+二级缓存

本文主要介绍 redis 缓存在线上的使用场景 由于业务的特殊性&#xff0c;在生产库用户表中&#xff0c;大概有 50 多万的测试用户&#xff0c;在真实业务计算中&#xff0c;要把测试用户给筛选掉&#xff0c;所以在计算前&#xff0c;需要把测试用户加载到 redis 缓存中&#x…...

EXCEL跨文件查询,指定条件列,返回满足条件的指定列

EXCEL跨文件查询&#xff0c;指定条件列&#xff0c;返回满足条件的指定列 Private Sub cmd_find_from_workbooks_Click() Dim S_Cols As String, thePath As String, Sor_Col As Integer, sz_Cols As Variant S_Cols T_jieguo_cols.Text sz_Cols Split(S_Cols, ",&quo…...

[数据集][目标检测]流水线物件检测数据集VOC+YOLO格式9255张26类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;9255 标注数量(xml文件个数)&#xff1a;9255 标注数量(txt文件个数)&#xff1a;9255 标注…...

StarRocks 存算分离 Compaction 原理

前言 StarRocks 中每次数据摄入都会生成一个新的数据版本&#xff0c;而查询时需要将所有版本数据进行合并才能获得一个正确的结果&#xff0c;如果历史数据版本太多&#xff0c;那么查询时需要读取的文件数也会很多&#xff0c;造成查询效率低下。因而 StarRocks 存在内部任务…...

搭建ELK日志采集与分析系统

SpringCloud微服务实战——企业级开发框架 &#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您…...

java集合中自动排序的treeset和treemap

底层 TreeSet 和 TreeMap 的底层架构都是基于红黑树实现的。红黑树是一种自平衡的二叉搜索树,其特性保证了插入、删除和查找操作的时间复杂度为 (O( log ⁡ n \log n logn)),无论数据量多大,操作性能都能保持在合理的范围内。 1. 红黑树概述 红黑树是一种平衡二叉搜索树(…...

Android 修改SystemUI 音量条的声音进度条样式

一、前言 Android System UI 开发经常会遇到修改音量进度条样式的需求&#xff0c;主要涉及的类有VolumeDialogImpl与xml文件&#xff0c;接下来会逐步实现流程。先看看效果。 修改前 修改后 二、找到对应类 通过aidegen 打断点调试对应代码类VolumeDialogImpl定位到volume_d…...

电商场景的视频生成的prompt测评集合

1.收集的一些提示词 一台写着Vidu的赛车在路上飞驰,赛车上面坐着一只乌龟 一个宇航员在太空中骑单车 两个巨大的机器人在打架,电影风格,史诗感,高细节 在科幻电影风格中,两个巨大的机器人在城市废墟中激烈战斗。使用高角度俯拍,展现机器人的宏伟和战斗的史诗感。机器人…...

day34

1 非阻塞型IO 让我们的read函数不再阻塞&#xff0c;无论是否读取到消息&#xff0c;立刻返回 1.1 fcntl函数 原型&#xff1a;int fcntl(int fd, int cmd, ... /* arg */ ); 调用&#xff1a;int flag fcntl(描述符,F_GETFL) fcntl(描述符&#xff0c;F_SETFL&am…...

无缝融入,即刻智能[三]:Dify-LLM平台知识库构建(多路召回、精排重排),43K+星标见证专属智能方案

无缝融入,即刻智能[三]:Dify-LLM平台知识库构建(多路召回、精排重排),43K+星标见证专属智能方案 大语言模型的训练数据一般基于公开的数据,且每一次训练需要消耗大量算力,这意味着模型的知识一般不会包含私有领域的知识,同时在公开知识领域存在一定的滞后性。为了解决这一…...

AWS服务WAF

在 AWS 中使用 Web Application Firewall (WAF) 来防御常见的攻击手段&#xff0c;如 DDoS 攻击和 SQL 注入攻击&#xff0c;可以通过创建和配置规则来实现。下面是如何使用 AWS WAF 阻止这些常见攻击的详细操作步骤。 1. 登录到 AWS 管理控制台 打开 AWS 管理控制台。使用你…...

二叉树中的奇偶树问题

目录 一题目&#xff1a; 二思路汇总&#xff1a; 1.二叉树层序遍历&#xff1a; 1.1题目介绍&#xff1a; 1.2 解答代码&#xff08;c版&#xff09;&#xff1a; 1.3 解答代码&#xff08;c版&#xff09;&#xff1a; 1.4 小结一下&#xff1a; 2.奇偶树分析&#xf…...

GD - EmbeddedBuilder - 用DMA进行串口发送接收,支持接收不定长包

文章目录 GD - EmbeddedBuilder - 用DMA进行串口发送接收&#xff0c;支持接收不定长包概述笔记硬件连接图形化配置485EN的配置串口的图形化配置 代码实现main.cgd32f3x0_hal_it.cgd32f3x0_hal_init.cgd32f3x0_hal_init.hgd32f3x0_hal_it.hgd32f3x0_libopt.h 备注END GD - Embe…...

英语中apartment(公寓)(美式)、house(房子)、flat(公寓)(英式)、villa(别墅)、room(房间)区别

文章目录 英语中apartment、house、flat、villa、room区别 英语中apartment、house、flat、villa、room区别 在英语中&#xff0c;“apartment”、“house”、“flat”、“villa”、和 “room” 这些词语都与居住空间有关&#xff0c;但它们各自的含义和用途有所不同&#xff…...

wordpress新建html/江苏网站开发

项目需要对接另外两个公司的程序接口&#xff0c;其中一个公司使用纯C实现&#xff0c;一个使用C实现&#xff0c;我们需要把C的库封装给纯C的框架&#xff0c;C的库值提供了C的类头文件和自己的库&#xff0c;需要将C的部分包装为纯C调用方式&#xff0c;提供给外部 先看Makef…...

房产网站内容建设部门规划/seo查询优化

前言玩转ECharts系列&#xff0c;主要为大家讲解我们基于ECharts如何实现企业级大屏项目中较为常用的各种奇奇怪怪的图表&#xff0c;接下来我们将通过几篇文章从基础图表开始为大家详细讲解实现这些图表样式的一些“小心机”。导读阅读完此文&#xff0c;你会了解基于ECharts&…...

现在做网站开发/电商运营培训学费多少

常用工具介绍当 Docker 部署规模逐步变大后&#xff0c;可视化监控容器环境的性能和健康状态将会变得越来越重要。 Docker的图形化管理工具&#xff0c;提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作&#xff08;包括上传下载镜像&#xff0c;创建容器等操…...

国外网页设计评论网站/seo技术 快速网站排名

以GoogLeNet模型为例子说明配置train_val.prototxt训练文件&#xff1a; 模块化结构图&#xff1a;从下往上看 需要用到的caffe.proto文件地址在&#xff1a;caffe-windows\src\caffe\proto可查看。 GoogLeNet网络结构明细表解析如下&#xff1a;0、输入 原始输入图像为224x22…...

网站上线倒计时html5模板/百度销售系统登录

对于Ubuntu 命令行下运行哪个命令进行软件包的安装&#xff1f;对于大部分开发者第一反应是: apt-get 但实际使用过程中&#xff0c;会遇到不知道所需要安装包的正确名称&#xff0c;导致安装失败&#xff0c;如下例子&#xff1a; Ubuntu下进行相关packet安装的命令是pip, 大…...

网站制作排名/网站收录查询站长工具

安装tensorflow&#xff1a; pip install tensorflow-gpu2.3.0 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install tensorflow 安装最新版tensorflow pip install tensorflow2.9.0 安装指定版本的tensorflow 查看Anaconda环境是否安装成功&#xff1a; conda --ve…...