linux platform架构下I2C接口驱动开发
目录
概述
1 认识I2C协议
1.1 初识I2C
1.2 I2C物理层
1.3 I2C协议分析
1.3.1 Start、Stop、ACK 信号
1.3.2 I2C协议的操作流程
1.3.3 操作I2C注意的问题
2 linux platform驱动开发
2.1 更新设备树
2.1.1 添加驱动节点
2.1.2 编译.dts
2.1.3 更新板卡中的.dtb
2.2 驱动程序设计要点
2.2.1 match设备节点
2.2.2 读写函数的注意点
2.2.2.1 读函数
2.2.2.1 写函数
3 驱动程序实现
3.1 编写驱动程序
3.2 编写Makefile
3.3 编译驱动
4 测试
4.1 编写测试代码
4.2 编写测试程序的Makefile
4.3 编译和运行测试代码
概述
本文主要详细介绍了I2C的知识,使用linux platform驱动架构开发一个基于i2c接口的驱动程序,其中包括编写和更新设备树文件,搭建驱动架构,编写驱动代码和测试代码。本文还是以AT24C02为例,介绍linux platform驱动下i2c类型设备驱动程序的设计方法。并介绍如何使用read和write函数来实现eeprom的读/写功能。
1 认识I2C协议
1.1 初识I2C
I2C 通讯协议(Inter-Integrated Circuit)是由 Philips 公司开发的一种简单、双向二线制同步串行总线, 只需要两根线即可在连接于总线上的器件之间传送信息。I2C 协议占用引脚特别少, 硬件实现简单, 可扩展型强, 现在被广泛地使用在系统内多个集成电路(IC)间的通讯。
1.2 I2C物理层
I2C 通讯设备之间的常用连接方式
物理层结构有如下特点:
1) 一条I2C总线上可以挂载多个设备,不同的设备地址必须不同
2)I2C总线由两条物理线路构成,分别为SCL和SDA,SCL为同步时钟线,SDA为数据线路
3)I2C可支持3中工作模式:标准模式(100k bit/ s),快速模式( 400k bit/ s),高速模式( 3.4M bit/ s)
1.3 I2C协议分析
完整的I2C工作时序图:
1.3.1 Start、Stop、ACK 信号
Start信号:
在空闲状态时,SDA为高电平,SCL也为高电平。当有数据需要传输时,Master首先发起start信号,SDA: 1-->0, SCL: 1
Stop信号:
数据传输完成后,SDA: 0-->1, SCL: 1
ACK信号:
在I2C协议中,数据传输的单位为byte, 传输完成一个数据时,需要8个bit, 在第9个bit( SCL电平: 0-->1)时,SDA : 0。该信号为ACK信号。
1.3.2 I2C协议的操作流程
需要注意的是I2C协议传输数据以字节为单位,每个字节有8个bit,传输完成一个字节后,还会发发送一个响应信号,即ACK信号,所以,其完成一个byte传输,实际需要9个bit。
Step-1: Master 发起Start信号 , SDA: 1---> 0, SCL: 1
Step-2: 传输数据,当SCL: 0 ->1, SDA发送一个bit,总共8个bit
Step-3: ACK信号,SCL: 0->1, SDA 1->0
Step-4: 传送下一个数据(循环执行: step-2 - > step-3)
Step-5: Master 发起Stop信号,SDA: 0--->1, SCL: 1
1.3.3 操作I2C注意的问题
1)空闲状态时,SDA=1, SCL1 =1
2) SCL 电平 0 ->1变化后,高电平保持期间,SDA上的数据才为有效bit
2 linux platform驱动开发
2.1 更新设备树
2.1.1 添加驱动节点
AT24C02引脚和IMX.6ULL引脚对应关系:
AT24C02 IO | IMX.6ULL PIN |
SCL | I2C2_SCL |
SDA | I2C2_SDA |
.dts文件路径:/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c/arch/arm/boot/dts/imx6ull-14x14-evk.dts
在.dts文件中添加如下代码:
at24c02: at24c02@50 {compatible = "atk-dl6y2c,at24c02";reg = <0x50>;};
其在imx6ull-14x14-evk.dts中位置:
2.1.2 编译.dts
编译.dts文件,并把编译生成的.dtb文件发送到NFS共享目录下,便于在板卡中操作该文件。
1)在内核根目录下使用如下命令编译.dts文件
make dtbs
2) 复制 .dtb 文件至NFS共享目录
cp arch/arm/boot/dts/imx6ull-14x14-emmc-4.3-480x272-c.dtb /home/mftang/nfs/atk_dl6y2c/
2.1.3 更新板卡中的.dtb
复制.dtb文件到相应的运行目录,然后重新板卡
cp /mnt/atk_dl6y2c/imx6ull-14x14-emmc-4.3-480x272-c.dtb /run/media/mmcblk1p1
reboot板卡后,内核会重新读取.dtb文件。然后在/proc/device-tree目录下查看板卡device tree,使用如下命令:
cd /sys/bus/i2c/devices ls
查看地址下设备名称
cat 1-0050/name
2.2 驱动程序设计要点
2.2.1 match设备节点
在板卡的.dts 文件中,定义的设备节点为:
在设备驱动,需要设计相应的匹配表来match该信息,驱动程序的代码如下:
static const struct of_device_id atk_dl6y2c_at24cxx[] = {{ .compatible = "atk-dl6y2c,at24c02" },{ },
};static const struct i2c_device_id at24c02_ids[] = {{ "xxxxyyy", (kernel_ulong_t)NULL },{ /* END OF LIST */ }
};/* platform_driver */
static struct i2c_driver at24cxx_driver = {.probe = at24cxx_probe,.remove = at24cxx_remove,.driver = {.name = "atk_at24cxx",.of_match_table = atk_dl6y2c_at24cxx,},.id_table = at24c02_ids,
};
2.2.2 读写函数的注意点
2.2.2.1 读函数
为了实现随机读取EEPROM中的数据,在用户层需要传递一个地址字节,于是该接口设计如下:
int at24cxx_read( unsigned char address, unsigned char *buff, unsigned int len)
{int ret;unsigned char addrbuff[1];struct i2c_msg msg[2];struct i2c_client *client = at24cxxdev.client;addrbuff[0] = address;/* msg[0]为发送要读取的首地址 */msg[0].addr = client->addr; /* at24c02 地址 */msg[0].flags = 0; /* 标记为发送数据 */msg[0].buf = addrbuff; /* 读取的首地址 */msg[0].len = 1; /* reg长度*//* msg[1]读取数据 */msg[1].addr = client->addr; /* at24c02 地址 */msg[1].flags = I2C_M_RD; /* 标记为读取数据*/msg[1].buf = buff; /* 读取数据缓冲区 */msg[1].len = len; /* 要读取的数据长度*/ret = i2c_transfer(client->adapter, msg, 2);mdelay(20);if(ret < 0){printk("i2c rd failed=%d len=%d\n",ret, len);}return ret;
}
和设备层相关的read 函数中,使用copy_from_user, 以得到用户层传递进来的参数,具体实现如下:
static ssize_t at24cxx_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{unsigned char tempbuff[size];unsigned char kernel_buf[1];int err, i;unsigned char addr;// get address hereerr = copy_from_user(kernel_buf, buf,1);addr = kernel_buf[0];at24cxx_read( addr, tempbuff, size );size = copy_to_user(buf, tempbuff, size);return size;
}
2.2.2.1 写函数
要实现随机写AT24C02内存的功能,就需要写数据时,先传递给它一个地址,然后在写数据,所以在驱动程序是这样实现该功能的:
int at24cxx_write( unsigned char *buff, unsigned int len)
{int ret;struct i2c_msg msg[1];struct i2c_client *client = at24cxxdev.client;/* msg[0]为发送要写的首地址 */msg[0].addr = client->addr; /* at24c02 地址 */msg[0].flags = 0; /* 标记为发送数据 */msg[0].buf = buff; /* 写的首地址 */msg[0].len = len; /* 数据长度*/ret = i2c_transfer(client->adapter, msg, 1);mdelay(20);if(ret < 0) {printk("i2c write failed=%d len=%d\n",ret, len);}return ret;
}
和driver 层相关的write函数如下,其中buff中的数据包含两部分:
buf[0] : 为地址信息,
buf[1 ~ n ] :user层要写的data数据:
static ssize_t at24cxx_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{unsigned char kernel_buf[size];int err, i;size = copy_from_user(kernel_buf, buf, size);at24cxx_write(kernel_buf, size );return size;
}
3 驱动程序实现
3.1 编写驱动程序
创建一个.c 文件,编写代码。详细驱动代码如下:
/***************************************************************
Copyright 2024-2029. All rights reserved.
文件名 : drv_15_at24cxx.c
作者 : tangmingfei2013@126.com
版本 : V1.0
描述 : at24cxx 驱动程序
其他 : 无
日志 : 初版V1.0 2024/1/30 使用方法:
1) 在.dts文件中定义节点信息at24c02: at24c02@50 {compatible = "atk-dl6y2c,at24c02";reg = <0x50>;};2) 在驱动匹配列表
static const struct of_device_id at24cxx_of_match[] = {{ .compatible = "atk-dl6y2c,at24c02" },{ } // Sentinel
};
***************************************************************/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/i2c.h>#define DEVICE_NAME "at24cxx" // dev/at24cxx/* at24cxxdev设备结构体 */
struct at24cxxstru_dev{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */int major; /* 主设备号 */struct device_node *node; /* at24cxx设备节点 */struct i2c_client *client;
};/* read or write at24cxx structure */static struct at24cxxstru_dev at24cxxdev;/*at24cxx driver
*/
int at24cxx_read( unsigned char address, unsigned char *buff, unsigned int len)
{int ret;unsigned char addrbuff[1];struct i2c_msg msg[2];struct i2c_client *client = at24cxxdev.client;addrbuff[0] = address;/* msg[0]为发送要读取的首地址 */msg[0].addr = client->addr; /* at24c02 地址 */msg[0].flags = 0; /* 标记为发送数据 */msg[0].buf = addrbuff; /* 读取的首地址 */msg[0].len = 1; /* reg长度*//* msg[1]读取数据 */msg[1].addr = client->addr; /* at24c02 地址 */msg[1].flags = I2C_M_RD; /* 标记为读取数据*/msg[1].buf = buff; /* 读取数据缓冲区 */msg[1].len = len; /* 要读取的数据长度*/ret = i2c_transfer(client->adapter, msg, 2);mdelay(20);if(ret < 0){printk("i2c rd failed=%d len=%d\n",ret, len);}return ret;
}int at24cxx_write( unsigned char *buff, unsigned int len)
{int ret;struct i2c_msg msg[1];struct i2c_client *client = at24cxxdev.client;/* msg[0]为发送要写的首地址 */msg[0].addr = client->addr; /* at24c02 地址 */msg[0].flags = 0; /* 标记为发送数据 */msg[0].buf = buff; /* 写的首地址 */msg[0].len = len; /* 数据长度*/ret = i2c_transfer(client->adapter, msg, 1);mdelay(20);if(ret < 0) {printk("i2c write failed=%d len=%d\n",ret, len);}return ret;
}/*linux driver 驱动接口: 实现对应的open/read/write等函数,填入file_operations结构体
*/
static ssize_t at24cxx_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{unsigned char tempbuff[size];unsigned char kernel_buf[1];int err, i;unsigned char addr;// get address hereerr = copy_from_user(kernel_buf, buf,1);addr = kernel_buf[0];at24cxx_read( addr, tempbuff, size );size = copy_to_user(buf, tempbuff, size);return size;
}static ssize_t at24cxx_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{unsigned char kernel_buf[size];int err, i;size = copy_from_user(kernel_buf, buf, size);at24cxx_write(kernel_buf, size );return size;
}static int at24cxx_drv_close(struct inode *node, struct file *file)
{printk(" %s line %d \r\n", __FUNCTION__, __LINE__);return 0;
}static int at24cxx_drv_open(struct inode *inode, struct file *filp)
{return 0;
}/* 定义driver的file_operations结构体
*/
static struct file_operations at24cxx_fops = {.owner = THIS_MODULE,.read = at24cxx_drv_read,.write = at24cxx_drv_write,.open = at24cxx_drv_open,.release = at24cxx_drv_close,
};/* 1. 从platform_device获得GPIO* 2. gpio=>irq* 3. request_irq*/
static int at24cxx_probe( struct i2c_client *client, const struct i2c_device_id *id )
{printk("at24cxx driver and device was matched!\r\n");/* 1. 获得硬件信息 */at24cxxdev.client = client;/* register file_operations */at24cxxdev.major = register_chrdev( 0, DEVICE_NAME, /* device name */&at24cxx_fops); /* create the device class */at24cxxdev.class = class_create(THIS_MODULE, "at24cxx_class");if (IS_ERR(at24cxxdev.class)) {printk("%s line %d\n", __FUNCTION__, __LINE__);unregister_chrdev( at24cxxdev.major, DEVICE_NAME);return PTR_ERR( at24cxxdev.class );}/* 2. device_create */device_create( at24cxxdev.class, NULL, MKDEV( at24cxxdev.major, 0 ), NULL, DEVICE_NAME); // device name return 0;
}static int at24cxx_remove(struct i2c_client *client)
{printk("%s line %d\n", __FUNCTION__, __LINE__);device_destroy( at24cxxdev.class, MKDEV( at24cxxdev.major, 0));class_destroy(at24cxxdev.class);unregister_chrdev(at24cxxdev.major, DEVICE_NAME);return 0;
}static const struct of_device_id atk_dl6y2c_at24cxx[] = {{ .compatible = "atk-dl6y2c,at24c02" },{ },
};static const struct i2c_device_id at24c02_ids[] = {{ "xxxxyyy", (kernel_ulong_t)NULL },{ /* END OF LIST */ }
};/* 1. 定义platform_driver */
static struct i2c_driver at24cxx_driver = {.probe = at24cxx_probe,.remove = at24cxx_remove,.driver = {.name = "atk_at24cxx",.of_match_table = atk_dl6y2c_at24cxx,},.id_table = at24c02_ids,
};/* 2. 在入口函数注册platform_driver
*/
static int __init at24cxx_init(void)
{int err;printk("%s line %d\n",__FUNCTION__, __LINE__);err = i2c_add_driver(&at24cxx_driver); return err;
}/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数* 卸载platform_driver*/
static void __exit at24cxx_exit(void)
{printk("%s line %d\n", __FUNCTION__, __LINE__);i2c_del_driver(&at24cxx_driver);
}/*4. 驱动入口和出口函数
*/
module_init(at24cxx_init);
module_exit(at24cxx_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("tangmingfei2013@126.com");
3.2 编写Makefile
在驱动程序的同级目录下创建Makefile文件,然后编写代码
PWD := $(shell pwd)KERNEL_DIR=/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c
ARCH=arm
CROSS_COMPILE=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-export ARCH CROSS_COMPILEobj-m:= drv_15_at24cxx.oall:$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modulesclean:rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *.symvers
3.3 编译驱动
使用Make命令编译驱动程序,然后将生成的.ko文件copy到NFS共享目录下,然后在板卡中安装该驱动。
使用 insmod 安装该驱动,安装成功后,会出现如下信息:
4 测试
编写一个测试程序,实现AT24CXX连续数据的读写功能
4.1 编写测试代码
创建一个.c文件,编写如下代码:
/***************************************************************
Copyright 2024-2029. All rights reserved.
文件名 : test_15_at24cxx.c
作者 : tangmingfei2013@126.com
版本 : V1.0
描述 : 测试at24cxx驱动程序
其他 : 无
日志 : 初版V1.0 2024/02/15
***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <time.h>#define DEV_FILE "/dev/at24cxx"int main(void)
{int fd, ret;int i = 0;unsigned char databuff[9];unsigned char rdatabuff[8];fd = open(DEV_FILE, O_RDWR);if (fd == -1){printf("can not open file: %s \n", DEV_FILE);return -1;}printf("write to at24cxx: \r\n ");for( i=0; i< sizeof(databuff); i++ ){databuff[i] = i;printf(" %x \t ", databuff[i]);}printf(" \r\n \r\n ");ret = write(fd, databuff, sizeof(databuff)); if( ret < 0 ){printf("%d %s %s i2c device write data failure: %s\n",__LINE__, __FILE__, __FUNCTION__, strerror(errno));close(fd);return -1;}rdatabuff[0] = 0; // 读数据,起始地址ret = read( fd, rdatabuff, sizeof(rdatabuff));if( ret < 0 ){printf("%d %s %s i2c device read data failure: %s\n",__LINE__, __FILE__, __FUNCTION__, strerror(errno));close(fd);return -1;}printf("read from at24cxx: \r\n ");for( i=0; i< sizeof(rdatabuff); i++ ){printf(" %x \t ", rdatabuff[i]);}printf(" \r\n \r\n ");close(fd);return 0;
}
4.2 编写测试程序的Makefile
在测试程序的同级目录下创建一个Makefile文件,实现如下代码:
CFLAGS= -Wall -O2
CC=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
STRIP=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-striptest_15_at24cxx: test_15_at24cxx.o$(CC) $(CFLAGS) -o test_15_at24cxx test_15_at24cxx.o$(STRIP) -s test_15_at24cxxclean:rm -f test_15_at24cxx test_15_at24cxx.o
4.3 编译和运行测试代码
使用make编译测试代码,然后将生成的可执行文件copy到NFS的共享目录下。在板卡中运行该测试程序:
运行该程序后可以看见:
相关文章:

linux platform架构下I2C接口驱动开发
目录 概述 1 认识I2C协议 1.1 初识I2C 1.2 I2C物理层 1.3 I2C协议分析 1.3.1 Start、Stop、ACK 信号 1.3.2 I2C协议的操作流程 1.3.3 操作I2C注意的问题 2 linux platform驱动开发 2.1 更新设备树 2.1.1 添加驱动节点 2.1.2 编译.dts 2.1.3 更新板卡中的.dtb 2.2 …...

基于机器学习的青藏高原高寒沼泽湿地蒸散发插补研究_王秀英_2022
基于机器学习的青藏高原高寒沼泽湿地蒸散发插补研究_王秀英_2022 摘要关键词 1 材料和方法1.1 研究区概况与数据来源1.2 研究方法 2 结果和分析2.1 蒸散发通量观测数据缺省状况2.2 蒸散发与气象因子的相关性分析2.3 不同气象因子输入组合下各模型算法精度对比2.4 随机森林回归模…...

Failed at the node-sass@4.14.1 postinstall script.
问题描述 安装sass # "node-sass": "^4.9.0" npm i node-sass报错如下 npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! node-sass4.14.1 postinstall: node scripts/build.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the node-sass4…...

【鸿蒙系统学习笔记】网络请求
一、介绍 资料来自官网:文档中心 网络管理模块主要提供以下功能: HTTP数据请求:通过HTTP发起一个数据请求。WebSocket连接:使用WebSocket建立服务器与客户端的双向连接。Socket连接:通过Socket进行数据传输。 日常…...

LabVIEW风力机智能叶片控制系统
LabVIEW风力机智能叶片控制系统 介绍了一种风力机智能叶片控制系统的开发。通过利用LabVIEW软件与CDS技术,该系统能够实时监测并调整风力机叶片的角度,优化风能转换效率。此项技术不仅提高了风力发电的稳定性和效率,而且为风力机的智能化管…...

HarmonyOS Stage模型 权限申请
配置声明权限 在module.json5配置文件中声明权限。不论是system_grant还是user_grant类型都需要声明权限,否则应用将无法获得授权。 {"module" : {// ..."requestPermissions":[{"name": "ohos.permission.DISCOVER_BLUETOOTH…...

标题:从预编译到链接:探索C/C++程序的翻译环境全貌
引言 在软件开发的世界里,我们通常会遇到两种不同的环境——翻译环境与运行环境。今天,我们将聚焦于前者,深入剖析C/C程序生命周期中至关重要的“翻译环境”,即从源代码到可执行文件这一过程中涉及的四个关键阶段:预编…...

深入理解单端模拟多路复用器DG406DW-E3 应用于高速数据采集、ATE系统和航空电子设备解决方案
DG406DW-E3是一款16通道单端模拟多路复用器设计用于将16个输入中的一个连接到公共端口由4位二进制地址确定的输出。应用包括高速数据采集、音频信号切换和路由、ATE系统和航空电子设备。高性能低功耗损耗使其成为电池供电和电池供电的理想选择远程仪器应用。采用44V硅栅CMOS工艺…...

Redis篇----第六篇
系列文章目录 文章目录 系列文章目录前言一、Redis 的持久化机制是什么?各自的优缺点?二、Redis 常见性能问题和解决方案:三、redis 过期键的删除策略?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章…...

【LeetCode】509. 斐波那契数(简单)——代码随想录算法训练营Day38
题目链接:509. 斐波那契数 题目描述 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0,F(1) 1 F(n) F(n -…...

[OpenGL教程05 ] glAccum() 函数对累积缓存设置
Accumulation Buffer:累积缓存 一、说明 openGL编程之所以困难,是因为它是三维图表示;简简单单加入一个Z轴,却使得几何遮挡、光线过度、运动随影等搞得尤其复杂。它的核心处理环节是像素缓存,本篇的积累缓存就是其一个…...

BeautifulSoup的使用与入门
1. 介绍 BeautifulSoup是用来从HTML、XML文档中提取数据的一个python库,安装如下: pip install beautifulsoup4 它支持多种解析器,包括python标准库、lxml HTML解析器、lxml XML解析器、html5lib等。结合稳定性和速度,这里推荐使用lxml HT…...

LLM之RAG实战(二十七)| 如何评估RAG系统
有没有想过今天的一些应用程序是如何看起来几乎神奇地智能的?这种魔力很大一部分来自于一种叫做RAG和LLM的东西。把RAG(Retrieval Augmented Generation)想象成人工智能世界里聪明的书呆子,它会挖掘大量信息,准确地找到…...

Linux Docker 关闭开机启动
说说自己为什么需要关闭自启动:Linux中安装Docker后,自启动会占用80和443端口,然后使用自己的SSL认证,导致自己Nginx配置的SSL认证失效,网站通过https打开显示不安全。 Docker是一个容器化平台,它可以让开…...

处理器管理补充——线程
传送门:操作系统——处理器管理http://t.csdnimg.cn/avaDO 1.1 线程的概念 回忆:[未引入线程前] 进程有两个基本属性:拥有资源的独立单位、处理器调度和分配的基本单位。 引入线程以后,线程将作为处理器调度和运行的基本单位&…...

RESTful 风格是指什么
RESTful(Representational State Transfer)是一种基于 HTTP 协议的软件架构风格,用于设计网络应用程序的接口。它的设计理念是利用 HTTP 协议中的方法(如 GET、POST、PUT、DELETE 等)来对资源进行 CRUD,使得…...

Python 二维矩阵加一个变量运算该如何避免 for 循环
Python 二维矩阵加一个变量运算该如何避免 for 循环 引言正文方法1------使用 for 循环方法2------不使用 for 循环引言 今天写代码的时候遇到了一个问题,比如我们需要做一个二维矩阵运算,其中一个矩阵是 2x2 的,另一个是 2x1 的。在这个二维矩阵中,其中各个参数会随着一个…...

Nginx 配置详解
官网:http://www.nginx.org/ 序言 Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的。从2004年发布至今,凭借开源的力量,已经接近成熟与完善。 Nginx功能丰富,可作为HTTP服务器,也可作为反向代理服务…...

python读写文件操作的三大基本步骤
目录 基本步骤 常用函数 open()函数 close()函数 read()函数 readlines()函数 readline()函数 write()函数 writelines()函数 with语句 读写操作的应用: 拷贝文件 with 语句的嵌套 逐行拷贝 基本步骤 1. 打开文件:open(filepath, mode, en…...

《Go 简易速速上手小册》第3章:数据结构(2024 最新版)
文章目录 3.1 数组与切片:Go 语言的动态队伍3.1.1 基础知识讲解3.1.2 重点案例:动态成绩单功能描述实现代码扩展功能 3.1.3 拓展案例 1:数据分析功能描述实现代码扩展功能 3.1.4 拓展案例 2:日志过滤器功能描述实现代码扩展功能 3…...

雷达模拟触摸屏,支持tuio\鼠标\Touch
案例展示: 雷达精度测试 星秒雷达互动软件测试 功能说明: 雷达互动系统支持各种品牌雷达,支持4-256点校准(校准点越大精度越高 ,而市场上基本都是4点校准 ,碰到大面积范围无法保证精准度)&…...

一文了解大数据生态
大数据一词最早指的是传统数据处理应用软件无法处理的过于庞大或过于复杂的数据集。 现在,对“大数据”一词的使用倾向于使用预测分析、用户行为分析或者其他一些从大数据中提取价值的高级数据分析方法,很少用于表示特定规模的数据集。 定义 大数据是…...

Linux篇:指令
一 基本常识: 1. 文件文件内容文件的属性 2. 文件的操作对文件内容的操作对文件属性的操作 3. 文件的类型: d:目录文件 -:普通文件 4. 指令是可执行程序,指令的代码文件在系统的某一个位置存在的。/u…...

Linux eject命令教程:如何控制可移动介质的弹出和收回(附案例详解和注意事项)
Linux eject命令介绍 eject命令在Linux中用于弹出可移动介质,通常是CD-ROM、软盘、磁带或JAZ或ZIP磁盘。您还可以使用此命令来控制一些多盘CD-ROM切换器,一些设备支持的自动弹出功能,以及关闭一些CD-ROM驱动器的光盘托盘。 Linux eject命令…...

【已解决】PPT无法复制内容怎么办?
想要复制PPT文件里的内容,却发现复制不了,怎么办? 这种情况,一般是PPT文件被设置了以“只读方式”打开,“只读方式”下的PPT无法进行编辑更改,也无法进行复制粘贴的操作。 想要解决这个问题,我…...

六大设计原则 (SOLID)
一、设计原则概述 古人云: 有道无术,术可求.有术无道,止于术. 而设计模式通常需要遵循一些设计原则,在设计原则的基础之上衍生出了各种各样的设计模式。设计原则是设计要求,设计模式是设计方案,使用设计模式的代码则是具体的实现。 设计模式中主要有六大设计原则,简称为SOL…...

深度解析Sora的核心技术
Sora要解决的核心问题 Sora面临的挑战是将不同类型的视觉信息,如视频、文本、图像和声音等,整合为一种共同的表征形式。这种转换是实现统一训练过程的关键,旨在将各类数据集中到一个训练框架中,以便于进行大规模的统一学习。简而…...

设计模式面试系列-02
1. Java 中工厂模式有什么优势? 1、工厂模式是最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。 2、利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。 3、将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。 2. …...

MKdocs添加顶部公告栏
效果如图: docs/overrides下新建main.html ,针对main.html文件 树状结构如下: $ tree -a . ├── .github │ ├── .DS_Store │ └── workflows │ └── PublishMySite.yml ├── docs │ └── index.md │ └──overrides │…...

Android全新UI框架之常用ComposeUI组件
在Compose中,每个组件都是一个带有Composable注解的函数,被称为Composable。Compose已经预置了很多基于MD设计规范的Composable组件。 在布局方面,Compose提供了Column、Row、Box三种布局组件(感觉跟flutter差不多),类似于传统视图…...