嵌入式Linux系统中SPI 子系统基本实现

news2024/12/23 12:25:16

1、SPI 驱动源文件目录

Linux common spi driver

kernel-4.14/drivers/spi/spi.c  Linux 提供的通用接口封装层驱动
kernel-4.14/drivers/spi/spidev.c  linux 提供的 SPI 通用设备驱动程序
kernel-4.14/include/linux/spi/spi.h  linux 提供的包含 SPI 的主要数据结构和函数

spi 控制器驱动,IC 厂商提供,不同厂商命名不同

kernel-4.14/drivers/spi/spi-mt65xx.c  MTK SPI 控制器驱动
kernel-4.14/drivers/spi/spi-mt65xx-dev.c
kernel-4.14/include/linux/platform_data/spi-mt65xx.h

dts

kernel-4.14/arch/arm/boot/dts/...
kernel-4.14/arch/arm64/boot/dts/...

以上文件对应如下 SPI 驱动软件架构:

SPI 控制器驱动程序

SPI 控制器不用关心设备的具体功能,它只负责把上层协议驱动准备好的数据按 SPI 总线的时序要求发送给 SPI 设备,同时把从设备收到的数据返回给上层的协议驱动,因此,内核把 SPI 控制器的驱动程序独立出来。

SPI 控制器驱动负责控制具体的控制器硬件,诸如 DMA 和中断操作等等,因为多个上层的协议驱动可能会通过控制器请求数据传输操作,所以,SPI 控制器驱动同时也要负责对这些请求进行队列管理,保证先进先出的原则。

SPI 通用接口封装层

为了简化 SPI 驱动程序的编程工作,同时也为了降低【协议驱动程序】和【控制器驱动程序】的耦合程度,内核把控制器驱动和协议驱动的一些通用操作封装成标准的接口,加上一些通用的逻辑处理操作,组成了 SPI 通用接口封装层。

这样的好处是,对于控制器驱动程序,只要实现标准的接口回调 API,并把它注册到通用接口层即可,无需直接和协议层驱动程序进行交互。而对于协议层驱动来说,只需通过通用接口层提供的 API 即可完成设备和驱动的注册,并通过通用接口层的 API 完成数据的传输,无需关注 SPI 控制器驱动的实现细节。

SPI 协议驱动程序

SPI 设备的具体功能是由 SPI 协议驱动程序完成的,SPI 协议驱动程序了解设备的功能和通信数据的协议格式。向下,协议驱动通过通用接口层和控制器交换数据,向上,协议驱动通常会根据设备具体的功能和内核的其它子系统进行交互。

例如,和 MTD 层交互以便把 SPI 接口的存储设备实现为某个文件系统,和 TTY 子系统交互把 SPI 设备实现为一个 TTY 设备,和网络子系统交互以便把一个 SPI 设备实现为一个网络设备。如果是一个专有的 SPI 设备,我们也可以按设备的协议要求,实现自己的专有协议驱动。

SPI 通用设备驱动程序

考虑到连接在 SPI 控制器上的设备的可变性,在内核没有配备相应的协议驱动程序,对于这种情况,内核为我们准备了通用的 SPI 设备驱动程序,该通用设备驱动程序向用户空间提供了控制 SPI 控制的控制接口,具体的协议控制和数据传输工作交由用户空间根据具体的设备来完成,在这种方式中,只能采用同步的方式和 SPI 设备进行通信,所以通常用于一些数据量较少的简单 SPI 设备。

2、SPI 通用接口层

  1. SPI 通用接口层把具体的 SPI 设备的协议驱动和 SPI 控制器驱动连接在一起。

  2. 负责 SPI 系统与 Linux 设备模型相关的初始化工作。

  3. 为协议驱动和控制器驱动提供一系列的标准接口 API 及其数据结构。

  4. SPI 设备、SPI 协议驱动、SPI 控制器的数据抽象

  5. 协助数据传输而定义的数据结构

kernel-4.14/drivers/spi/spi.c

static int __init spi_init(void)
{
 int status;

 buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
 if (!buf) {
  status = -ENOMEM;
  goto err0;
 }
        
  // 创建 /sys/bus/spi 节点
 status = bus_register(&spi_bus_type);
 if (status < 0)
  goto err1;

  //创建 /sys/class/spi_master 节点
 status = class_register(&spi_master_class);
 if (status < 0)
  goto err2;

 if (IS_ENABLED(CONFIG_SPI_SLAVE)) {
  status = class_register(&spi_slave_class);
  if (status < 0)
   goto err3;
 }
        ......
}

在这里创建了 SPI 总线,创建 /sys/bus/spi 节点和 /sys/class/spi_master 节点。

重要数据结构:

spi_device
spi_driver
spi_board_info
spi_controller/spi_master
spi_transfer
spi_message

重要 API

spi_message_init
spi_message_add_tail
spi_sync
spi_async
spi_write
spi_read

接下来详细解析结构体和API,只讲解重点部分,完整解析请参考官方文档

https://www.kernel.org/doc/html/v4.14//driver-api/spi.html

只有熟悉每个结构体存储的是什么东西,才能真正搞懂 SPI 模块。

spi_master/spi_controller:描述一个 spi 主机设备

struct spi_master {
  //Linux 驱动模型中的设备
 struct device dev;

  //此 spi_master 设备在全局 spi_master 链表中的节点
 struct list_head list;

  //此 spi_master 编号
 s16   bus_num;

  //此 spi_master 支持的片选信号数量
 u16   num_chipselect;

  //dma 地址对齐
 u16   dma_alignment;

  //此 spi_master 支持传输的 mode
 u16   mode_bits;
 u32   bits_per_word_mask;
 /* limits on transfer speed */
 u32   min_speed_hz;
 u32   max_speed_hz;

 /* other constraints relevant to this driver */
 u16   flags;

 /* lock and mutex for SPI bus locking */
 spinlock_t  bus_lock_spinlock;//总线自旋锁
 struct mutex  bus_lock_mutex;//总线互斥锁

  //总线是否处于 lock 状态
 bool   bus_lock_flag;

  //准备传输,设置传输的参数
 int   (*setup)(struct spi_device *spi);

  //传输数据
 int   (*transfer)(struct spi_device *spi,
     struct spi_message *mesg);
  // 设备 release 时的清除工作
 void   (*cleanup)(struct spi_device *spi);

 bool   (*can_dma)(struct spi_master *master,
        struct spi_device *spi,
        struct spi_transfer *xfer);

 bool   queued;//是否采用系统的序列化传输
 struct kthread_worker kworker;//序列化传输时的线程 worker
 struct task_struct *kworker_task;//序列化传输的线程
 struct kthread_work pump_messages;//序列化传输时的处理函数
 spinlock_t  queue_lock;//序列化传输时的queue_lock
 struct list_head queue;//序列化传输时的 msg 队列头
 struct spi_message *cur_msg;//序列化传输时当前的 msg
 bool   idling;
 bool   busy;//序列化传输时线程是否处于busy状态
 bool   running;//序列化传输时线程是否在运行
 bool   rt;//是否实时传输
  ......

 int (*prepare_transfer_hardware)(struct spi_master *master);

  //一个 msg 的传输实现
 int (*transfer_one_message)(struct spi_master *master,
        struct spi_message *mesg);
  ......

 /* gpio chip select */
 int   *cs_gpios;
  ......
};

spi_device:描述一个 spi 从机设备

struct spi_device {
  //Linux驱动模型中的设备
 struct device  dev;
 struct spi_master *master;//设备所连接的 spi 主机设备
 u32   max_speed_hz;//该设备最大传输速率
 u8   chip_select;//CS片选信号编号
 u8   bits_per_word;//每次传输长度
 u16   mode;//传输模式
 ......
 int   irq;//软件中断号
 void   *controller_state;//控制器状态
 void   *controller_data;//控制参数
 char   modalias[SPI_NAME_SIZE];//设备名称
  //CS 片选信号对应的 GPIO number
 int   cs_gpio;  /* chip select gpio */

 /* the statistics */
 struct spi_statistics statistics;
};

spi_driver:描述一个 spi 设备驱动

struct spi_driver {
  //此driver所支持的 spi 设备 list
 const struct spi_device_id *id_table;
 int   (*probe)(struct spi_device *spi);
 int   (*remove)(struct spi_device *spi);
  //系统 shutdown 时的回调函数
 void   (*shutdown)(struct spi_device *spi);
 struct device_driver driver;
};

spi_board_info:描述一个 spi 从机设备板级信息,无设备树时使用

struct spi_board_info {
  //设备名称
 char  modalias[SPI_NAME_SIZE];
 const void *platform_data;//设备的平台数据
 void  *controller_data;//设备的控制器数据
 int  irq;//设备的中断号
 u32  max_speed_hz;//设备支持的最大速率
 u16  bus_num;//设备连接的 spi 总线编号
 u16  chip_select;//设备连接的 CS 信号编号
 u16  mode;//设备使用的传输 mode
};

spi_transfer:描述 spi 传输的具体数据

struct spi_transfer {

 const void *tx_buf;//spi_transfer 的发送 buf
 void  *rx_buf;//spi_transfer 的接收 buf
 unsigned len;//spi_transfer 发送和接收的长度

 dma_addr_t tx_dma;//tx_buf 对应的 dma 地址
 dma_addr_t rx_dma;//rx_buf 对应的 dma 地址
 struct sg_table tx_sg;
 struct sg_table rx_sg;

  //spi_transfer传输完成后是否要改变 CS 片选信号
 unsigned cs_change:1;
 unsigned tx_nbits:3;
 unsigned rx_nbits:3;
  ......
 u8  bits_per_word;//spi_transfer 中一个 word 占的bits
 u16  delay_usecs;//两个 spi_transfer 直接的等待延迟
 u32  speed_hz;//spi_transfer 的传输速率

 struct list_head transfer_list;//spi_transfer挂载到的 message 节点
};

spi_message:描述一次 spi 传输的信息

struct spi_message {
  //挂载在此 msg 上的 transfer 链表头
 struct list_head transfers;
  //此 msg 需要通信的 spi 从机设备
 struct spi_device *spi;
  //所使用的地址是否是 dma 地址
 unsigned  is_dma_mapped:1;

 //msg 发送完成后的处理函数
 void   (*complete)(void *context);
 void   *context;//complete函数的参数
 unsigned  frame_length;
 unsigned  actual_length;//此 msg 实际成功发送的字节数
 int   status;//此 msg 的发送状态,0:成功,负数,失败

 struct list_head queue;//此 msg 在所有 msg 中的链表节点
 void   *state;//此 msg 的私有数据
};

队列化

SPI 数据传输可以有两种方式:同步方式和异步方式。

同步方式:数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返回。

异步方式:数据传输的发起者无需等待传输的结束,数据传输期间还可以做其它事情,用代码来解释就是,调用传输的函数后,函数会立刻返回而不用等待数据传输完成,我们只需设置一个回调函数,传输完成后,该回调函数会被调用以通知发起者数据传送已经完成。

同步方式简单易用,很适合处理那些少量数据的单次传输。但是对于数据量大、次数多的传输来说,异步方式就显得更加合适。

对于 SPI 控制器来说,要支持异步方式必须要考虑以下两种状况:

  1. 对于同一个数据传输的发起者,既然异步方式无需等待数据传输完成即可返回,返回后,该发起者可以立刻又发起一个 message,而这时上一个message还没有处理完。

  2. 对于另外一个不同的发起者来说,也有可能同时发起一次message传输请求。

队列化正是为了为了解决以上的问题,所谓队列化,是指把等待传输的 message 放入一个等待队列中,发起一个传输操作,其实就是把对应的 message 按先后顺序放入一个等待队列中,系统会在不断检测队列中是否有等待传输的 message,如果有就不停地调度数据传输内核线程,逐个取出队列中的 message 进行处理,直到队列变空为止。SPI 通用接口层为我们实现了队列化的基本框架。

spi_message 就是一次 SPI 数据交换的原子操作,不可打断。

3、SPI 控制器驱动层

SPI 控制器驱动层负责最底层的数据收发,主要有以下功能:

  1. 申请必要的硬件资源,比如中断、DMA 通道、DMA 内存缓冲区等等

  2. 配置 SPI 控制器的工作模式和参数,使之可以和相应的设备进行正确的数据交换

  3. 向通用接口层提供接口,使得上层的协议驱动可以通过通用接口层访问控制器驱动

  4. 配合通用接口层,完成数据消息队列的排队和处理,直到消息队列变空为止

SPI 主机驱动就是 SOC 的 SPI 控制器驱动。Linux 内核使用 spi_master/spi_controller 表示 SPI 主机驱动,spi_master 是个结构体,定义在 include/linux/spi/spi.h 文件中。

SPI 主机驱动的核心就是申请 spi_master,然后初始化 spi_master,最后向 Linux 内核注册 spi_master。

API 如下:

spi_alloc_master 函数:申请 spi_master。
spi_master_put 函数:释放 spi_master。

spi_register_master函数:注册 spi_master。
spi_unregister_master 函数:注销 spi_master。

spi_bitbang_start函数:注册 spi_master。
spi_bitbang_stop 函数:注销 spi_master。

SPI 主机驱动的加载

以 MTK 为例,源码来自于小米开源项目

https://github.com/MiCode/Xiaomi_Kernel_OpenSource

小米每做一个项目,都会把 kernel 部分开源,因为需要遵循 Linux GPL 开源协议。

【设备】声明在设备树中

kernel-4.14/arch/arm64/boot/dts/mediatek/mt6885.dts

【驱动】

kernel-4.14/drivers/spi/spi-mt65xx.c

匹配以后,probe 函数执行,申请 spi_master,初始化 spi_master,最后向 Linux 内核注册 spi_master。

4、软件流程

看懂该图,对 SPI 驱动框架就有完整的了解了。

1、2、3 按顺执行,首先有 spi 总线的注册,然后是 spi 控制器驱动加载,然后是设备驱动加载。区别在于,spi 控制器驱动加载时,是靠 platform 总线匹配设备(控制器)与驱动。spi 设备驱动加载时,是靠 spi 总线匹配设备(外设IC)与驱动。

init flow

spi_register_master 的调用序列图

队列化的工作机制及过程

当协议驱动程序通过 spi_async 发起一个 message 请求时,队列化和工作线程被激活,触发一些列的操作,最终完成 message 的传输操作。

spi_sync 与 spi_async 类似,只是有一个等待过程。

5、SPI 设备驱动

【设备】声明在设备树中

注意:设备的声明,slave device node 应该包含在你所要挂载的 &spi node 下,将 device 绑定在 master 上。然后通过 pinctrl 方式指定 GPIO,并在驱动中操作 pinctrl 句柄。

【驱动】demo

Linux 内核使用 spi_driver 结构体来表示 spi 设备驱动,我们在编写 SPI 设备驱动的时候需要实现 spi_driver。spi_driver 结构体定义在 include/linux/spi/spi.h 文件中。

spi_register_driver:注册 spi_driver
spi_unregister_driver:销掉 spi_driver
/* probe 函数 */
static int xxx_probe(struct spi_device *spi)
{

 /* 具体函数内容 */
 return 0;
}

/* remove 函数 */
static int xxx_remove(struct spi_device *spi)
{

 /* 具体函数内容 */
 return 0;
}

/* 传统匹配方式 ID 列表 */
static const struct spi_device_id xxx_id[] = {

 {"xxx", 0},
 {}
};

/* 设备树匹配列表 */
static const struct of_device_id xxx_of_match[] = {

 { .compatible = "xxx" },
 { /* Sentinel */ }
};

/* SPI 驱动结构体 */
static struct spi_driver xxx_driver = {

 .probe = xxx_probe,
 .remove = xxx_remove,
 .driver = {
  .owner = THIS_MODULE,
  .name = "xxx",
  .of_match_table = xxx_of_match,
  },
 .id_table = xxx_id,
};

/* 驱动入口函数 */
static int __init xxx_init(void)
{

 return spi_register_driver(&xxx_driver);
}

/* 驱动出口函数 */
static void __exit xxx_exit(void)
{

 spi_unregister_driver(&xxx_driver);
}

module_init(xxx_init);
module_exit(xxx_exit);

在驱动入口函数中调用 spi_register_driver 来注册 spi_driver。

在驱动出口函数中调用 spi_unregister_driver 来注销 spi_driver。

spi 读写数据demo

/* SPI 多字节发送 */
static int spi_send(struct spi_device *spi, u8 *buf, int len)
{
 int ret;
 struct spi_message m;
 
 struct spi_transfer t = {
  .tx_buf = buf,
  .len = len,
 };
 
 spi_message_init(&m); /* 初始化 spi_message */
 spi_message_add_tail(t, &m);/* 将 spi_transfer 添加到 spi_message 队列 */
 ret = spi_sync(spi, &m); /* 同步传输 */
 return ret;
}
/* SPI 多字节接收 */
static int spi_receive(struct spi_device *spi, u8 *buf, int len)
{
 int ret;
 struct spi_message m;
 
 struct spi_transfer t = {
  .rx_buf = buf,
  .len = len,
 };
 
 spi_message_init(&m); /* 初始化 spi_message */
 spi_message_add_tail(t, &m);/* 将 spi_transfer 添加到 spi_message 队列 */
 ret = spi_sync(spi, &m); /* 同步传输 */
 return ret;
}

除了 init、exit、probe、remove、read、write 函数外,其他的函数看需求实现,这几个是最基本的。

6、总结

Linux 是 总线、设备、驱动 的框架,理解了这个框架,就能理解所有的模块驱动框架。

SPI 驱动比 I2C 驱动还是简单很多的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sourcetree的使用

目录 前言 一、Sourcetree简介 二、创建分支与合并分支 三、合并冲突问题 总结 前言 今天提交项目代码时,接触到非常好用方便的可视化Git管理提交软件Sourcetree,今天记录一下使用过程 一、Sourcetree简介 通过Git可以进行对项目的版本管理,但是如果直接使用Git的软件会比…

MinIO快速入门——在Linux系统上安装和启动

1、简介 MinIO 是一款基于Go语言发开的高性能、分布式的对象存储系统。客户端支持Java,Net,Python,Javacript, Golang语言。MinIO系统&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等。 2、环境搭建&#…

【MySQL】一文带你了解数据库约束

文章目录 1. 约束类型2&#xff0e;PRIMARY KEY&#xff1a;主键约束3&#xff0e;FOREIGN KEY&#xff1a;外键约束4&#xff0e;NOT NULL&#xff1a;非空约束5&#xff0e;UNIQUE&#xff1a;唯一约束5&#xff0e;DEFAULT&#xff1a;默认值约束6&#xff0e;总结 1. 约束类…

用数据说话,R语言有哪七种可视化应用?

今天&#xff0c;随着数据量的不断增加&#xff0c;数据可视化成为将数字变成可用的信息的一个重要方式。R语言提供了一系列的已有函数和可调用的库&#xff0c;通过建立可视化的方式进行数据的呈现。在使用技术的方式实现可视化之前&#xff0c;我们可以先和AI科技评论一起看看…

SpringBoot 源码分析准备应用上下文(2)-prepareContext

一、入口 /*** Run the Spring application, creating and refreshing a new* {link ApplicationContext}.* param args the application arguments (usually passed from a Java main method)* return a running {link ApplicationContext}*/public ConfigurableApplicationC…

生成测试报告,在Unittest框架中就是简单

测试套件&#xff08;Test Suite&#xff09;是测试用例、测试套件或两者的集合&#xff0c;用于组装一组要运行的测试&#xff08;多个测试用例集合在一起&#xff09;。 &#xff08;1&#xff09;创建一个测试套件&#xff1a; import unittest suite unittest.TestSuite…

车载测试:详解ADAS传感器(相机)标定数据采集方法

1.基本原理 相机外参标定&#xff0c;通过拍摄多角度棋盘格标定相机外参。 2.外参标定板设计 标定板分为垂直标定板和水平标定板&#xff0c;由于地面的水平标定板不容易被检测到&#xff0c;本文采用垂直标定板进行相机标定。 在标定过程中标定板需要和车身坐标成正交状态…

中国人民大学与加拿大女王大学金融硕士——所有的为时已晚都是恰逢其时

你是否有过同样的感觉&#xff0c;工作之余想学点什么又觉得有点晚了&#xff0c;心里反复纠结&#xff0c;总是没个结果。记得在网上看到过一句话&#xff0c;你觉得为时已晚的时候&#xff0c;恰恰是最早的时候。与其在心里反复琢磨&#xff0c;不如去付诸行动。中国人民大学…

超详细,自动化测试-Allure测试报告动态生成用例/标题(实战撸码)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 pytest 结合 allu…

Android-源码分析-MTK平台BUG解决:客户电池NTC功能(移植高低温报警,关机报警功能)---第一天分析与解决

MTK平台BUG解决&#xff1a;客户电池NTC功能 一、概述二、步骤1&#xff1a;实现目的&#xff1f;2&#xff1a;准备工作&#xff1a;机制原理的学习&#xff08;1&#xff09;MTK充电温度保护机制&#xff08;2&#xff09;MTKthermal高温充电机制 3&#xff1a;定位查找与源码…

提高自动化测试效率 , WEB自动化框架的基础封装模块!

目录 前言 一、环境搭建 1. Python环境 2. Selenium安装 3. Chrome浏览器 二、基础封装模块介绍 1. 代码框架介绍 2. 使用示例 三、总结 前言 在软件测试中&#xff0c;WEB自动化测试已成为不可或缺的一部分。WEB自动化测试涉及到大量的代码编写&#xff0c;为了提高…

SUSTechPOINTS三维点云标注工具使用

官方地址&#xff1a;SUSTechPOINTS 官方中文教程 相关文章&#xff1a; OpenPCDet安装、使用方式及自定义数据集训练 安装 git clone https://github.com/naurril/SUSTechPOINTS cd SUSTechPOINTS pip install -r requirement.txt wget https://github.com/naurril/SUSTec…

【全栈开发】基于Spring BootVueAndroid扫码授权登录

文章目录 一、引言二、设计1、移动端&#xff08;Android&#xff09;&#xff08;1&#xff09;库&#xff08;2&#xff09;依赖&#xff08;3&#xff09;使用 2、前端&#xff08;Vue&#xff09;&#xff08;1&#xff09;库&#xff08;2&#xff09;使用 3、后端&#x…

Home Assistant-开源智能家居系统

Home Assistant&#xff08;以下简称HA&#xff09; 它是个开源的智能家居平台&#xff0c;一个系统平台软件&#xff0c;像TB 1.它把家中的智能家居设备整合到HA中&#xff0c;它能够接入的设备非常的多比如小米、博联、易微联、飞利浦、特斯拉…&#xff0c;也可以接入软件&…

Python远程连接Ubuntu20.4下的Mariadb数据库进行操作

文章目录 前言一、ubuntu20.4安装mariadb10.51、更换数据源2、安装mariadb3、设置密码4、设置管理用户5、设置远程登录6、修改端口 二、mariadb10.5建库建表创建数据库2.建表 三、Python代码及环境准备1、Python2、环境 四、总结五、参考资料 前言 环境&#xff1a; 1、Ubuntu2…

Chromium浏览器渗透测试工具EvilSelenium简单入门

EvilSelenium是一款基于Selenium的渗透测试工具&#xff0c;该工具基于武器化的Selenium实现其功能&#xff0c;可以帮助广大研究人员针对基于Chromium的浏览器进行安全分析和渗透测试。 功能介绍 1、通过autofill获取存储的凭证信息&#xff1b; 2、获取Cookie数据&#xf…

高考答题卡怎么被机器识别?基于OpenCV答题卡识别模拟-米尔ARM+FPGA异构开发板

本篇测评由优秀测评者“筑梦者与梦同行”提供。 01. 前言MYD-JX8MMA7SDK发布说明 根据下图文件内容可以知道myir-image-full系统支持的功能&#xff0c;其支持OpenCV&#xff0c;也就不用在格外安装相关驱动包等&#xff0c;省了很多事情。 02. MYD-JX8MMA7软件评估指南 本文…

Java中Object类常用的11个方法

Java中Object类常用的11个方法 先看下 Object 的类结构&#xff08;快捷键&#xff1a;alt7&#xff09;&#xff1a; 1. getClass 方法&#xff08;获取类的class对象。&#xff09; public final native Class<?> getClass();final 方法、获取对象的运行时 class …

学生成绩管理系统(PowerDesigner+MyEclipse+SQL Server)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;69学生 获取完整源码源文件论文报告数据库表等 系统中用户共有管理员、教师和学生三种&#xff0c;分别对应不同的权限。 管理员 &#xff08;1&#xff09;院系的开设&#xff1b; &#xff08;2&#xff09;教师基本信息…

VScode的插件和.json文件和快捷键

文章目录 1. 插件了解插件的配置的修改Remote DevelopmentFilter LineC/C 和 C intellisense&#xff08;弃用&#xff09;cpp-check-lint 2. VScode中的.json文件2.1 tasks.jsontasks.json文件的格式tasks.json文件中任务的配置arg参数选择 案例&#xff1a; 2.2 lauch.json参…