【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十六章 设备驱动IO控制

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、

【公众号】迅为电子

【粉丝群】258811263(加群获取驱动文档+例程)


第五十六章 设备驱动IO控制

本章导读

本章节我们将来学习ioctl接口,那么我们在学习之前先来回想一下,我们以前操作一个GPIO是怎么操作的呢?在前面章节中我们使用GPIO函数来操作GPIO的,在使用GPIO函数之前是使用寄存器来进行操作的,我们使用GPIO函数操作GPIO比直接使用寄存器来操作GPIO进一步升级了。我们操作GPIO的时候,使用的是逻辑判断,kbuf[0]的数据是从应用层传递过来的我们要使用到copy_from_usr。当我们在应用层write驱动节点的时候,会触发驱动层的write函数,然后我们在write函数里面控制我们的GPIO。虽然这样的方法是可以的,但是这样的方法是不是比较麻烦呢?有没有更简单的办法呢?当然是有了,方法就是我们这节课讲的ioctl接口。

56.1章节讲解了设备驱动IO控制原理

56.2章节编写驱动程序和应用程序,测试应用层不传递数据

56.3章节编写驱动程序和应用程序,测试应用层写数据

56.4章节编写驱动程序和应用程序,测试应用层读数据

本章内容对应视频讲解链接(在线观看):

ioctl接口(  https://www.bilibili.com/video/BV1Vy4y1B7ta?p=32

ioctl接口(  https://www.bilibili.com/video/BV1Vy4y1B7ta?p=33

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\013-设备驱动io控制”路径下。

56.1 设备驱动IO控制原理

在内核3.0 以前,ioctl接口的名字叫ioctl;内核3.0以后,ioctl接口的名字叫unlocked_ioctl。unlocked_ioctl就是ioctl接口,但是功能和对应的系统调用均没有发生变化。unlocked_ioctl和read/write函数有什么异同呢?相同点:都可以往内核写数据。不同点:read函数只能完成读的功能,write只能完成写的功能。读取大数据的时候效率高。ioctl既可以读也可以写,读取大数据的时候效率不高。

我们现在有了ioctl函数,内核已经把工作的任务给我们区分了,定义命令就不再使用read和write函数了,而是使用ioctl函数,因为ioctl函数的任务就是对我们的工作参数进行设置和查询,write和read函数专注于数据传输。

在驱动程序里, ioctl()函数上传送的变量 cmd是应用程序用于区别设备驱动程序请求处理内容的值。cmd除了可区别数字外,还包含有助于处理的几种相应信息。 cmd的大小为 32位,共分 4 个域,命令规则为:

第一个分区:0-7,命令的编号,范围是0-255.

第二个分区:8-15,命令的幻数。

第一个分区和第二个分区主要作用是用来区分命令的。

第三个分区:16-29表示传递的数据大小。

第四个分区:30-31 代表读写的方向。

00:表示用户程序和驱动程序没有数据传递

10:表示用户程序从驱动里面读数据

01:表示用户程序向驱动里面写数据

11:先写数据到驱动里面然后在从驱动里面把数据读出来。

 合成宏:

 _IO(type,nr)  :用来定义没有数据传递的命令

_IOR(type,nr,size)  :用来定义从驱动中读取数据的命令

_IOW(type,nr,size)  :用来定义向驱动写入数据的命令

_IOWR(type,nr,size) :用来定义数据交换类型的命令,先写入数据,再读取数据这类命令。 

参数说明:

  • type:表示命令组成的魔数,也就是8~15位
  • nr:表示命令组成的编号,也就是0~7位
  • size:表示命令组成的参数传递大小,注意这里不是传递数字,而是数据类型,如要传递4字节,就可以写成int。

分解宏:

_IOC_DIR(nr)    分解命令的方向,也就是上面说30~31位的值

_IOC_TYPE(nr)   :分解命令的魔数,也就是上面说8~15位的值

_IOC_NR(nr)    分解命令的编号,也就是上面说0~7位

_IOC_SIZE(nr)    :分解命令的复制数据大小,也就是上面说的16~29位

参数说明:

  • nr :要分解的命令

验证程序代码如下所示:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define CMD_TEST0 _IO('L', 0)
#define CMD_TEST1 _IO('A', 1)
#define CMD_TEST2 _IOW('L', 2, int)
#define CMD_TEST3 _IOR('L', 3, int)int main(int argc, char *argv[])
{printf("30-31 is %d \n", _IOC_DIR(CMD_TEST0));printf("30-31 is %d \n", _IOC_DIR(CMD_TEST3));printf("7-15 is %c \n", _IOC_TYPE(CMD_TEST0));printf("7-15 is %c \n", _IOC_TYPE(CMD_TEST1));printf("0-7 is %d \n", _IOC_NR(CMD_TEST2));
}

那么我们定义的这些命令要怎么用呢?第一种方法是用分解宏将它分解出来,还有一种用法是搭配switch来用。

56.2 编写测试-不传递数据

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\013-设备驱动io控制\001”路径下。

我们拷贝第42章的驱动代码,在此基础上进行修改,完整代码如下所示:

//初始化头文件
#include <linux/init.h>
//最基本的文件,支持动态添加和卸载模块。
#include <linux/module.h>
//包含了miscdevice结构的定义及相关的操作函数。
#include <linux/miscdevice.h>
//文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)
#include <linux/fs.h>
//包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include <linux/uaccess.h>
//包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include <linux/io.h>
//驱动要写入内核,与内核相关的头文件
#include <linux/kernel.h>#define CMD_TEST1 _IO('A', 1)
#define CMD_TEST0 _IO('L', 0)ssize_t misc_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{printk("misc_read\n ");return 0;
}
ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{/*应用程序传入数据到内核空间,然后控制led的逻辑,在此添加*/// kbuf保存的是从应用层读取到的数据char kbuf[64] = {0};// copy_from_user 从应用层传递数据给内核层if (copy_from_user(kbuf, ubuf, size) != 0){// copy_from_user 传递失败打印printk("copy_from_user error \n ");return -1;}//打印传递进内核的数据printk("kbuf is %d\n ", kbuf[0]);return 0;
}
/***************************************************************************************** @brief misc_release : 用户空间关闭设备节点时执行此函数* @param inode        : 文件索引* @param file         : 文件* @return             :成功返回 0  ****************************************************************************************/
int misc_release(struct inode *inode, struct file *file)
{printk("hello misc_relaease bye bye \n ");return 0;
}
/***************************************************************************************** @brief misc_open : 用户空间打开设备节点时执行此函数* @param inode     : 文件索引* @param file      : 文件* @return          : 成功返回 0    ****************************************************************************************/
int misc_open(struct inode *inode, struct file *file)
{printk("hello misc_open\n ");return 0;
}
/***************************************************************************************** @brief misc_ioctl : 用户空间使用ioctl(int fd, unsigned long request, ...(void* arg))时*                      自动执行此函数,根据命令执行对应的操作* @param file       : 设备文件* @param cmd        : 用户空间ioctl接口命令request* @param value      : 用户空间的arg指针,依赖于接口命令request* @return           : 成功返回 0   ****************************************************************************************/
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{printk("LED ON \n");switch (cmd) //根据命令进行对应的操作{case CMD_TEST0:printk("LED ON \n");break;case CMD_TEST1:printk("LED OFF \n");break;}return 0;
}
struct file_operations misc_fops = {.owner = THIS_MODULE,.open = misc_open,.release = misc_release,.read = misc_read,.write = misc_write,.unlocked_ioctl = misc_ioctl /* 64 bit system special */};
struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops,
};
static int misc_init(void)
{int ret;ret = misc_register(&misc_dev);if (ret < 0){printk("misc registe is error \n");}printk("misc registe is succeed \n");return 0;
}
static void misc_exit(void)
{misc_deregister(&misc_dev);printk(" misc gooodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

参考第三十七章 Linux内核模块,将led.c编译为led.ko 文件,如下图所示:

应用程序ioctrl.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>#define CMD_TEST0 _IO('L',0)
#define CMD_TEST1 _IO('A',1)
//#define CMD_TEST2 _IOW('L',2,int)
//#define CMD_TEST3 _IOR('L',3,int)int main(int argc,char *argv[])
{int fd;char buf[64] ={0};fd = open("/dev/hello_misc",O_RDWR);if(fd < 0){perror("open error \n");return fd;  }while(1){ioctl(fd,CMD_TEST0);sleep(2);ioctl(fd,CMD_TEST1);}return 0;
}

我们将ioctl.c文件拷贝到Ubuntu的/home/topeet/imx8mm/13/001目录下,输入以下命令编译ioctl.c

我们进入共享目录,加载驱动模块以后,再运行应用程序,如下图所示: 

56.3 编写测试-写数据

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\013-设备驱动io控制\002”路径下。

 我们在56.2章节代码的基础上进行修改,完整代码如下所示:

//初始化头文件
#include <linux/init.h>
//最基本的文件,支持动态添加和卸载模块。
#include <linux/module.h>
//包含了miscdevice结构的定义及相关的操作函数。
#include <linux/miscdevice.h>
//文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)
#include <linux/fs.h>
//包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include <linux/uaccess.h>
//包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include <linux/io.h>
//驱动要写入内核,与内核相关的头文件
#include <linux/kernel.h>#define CMD_TEST1 _IO('A', 1)
#define CMD_TEST0 _IO('L', 0)
#define CMD_TEST2 _IOW('L', 2, int)
#define CMD_TEST3 _IOW('L', 3, int)ssize_t misc_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{printk("misc_read\n ");return 0;
}
ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{/*应用程序传入数据到内核空间,然后控制led的逻辑,在此添加*/// kbuf保存的是从应用层读取到的数据char kbuf[64] = {0};// copy_from_user 从应用层传递数据给内核层if (copy_from_user(kbuf, ubuf, size) != 0){// copy_from_user 传递失败打印printk("copy_from_user error \n ");return -1;}//打印传递进内核的数据printk("kbuf is %d\n ", kbuf[0]);return 0;
}
/***************************************************************************************** @brief misc_release : 用户空间关闭设备节点时执行此函数* @param inode        : 文件索引* @param file         : 文件* @return             :成功返回 0  ****************************************************************************************/
int misc_release(struct inode *inode, struct file *file)
{printk("hello misc_relaease bye bye \n ");return 0;
}
/***************************************************************************************** @brief misc_open : 用户空间打开设备节点时执行此函数* @param inode     : 文件索引* @param file      : 文件* @return          : 成功返回 0    ****************************************************************************************/
int misc_open(struct inode *inode, struct file *file)
{printk("hello misc_open\n ");return 0;
}
/***************************************************************************************** @brief misc_ioctl : 用户空间使用ioctl(int fd, unsigned long request, ...(void* arg))时*                      自动执行此函数,根据命令执行对应的操作* @param file       : 设备文件* @param cmd        : 用户空间ioctl接口命令request* @param value      : 用户空间的arg指针,依赖于接口命令request* @return           : 成功返回 0   ****************************************************************************************/
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{switch (cmd)//根据命令进行对应的操作{case CMD_TEST2:printk("LED ON \n");printk("value is %ld\n", value);break;case CMD_TEST3:printk("LED OFF \n");printk("value is %ld\n", value);break;}return 0;
}
struct file_operations misc_fops = {.owner = THIS_MODULE,.open = misc_open,.release = misc_release,.read = misc_read,.write = misc_write,.unlocked_ioctl = misc_ioctl };
struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops,
};
static int misc_init(void)
{int ret;ret = misc_register(&misc_dev);if (ret < 0){printk("misc registe is error \n");}printk("misc registe is succeed \n");return 0;
}
static void misc_exit(void)
{misc_deregister(&misc_dev);printk(" misc goodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

将led.c编译为led.ko 文件,如下图所示:

应用程序代码ioctrl.c代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>#define CMD_TEST0 _IO('L',0)
#define CMD_TEST1 _IO('A',1)#define CMD_TEST2 _IOW('L',2,int)
#define CMD_TEST3 _IOW('L',3,int)
//#define CMD_TEST3 _IOR('L',3,int)int main(int argc,char *argv[])
{int fd;char buf[64] ={0};fd = open("/dev/hello_misc",O_RDWR);if(fd < 0){perror("open error \n");return fd;  }while(1){ioctl(fd,CMD_TEST2,0);sleep(2);ioctl(fd,CMD_TEST3,1);}return 0;
}

编译完成如下图所示:

我们进入共享目录,卸载原来加载的驱动模块,然后再加载新的驱动模块以后,再运行应用程序,如下图所示: 

56.4 编写测试-读数据

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\013-设备驱动io控制\003”路径下。

我们在56.3的代码的基础上进行修改,完整代码如下所示:

//初始化头文件
#include <linux/init.h>
//最基本的文件,支持动态添加和卸载模块。
#include <linux/module.h>
//包含了miscdevice结构的定义及相关的操作函数。
#include <linux/miscdevice.h>
//文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)
#include <linux/fs.h>
//包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include <linux/uaccess.h>
//包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include <linux/io.h>
//驱动要写入内核,与内核相关的头文件
#include <linux/kernel.h>#define CMD_TEST1 _IO('A', 1)
#define CMD_TEST0 _IO('L', 0)
#define CMD_TEST2 _IOW('L', 2, int)
#define CMD_TEST3 _IOW('L', 3, int)
#define CMD_TEST4 _IOR('L', 4, int)ssize_t misc_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{printk("misc_read\n ");return 0;
}
ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{/*应用程序传入数据到内核空间,然后控制led的逻辑,在此添加*/// kbuf保存的是从应用层读取到的数据char kbuf[64] = {0};// copy_from_user 从应用层传递数据给内核层if (copy_from_user(kbuf, ubuf, size) != 0){// copy_from_user 传递失败打印printk("copy_from_user error \n ");return -1;}//打印传递进内核的数据printk("kbuf is %d\n ", kbuf[0]);return 0;
}
/***************************************************************************************** @brief misc_release : 用户空间关闭设备节点时执行此函数* @param inode        : 文件索引* @param file         : 文件* @return             :成功返回 0  ****************************************************************************************/
int misc_release(struct inode *inode, struct file *file)
{printk("hello misc_relaease bye bye \n ");return 0;
}
/***************************************************************************************** @brief misc_open : 用户空间打开设备节点时执行此函数* @param inode     : 文件索引* @param file      : 文件* @return          : 成功返回 0    ****************************************************************************************/
int misc_open(struct inode *inode, struct file *file)
{printk("hello misc_open\n ");return 0;
}
/***************************************************************************************** @brief misc_ioctl : 用户空间使用ioctl(int fd, unsigned long request, ...(void* arg))时*                      自动执行此函数,根据命令执行对应的操作* @param file       : 设备文件* @param cmd        : 用户空间ioctl接口命令request* @param value      : 用户空间的arg指针,依赖于接口命令request* @return           : 成功返回 0   ****************************************************************************************/
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{int val;switch (cmd)//根据命令进行对应的操作{case CMD_TEST2:printk("LED ON \n");printk("value is %ld\n", value);break;case CMD_TEST3:printk("LED OFF \n");printk("value is %ld\n", value);break;case CMD_TEST4:val = 12;if (copy_to_user((int *)value, &val, sizeof(val)) != 0){printk("cpoy_to_usr error \n");return -1;}break;}return 0;
}
struct file_operations misc_fops = {.owner = THIS_MODULE,.open = misc_open,.release = misc_release,.read = misc_read,.write = misc_write,.unlocked_ioctl = misc_ioctl };
struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops,
};
static int misc_init(void)
{int ret;ret = misc_register(&misc_dev);if (ret < 0){printk("misc registe is error \n");}printk("misc registe is succeed \n");return 0;
}
static void misc_exit(void)
{misc_deregister(&misc_dev);printk(" misc gooodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

将led.c编译为led.ko 文件,如下图所示:

应用程序代码ioctl.c代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>#define CMD_TEST0 _IO('L', 0)
#define CMD_TEST1 _IO('A', 1)#define CMD_TEST2 _IOW('L', 2, int)
#define CMD_TEST3 _IOW('L', 3, int)
#define CMD_TEST4 _IOR('L', 4, int)int main(int argc, char *argv[])
{int fd;int value;char buf[64] = {0};fd = open("/dev/hello_misc", O_RDWR);if (fd < 0){perror("open error \n");return fd;}while (1){ioctl(fd, CMD_TEST4, &value);printf("value is %d \n", value);sleep(2);}return 0;
}

 编译完成如我们进入共享目录,卸载原来加载的驱动模块,然后再加载新的驱动模块以后,再运行应用程序,如下图所示:

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

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

相关文章

【Qt】Qt容器和STL容器的区别

1、简述 Qt容器和STL容器略有不同,作为一个Qter,应该知道它们之间的异同。 Qt容器官网介绍:https://doc.qt.io/qt-5/containers.html STL容器官网介绍:https://zh.cppreference.com/w/cpp/container 2、Qt容器和STL容器的对应关系 注意:QList 与 std::list 无关,QSet …

Python - 开源库 ReportLab 库合并 CVS 和图像生成 PDF 文档

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/140281680 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Report…

算法 —— 暴力枚举

目录 循环枚举 P2241 统计方形&#xff08;数据加强版&#xff09; P2089 烤鸡 P1618 三连击&#xff08;升级版&#xff09; 子集枚举 P1036 [NOIP2002 普及组] 选数 P1157 组合的输出 排列枚举 P1706 全排列问题 P1088 [NOIP2004 普及组] 火星人 循环枚举 顾名思…

Unity UGUI 之 Input Field

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 1.Input Field是什么&#xff1f; 给玩家提供输入的输入框 2.重要参数 中英文对照着看…

环境搭建-Windows系统搭建Docker

Windows系统搭建Docker 一、系统虚拟化1.1 启用虚拟化2.2 启用Hyper-v并开启虚拟任务 三、安装WSL3.1 检验安装3.2 安装WSL 四、Docker安装4.1 Docker安装包下载4.2 Docker安装4.3 运行docker Desktop 五、Docker配置5.1 打开Docker配置中心5.2 配置Docker国内镜像 六、使用 一…

DAY15

数组 冒泡排序 冒泡排序无疑是最为出名的排序算法之一&#xff0c;总共有八大排序 冒泡的代码还是相当简单的&#xff0c;两层循环&#xff0c;外层冒泡轮数&#xff0c;里层依次比较&#xff0c;江湖中人人尽皆知 我们看到嵌套循环&#xff0c;应该马上就可以得到这个算法的…

错误解决 error CS0117: ‘Buffer‘ does not contain a definition for ‘BlockCopy‘

Unity 2022.3.9f1 导入 Runtime OBJ Importer 后出现&#xff1a; error CS0117: ‘Buffer’ does not contain a definition for ‘BlockCopy’ 解决办法&#xff1a; 源代码&#xff1a; int DDS_HEADER_SIZE 128; byte[] dxtBytes new byte[ddsBytes.Length - DDS_HEAD…

Python + PyQt 搭建可视化页面(PyCharm)

Python PyQt 搭建可视化页面&#xff08;PyCharm&#xff09; 配置PyQt5环境 1.1 安装PyQt5和PyQt5-tools pip install PyQt5pip install PyQt5-tools1.2 QtDesigner和PyUIC环境的配置 配置QTDesigner&#xff0c;用来打开QT可视化开发工具 在PyCharm中依次打开&#xff1a…

软件合集:5大3C产品在线说明书制作利器

3C产品&#xff08;指计算机、通讯和消费性电子三类产品的简称&#xff09;在线说明书在当今数字化时代扮演着至关重要的角色&#xff0c;相较于传统纸质说明书&#xff0c;3C产品在线说明书更加便捷、实时更新且环保。用户可随时在线访问&#xff0c;获取最新信息&#xff0c;…

Matplotlib知识点详解(巨详细!!!)

37.Matplotlib&#xff1a; 配置参数&#xff1a; 如果浏览器不显示图片&#xff0c;加上 %matplotlib inline 让图片可以显示中文 plt.rcParams[font.sans-serif]SimHei 让图片可以显示负号 plt.rcParams[axes.unicode_minus]False 支持svg矢量图 %config Inlineback…

听我的,事务注解真的别乱动!

更多大厂面试内容可见 -> http://11come.cn 听我的&#xff0c;事务注解真的别乱动&#xff01; 背景 故事的起源&#xff1a; 发现存在重复插入数据库的现象&#xff0c;通过排查发现是因为事务中包了锁 原因分析&#xff1a; 当线程 1 释放锁之后&#xff0c;但是此时还…

Java反射详细学习笔记

动态代理 特点 : 无侵入式的给代码增加额外的功能 ; 代理里面就是对象要被代理的方法 ; 通过接口保证,后面的对象和代理需要实现同一个接口 &#xff0c; 接口中就是被代理的所有方法 ; 如何为java对象创建一个代理 : java.lang.reflect.Proxy类 : 提供了为对象产生代理对象的…

【全面讲解下Docker in Docker的原理与实践】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 👉目录 👉前言👉原理👉实践👉安全和最佳实践👉前言 🦛…

JAVA中的泛型机制详解

1.泛型的概念 java泛型是java5引入的一个特性&#xff0c;它允许我们为类&#xff0c;接口&#xff0c;方法指定类型参数&#xff0c;从而提供编译时类型安全检查。泛型的本质是参数化类型&#xff0c;即在声明类&#xff0c;接口或者方法时不指定具体的类型&#xff0c;而是使…

openEuler 安装 ROS2 Humble

openEuler 安装 ROS2 Humble 1 介绍2 安装【openEuler 24.03】2.1 Installing ros-humble2.2 Test ros-humble【python 版本冲突&#xff0c;未解决】 2 安装【openEuler 22.03】3 Python 版本问题【pyenv】参考 1 介绍 2 安装【openEuler 24.03】 2.1 Installing ros-humble…

力扣高频SQL 50题(基础版)第十三题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第十三题570. 至少有5名直接下属的经理题目说明思路分析实现过程准备数据实现方式结果截图 力扣高频SQL 50题&#xff08;基础版&#xff09;第十三题 570. 至少有5名直接下属的经理 题目说明 表: Employee ------…

Java面试八股之后Spring、spring mvc和spring boot的区别

Spring、spring mvc和spring boot的区别 Spring, Spring Boot和Spring MVC都是Spring框架家族的一部分&#xff0c;它们各自有其特定的用途和优势。下面是它们之间的主要区别&#xff1a; Spring: Spring 是一个开源的轻量级Java开发框架&#xff0c;最初由Rod Johnson创建&…

Linux之存储桶minio单机安装和使用简介

一、minio简介 MinIO 是一个高性能的分布式对象存储系统&#xff0c;主要用于存储非结构化数据&#xff0c;例如照片、视频、备份和日志文件。它是开源的&#xff0c;基于 Go 语言开发&#xff0c;具有高度可扩展性和高可用性&#xff0c;能够在私有云、公有云和边缘环境中部署…

20240725项目的maven环境报红-重新配置maven

1.在编辑器里面打开项目&#xff0c;导入源码 &#xff08;1&#xff09;找到项目的地址C:\Users\zzz\IdeaProjects\datasys&#xff0c;然后右击用idea编辑器打开。 &#xff08;2&#xff09;idea中上菜单栏打开open&#xff0c;然后输入file&#xff0c;选择源代码文件 2.…

LabVIEW放大器自动测量系统

开发了一个基于LabVIEW平台的多路前置放大器自动测量系统的开发与实施。该系统集成了硬件控制与软件编程&#xff0c;能够实现放大器各项性能指标的快速自动测量&#xff0c;有效提高了测试的精确性和效率。系统设计采用了虚拟仪器技术&#xff0c;结合了先进的测量与控制策略&…