STM32 usb_prop.c文件分析与usb_core.h一些数据定义分析

2024-06-04 18:38

本文主要是介绍STM32 usb_prop.c文件分析与usb_core.h一些数据定义分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

usb_prop.c文件可以说是一个蛮重要的文件,因为USB的许多处理函数都在这里定义。在无论是在USB的建立阶段、数据阶段还是状态阶段的一些处理都在这个文件,USB标准函数请求的函数也在这个文件里。
usb_prop.c一开始就是一连串的结构体,如下:

DEVICE Device_Table = { EP_NUM, //被使用的端点数 1 //可以使用的端点数 };DEVICE_PROP Device_Property = //注册一些CustomHID函数 { CustomHID_init, //CustomHID的初始化函数 CustomHID_Reset, //CustomHID的复位函数 CustomHID_Status_In, //CustomHID状态输入函数 CustomHID_Status_Out, //CustomHID状态输出函数 CustomHID_Data_Setup, //CustomHID的处理有数据阶段的特殊类请求函数 CustomHID_NoData_Setup, //CustomHID的处理没有数据阶段特殊类请求函数 CustomHID_Get_Interface_Setting, //CustomHID获取接口及备用接口设置(是否可用) CustomHID_GetDeviceDescriptor, //CustomHID获取设备描述符 CustomHID_GetConfigDescriptor, //CustomHID获取配置描述符 CustomHID_GetStringDescriptor, //CustomHID获取字符串描述符 0, //当前库未使用 0x40 /*MAX PACKET SIZE*/ //最大的包长度为64字节 };/*注册USB标准请求的实现函数*/ USER_STANDARD_REQUESTS User_Standard_Requests = { CustomHID_GetConfiguration, //获取配置请求 CustomHID_SetConfiguration, //设置配置请求 CustomHID_GetInterface, //获取接口请求 CustomHID_SetInterface, //设置接口请求 CustomHID_GetStatus, //获取状态请求 CustomHID_ClearFeature, //清除属性请求 CustomHID_SetEndPointFeature, //设置端点属性请求 CustomHID_SetDeviceFeature, //设置设备属性请求 CustomHID_SetDeviceAddress //设置设备地址请求 };/*注册设备描述符信息*/ ONE_DESCRIPTOR Device_Descriptor = { (uint8_t*)CustomHID_DeviceDescriptor, //注册设备描述符数组 CUSTOMHID_SIZ_DEVICE_DESC //设备描述符的长度 };/*注册设备描述符信息*/ ONE_DESCRIPTOR Config_Descriptor = { (uint8_t*)CustomHID_ConfigDescriptor, //注册配置描述符数组 CUSTOMHID_SIZ_CONFIG_DESC //配置描述符的长度 };/*注册报告描述符信息*/ ONE_DESCRIPTOR CustomHID_Report_Descriptor = { (uint8_t *)CustomHID_ReportDescriptor, //注册报告描述符数组 CUSTOMHID_SIZ_REPORT_DESC //报告描述符的长度 };/*注册HID描述符信息*/ ONE_DESCRIPTOR CustomHID_Descriptor = { (uint8_t*)CustomHID_ConfigDescriptor + CUSTOMHID_OFF_HID_DESC, //注册HID描述符数组 CUSTOMHID_SIZ_HID_DESC //HID数组的长度 };/*注册字符串描述符,包括语言ID、厂商、产品、序列号描述符*/ ONE_DESCRIPTOR String_Descriptor[4] = { {(uint8_t*)CustomHID_StringLangID, CUSTOMHID_SIZ_STRING_LANGID},//注册语言字符串描述符数组 {(uint8_t*)CustomHID_StringVendor, CUSTOMHID_SIZ_STRING_VENDOR},//注册厂商字符串描述符数组 {(uint8_t*)CustomHID_StringProduct, CUSTOMHID_SIZ_STRING_PRODUCT},//注册产品字符串描述符数组 {(uint8_t*)CustomHID_StringSerial, CUSTOMHID_SIZ_STRING_SERIAL} //注册序列号字符串描述符数组 };

应该看了很明白,这一系列的结构体就是注册一些处理函数。我们一个个分析。
先来说下 DEVICE Device_Table这个结构体,DEVICE这个结构体类型在usb_core.h中定义:

typedef struct _DEVICE { uint8_t Total_Endpoint; /*被使用的端点数*/ uint8_t Total_Configuration;/*还可以用的端点数*/ } DEVICE;

这个结构体类型很简单,在结构体中定义了已经被使用的端点和没有被使用的端点,把他们两个放在一起方便查询和管理。



接下去的说说 D EVICE_PROP Device_Property 这个类型的结构体。这个结构体的前10个元素都是函数指针类型的,把一些常用的函数放在这里,而函数定义都在该结构体之后定义,有没有觉得像是语文中的关键句,把整个文件的概要全部浓缩在这个结构体中了,只要看这个结构体就可以把整个文件做什么了解个七七八八了。这样的结构使用起来也非常方便,比如说我想要使用 CustomHID_init函数,只要写Device_Property.CustomHID_init不就可以了。我们必须学会这种方法。
D EVICE_PROP这个结构体类型还是在usb_core.h中定义:

typedef struct _DEVICE_PROP { void (*Init)(void); /*初始化设备*/ void (*Reset)(void); /*复位该设备*/ /*在控制传输中分三个过程:1.建立过程,2、可选的数据过程,3、状态过程*/ /* Device dependent process after the status stage */ void (*Process_Status_IN)(void);/*状态过程中,处理IN令牌包*/ void (*Process_Status_OUT)(void);/*状态过程中,处理OUT令牌包*/ /*在建立阶段的过程中,会有很多特殊类请求的数据阶段stage */ /*所有在数据阶段的特殊类请求都在Class_Data_Setup()函数中处理 Class_Data_Setup() 会响应去检查所有的特殊类请求,同时根据请求填充ENDPOINT_INFO结构信息 如果IN令牌包是期望的令牌包,则wLength和wOffset两个域会分别被填充成要发送的总字节数和要开始传输的位置 如果OUT令牌包是期盼的令牌包,则rLength和rOffser将会分别被填充成要接收的总字节数和要接收数据的缓冲区起始地址 如果请求有效,Class_Data_Setup返回SUCCESS,否则返回UNSUPPORT 注意: 因为GET_CONFIGURATION和GET_INTERFACE两个请求跟个别的类联系密切,所以他们会在该函数中检查和处理*/ RESULT (*Class_Data_Setup)(uint8_t RequestNo); /*在建立过程中,会有很多特殊类请求的无数据阶段*/ /*所有的没有数据阶段的特殊请求都在Class_NoData_Setup这个函数中处理 Class_NoData_Setup() 会响应去检查所有特殊类请求,并且执行请求 注意: 因为SET_CONFIGURATION和SET_INTERFACE这两个请求跟个别的类联系密切,他们都会在该函数中被检查和处理*/ RESULT (*Class_NoData_Setup)(uint8_t RequestNo); /*Class_Get_Interface_Setting() 这个函数时在usb_core.c文件中被调用来测试应用程序是否支持被选中的接口和备用接口 这个函数时由用户写的。如果应用程序支持接口和备用接口,则必须返回"SUCCESS",否则,返回"UNSUPPORT"*/ RESULT (*Class_Get_Interface_Setting)(uint8_t Interface, uint8_t AlternateSetting); uint8_t* (*GetDeviceDescriptor)(uint16_t Length); uint8_t* (*GetConfigDescriptor)(uint16_t Length); uint8_t* (*GetStringDescriptor)(uint16_t Length); /* 这个字段不是用于当前库版本。它是只保持兼容以前的版本*/ void* RxEP_buffer; uint8_t MaxPacketSize;}DEVICE_PROP;




接下去是USER_STANDARD_REQUESTS User_Standard_Requests这个结构体,在这个结构体中主要注册了USB标准请求的实现函数,当然这些函数也实在该结构体后面定义的。跟上面的 D EVICE_PROP Device_Property结构体类似,就不多讲了。
USER_STANDARD_REQUESTS  结构体也是在usb_core.h中定义:

typedef struct _USER_STANDARD_REQUESTS { void (*User_GetConfiguration)(void); /*获取配置*/ void (*User_SetConfiguration)(void); /*设置配置*/ void (*User_GetInterface)(void); /*获取接口*/ void (*User_SetInterface)(void); /*设置接口*/ void (*User_GetStatus)(void); /*获取状态*/ void (*User_ClearFeature)(void); /*清除特性*/ void (*User_SetEndPointFeature)(void); /*设置端点特性*/ void (*User_SetDeviceFeature)(void); /*设置设备特性*/ void (*User_SetDeviceAddress)(void); /*设置设备地址*/ } USER_STANDARD_REQUESTS;


像ONE_DESCRIPTOR Device_Descriptor、ONE_DESCRIPTOR Config_Descriptor、ONE_DESCRIPTOR CustomHID_Report_Descriptor、ONE_DESCRIPTOR CustomHID_Descriptor、ONE_DESCRIPTOR String_Descriptor[4]这些结构体都不仔细讲了。贴出各个结构体的定义,依旧在usb_core.h中:

typedef struct OneDescriptor { uint8_t *Descriptor; uint16_t Descriptor_Size; } ONE_DESCRIPTOR, *PONE_DESCRIPTOR;


接下去上面各个结构体注册的函数贴出来:

/******************************************************************************* * Function Name : CustomHID_init. * Description : CustomHID Mouse init routine.初始化 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_init(void) { /* Update the serial number string descriptor with the data from the unique ID*/ Get_SerialNum(); //获取序列号 pInformation->Current_Configuration = 0; /* Connect the device */ PowerOn(); //上电 /* Perform basic device initialization operations */ USB_SIL_Init(); //执行基本的初始化操作,比如说设备IP和端点0的初始化 bDeviceState = UNCONNECTED; //设置状态为未连接 }/******************************************************************************* * Function Name : CustomHID_Reset. * Description : CustomHID Mouse reset routine.复位 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_Reset(void) { /* Set CustomHID_DEVICE as not configured */ pInformation->Current_Configuration = 0; //设置当前的配置为0,表示没有配置过 pInformation->Current_Interface = 0;//默认的接口 /* Current Feature initialization */ pInformation->Current_Feature = CustomHID_ConfigDescriptor[7];//当前的属性,bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒#ifdef STM32F10X_CL /* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */ /* Init EP1 IN snd EP1 OUT as Interrupt endpoint */ OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, EP1_SIZE); OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, EP1_SIZE); #else SetBTABLE(BTABLE_ADDRESS); /* Initialize Endpoint 0 */ SetEPType(ENDP0, EP_CONTROL); //设置端点1为控制端点 SetEPTxStatus(ENDP0, EP_TX_STALL); //设置端点0发送延时 SetEPRxAddr(ENDP0, ENDP0_RXADDR); //设置端点0的接收缓冲区地址 SetEPTxAddr(ENDP0, ENDP0_TXADDR); //设置端点0的发送缓冲区地址 Clear_Status_Out(ENDP0); //清除端点0的状态 SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);//设置端点0的接收的计数 SetEPRxValid(ENDP0); //使能接收状态 /* Initialize Endpoint 1 */ SetEPType(ENDP1, EP_INTERRUPT); //设置端点1为中断控制端点 SetEPRxAddr(ENDP1, ENDP1_RXADDR); //设置端点1的接收缓冲地址 SetEPRxCount(ENDP1, REPORT_COUNT); //设置端点1的接收计数 SetEPRxStatus(ENDP1, EP_RX_VALID); //设置端点1接收有效 //SetEPTxStatus(ENDP1, EP_TX_DIS); /* Initialize Endpoint 2 */ SetEPType(ENDP2, EP_INTERRUPT); //设置端点2为中断控制端点 SetEPTxAddr(ENDP2, ENDP2_TXADDR); //设置端点2的接收缓冲地址 SetEPTxCount(ENDP2, REPORT_COUNT); //设置端点2的接收计数 // SetEPTxStatus(ENDP2, EP_TX_DIS); SetEPTxStatus(ENDP2, EP_TX_NAK); //设置端点2为接收不响应 bDeviceState = ATTACHED; //设置设备状态为 ATTACHED状态 /* Set this device to response on default address */ SetDeviceAddress(0); //设置设备为默认地址 #endif /* STM32F10X_CL */ bDeviceState = ATTACHED; } /******************************************************************************* * Function Name : CustomHID_SetConfiguration. * Description : 更新设备配置状态 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_SetConfiguration(void) { DEVICE_INFO *pInfo = &Device_Info; if (pInfo->Current_Configuration != 0) { /* Device configured */ bDeviceState = CONFIGURED; } } /******************************************************************************* * Function Name : CustomHID_SetConfiguration. * Description : 更新设备的编址状态 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_SetDeviceAddress (void) { bDeviceState = ADDRESSED; } /******************************************************************************* * Function Name : CustomHID_Status_In. * Description : 状态输入函数 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_Status_In(void) {}/******************************************************************************* * Function Name : CustomHID_Status_Out * Description : 状态输出函数 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_Status_Out(void) {}/******************************************************************************* * Function Name : CustomHID_Data_Setup * Description : 处理有数据阶段的特殊类请求 * Input : Request Nb. * Output : None. * Return : USB_UNSUPPORT or USB_SUCCESS. *******************************************************************************/ RESULT CustomHID_Data_Setup(uint8_t RequestNo) { uint8_t *(*CopyRoutine)(uint16_t); //定义一个指向函数指针的指针 CopyRoutine = NULL; if ((RequestNo == GET_DESCRIPTOR) //是GET_DESCRIPTOR请求,见圈圈P75 && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//请求的类型为标准请求,请求的接收者为接口 && (pInformation->USBwIndex0 == 0)) //是非语言ID字符串描述符的其他描述符 { if (pInformation->USBwValue1 == REPORT_DESCRIPTOR) //是报告描述符 { CopyRoutine = CustomHID_GetReportDescriptor; //CopyRoutine指向获取报告描述符的函数指针 } else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE)//是HID描述符 { CopyRoutine = CustomHID_GetHIDDescriptor; //CopyRoutine指向获取HID描述符的函数指针 } } /* End of GET_DESCRIPTOR */ /*** GET_PROTOCOL ***/ else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) //请求的类型是类请求,请求的接收者为接口请求 && RequestNo == GET_PROTOCOL) //获取协议 { CopyRoutine = CustomHID_GetProtocolValue; //获取协议的值 } if (CopyRoutine == NULL) //如果长度为0,CopyRoutine=NULL { return USB_UNSUPPORT; //USB没有接上 } pInformation->Ctrl_Info.CopyData = CopyRoutine; //注册CopyData函数 pInformation->Ctrl_Info.Usb_wOffset = 0; //数据的偏移 (*CopyRoutine)(0); //调用CopyData()函数 return USB_SUCCESS; //返回 USB_SUCCESS }/******************************************************************************* * Function Name : CustomHID_NoData_Setup * Description : 处理没有数据阶段的特殊类请求 * Input : Request Nb. * Output : None. * Return : USB_UNSUPPORT or USB_SUCCESS. *******************************************************************************/ RESULT CustomHID_NoData_Setup(uint8_t RequestNo) { if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) //类请求、接口接收 && (RequestNo == SET_PROTOCOL)) //设置协议 { return CustomHID_SetProtocol(); } else { return USB_UNSUPPORT; } }/******************************************************************************* * Function Name : CustomHID_GetDeviceDescriptor. * Description : 获取设备描述符 * Input : Length * Output : None. * Return : The address of the device descriptor. *******************************************************************************/ uint8_t *CustomHID_GetDeviceDescriptor(uint16_t Length) { return Standard_GetDescriptorData(Length, &Device_Descriptor); }/******************************************************************************* * Function Name : CustomHID_GetConfigDescriptor. * Description : 获取配置描述符 * Input : Length * Output : None. * Return : The address of the configuration descriptor. *******************************************************************************/ uint8_t *CustomHID_GetConfigDescriptor(uint16_t Length) { return Standard_GetDescriptorData(Length, &Config_Descriptor); }/******************************************************************************* * Function Name : CustomHID_GetStringDescriptor * Description : 根据索引获取字符描述符 * Input : Length * Output : None. * Return : The address of the string descriptors. *******************************************************************************/ uint8_t *CustomHID_GetStringDescriptor(uint16_t Length) { uint8_t wValue0 = pInformation->USBwValue0; if (wValue0 > 4) { return NULL; } else { return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]); } }/******************************************************************************* * Function Name : CustomHID_GetReportDescriptor. * Description : 获取报告描述符 * Input : Length * Output : None. * Return : The address of the configuration descriptor. *******************************************************************************/ uint8_t *CustomHID_GetReportDescriptor(uint16_t Length) { return Standard_GetDescriptorData(Length, &CustomHID_Report_Descriptor); }/******************************************************************************* * Function Name : CustomHID_GetHIDDescriptor. * Description : 获取HID描述符 * Input : Length * Output : None. * Return : The address of the configuration descriptor. *******************************************************************************/ uint8_t *CustomHID_GetHIDDescriptor(uint16_t Length) { return Standard_GetDescriptorData(Length, &CustomHID_Descriptor); }/******************************************************************************* * Function Name : CustomHID_Get_Interface_Setting. * Description : 测试接口及其备用接口是否可用 * Input : - Interface : interface number. * - AlternateSetting : Alternate Setting number. * Output : None. * Return : USB_SUCCESS or USB_UNSUPPORT. *******************************************************************************/ RESULT CustomHID_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting) { if (AlternateSetting > 0) //备用的编号大于0 { return USB_UNSUPPORT; } else if (Interface > 0) //接口的编号大于0 { return USB_UNSUPPORT; } return USB_SUCCESS; }/******************************************************************************* * Function Name : CustomHID_SetProtocol * Description : 设置接口所使用协议请求函数 * Input : None. * Output : None. * Return : USB SUCCESS. *******************************************************************************/ RESULT CustomHID_SetProtocol(void) { uint8_t wValue0 = pInformation->USBwValue0; //获取设备信息中的USBwValue值 ProtocolValue = wValue0; return USB_SUCCESS; }/******************************************************************************* * Function Name : CustomHID_GetProtocolValue * Description : 获取协议的值 * Input : Length. * Output : None. * Return : address of the protcol value. *******************************************************************************/ uint8_t *CustomHID_GetProtocolValue(uint16_t Length) { if (Length == 0) //Length为0时 { pInformation->Ctrl_Info.Usb_wLength = 1;//要发送的长度为1 return NULL; } else { return (uint8_t *)(&ProtocolValue); //返回协议的值 } }

这篇关于STM32 usb_prop.c文件分析与usb_core.h一些数据定义分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1030800

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

pandas数据过滤

Pandas 数据过滤方法 Pandas 提供了多种方法来过滤数据,可以根据不同的条件进行筛选。以下是一些常见的 Pandas 数据过滤方法,结合实例进行讲解,希望能帮你快速理解。 1. 基于条件筛选行 可以使用布尔索引来根据条件过滤行。 import pandas as pd# 创建示例数据data = {'Name': ['Alice', 'Bob', 'Charlie', 'Dav