Linux中SPI

参考资料

https://www.cnblogs.com/aaronLinux/p/6219146.html

1.SPI
在这里插入图片描述
2.SPI传输
2.1传输示例

首先,CS0拉低选中的SPI Flash ,
然后在每个时钟周期,
DO输出对应的电平。
SPI FLASH会在每个时钟的上升沿读取D0的电平。

在这里插入图片描述
2.2SPI模式
根据SCK的电平以及数据在第一个跳变沿还是第二个跳变沿传输,SPI传输总共有四种模式。
在这里插入图片描述
在这里插入图片描述
3.SPI总线设备驱动模型

SPI系统中设涉及两类硬件:
SPI控制器
SPI设备

在这里插入图片描述
spi控制器有驱动程序,提供spi的传输能力。
spi设备也有自己的驱动程序,提供spi设备的访问能力。
4.spi设备驱动框架图

SPI驱动程序由spi_master及spi_device组成
spi_master是在设备树中定义的spi master及master
下边的device信息;当左边drive中的of_device_id和设备树中的compatible参数匹配的时候,会调用driver中的prboe函数,probe函数会生成master,还会生成spi_device。
spi设备左边包括一个spi驱动,当其中的of_device_id和spi_device匹配时,会调用左边driver中的probe函数。

在这里插入图片描述
4.1SPI控制器驱动程序
基于平台总线设备驱动模型实现。在probe函数中除了生成spi_master,还会创建spi_device结构体。
在这里插入图片描述
4.2SPI设备驱动程序

左边是spi_drive,里边有id_table表示能支持哪些SPI设备,有probe函数。
右边是spi_device,用来描述spi设备,可以来自设备树或者c文件

在这里插入图片描述

5.spi设备树处理过程
5.1spi_device

/*** struct spi_device - Master side proxy for an SPI slave device* @dev: Driver model representation of the device.* @master: SPI controller used with the device.* @max_speed_hz: Maximum clock rate to be used with this chip*	(on this board); may be changed by the device's driver.*	The spi_transfer.speed_hz can override this for each transfer.* @chip_select: Chipselect, distinguishing chips handled by @master.* @mode: The spi mode defines how data is clocked out and in.*	This may be changed by the device's driver.*	The "active low" default for chipselect mode can be overridden*	(by specifying SPI_CS_HIGH) as can the "MSB first" default for*	each word in a transfer (by specifying SPI_LSB_FIRST).* @bits_per_word: Data transfers involve one or more words; word sizes*	like eight or 12 bits are common.  In-memory wordsizes are*	powers of two bytes (e.g. 20 bit samples use 32 bits).*	This may be changed by the device's driver, or left at the*	default (0) indicating protocol words are eight bit bytes.*	The spi_transfer.bits_per_word can override this for each transfer.* @irq: Negative, or the number passed to request_irq() to receive*	interrupts from this device.* @controller_state: Controller's runtime state* @controller_data: Board-specific definitions for controller, such as*	FIFO initialization parameters; from board_info.controller_data* @modalias: Name of the driver to use with this device, or an alias*	for that name.  This appears in the sysfs "modalias" attribute*	for driver coldplugging, and in uevents used for hotplugging* @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when*	when not using a GPIO line)** @statistics: statistics for the spi_device** A @spi_device is used to interchange data between an SPI slave* (usually a discrete chip) and CPU memory.** In @dev, the platform_data is used to hold information about this* device that's meaningful to the device's protocol driver, but not* to its controller.  One example might be an identifier for a chip* variant with slightly different functionality; another might be* information about how this particular board wires the chip's pins.*/
struct spi_device {struct device		dev;struct spi_master	*master;u32			max_speed_hz;/* 该设备能支持的spi时钟最大值 */u8			chip_select;/* 是对应的spi_master下边的第几个设备 */u8			bits_per_word;/* 每个基本的spi传输涉及多少位 */u16			mode; /*spi_chpa  spi_cpol组合起来得到spi传输的四种模式 */
#define	SPI_CPHA	0x01			/* clock phase */
#define	SPI_CPOL	0x02			/* clock polarity */
#define	SPI_MODE_0	(0|0)			/* (original MicroWire) */
#define	SPI_MODE_1	(0|SPI_CPHA)
#define	SPI_MODE_2	(SPI_CPOL|0)
#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA)
#define	SPI_CS_HIGH	0x04			/* chipselect active high? */
#define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
#define	SPI_3WIRE	0x10			/* SI/SO signals shared */
#define	SPI_LOOP	0x20			/* loopback mode */
#define	SPI_NO_CS	0x40			/* 1 dev/bus, no chipselect */
#define	SPI_READY	0x80			/* slave pulls low to pause */
#define	SPI_TX_DUAL	0x100			/* transmit with 2 wires */
#define	SPI_TX_QUAD	0x200			/* transmit with 4 wires */
#define	SPI_RX_DUAL	0x400			/* receive with 2 wires */
#define	SPI_RX_QUAD	0x800			/* receive with 4 wires */int			irq;void			*controller_state;void			*controller_data;char			modalias[SPI_NAME_SIZE];int			cs_gpio;	/* chip select gpio *//* the statistics */struct spi_statistics	statistics;/** likely need more hooks for more protocol options affecting how* the controller talks to each chip, like:*  - memory packing (12 bit samples into low bits, others zeroed)*  - priority*  - drop chipselect after each word*  - chipselect delays*  - ...*/
};

5.2设备树中的spi节点

    spi4 {compatible = "spi-gpio";/* 这个属性很关键,因为根据这个属性找到spi_master */pinctrl-names = "default";pinctrl-0 = <&pinctrl_spi4>;pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;status = "okay";gpio-sck = <&gpio5 11 0>;gpio-mosi = <&gpio5 10 0>;cs-gpios = <&gpio5 7 0>;num-chipselects = <1>;#address-cells = <1>;/* 这个SPI Master下的SPI设备,需要多少个cell来表述它的片选引脚 */#size-cells = <0>; /* 这个必须设置为0 *//* gpio_spi是spi_master 下边的device节点 */gpio_spi: gpio_spi@0 {compatible = "fairchild,74hc595";/* 根据它找到spi device驱动 */gpio-controller;#gpio-cells = <2>;reg = <0>;/* 使用哪个片选引脚 */registers-number = <1>;registers-default = /bits/ 8 <0x57>;spi-max-frequency = <10000>;/* 该设备支持的最大spi时钟 */};};

在这里插入图片描述

6.spi device设备驱动程序编写
6.1怎么编写SPI设备驱动程序

1.查看原理图,确定设备在哪个spi控制器下边。
2.在设备树中找到对应的spi控制器,在该节点下创建子节点,表示spi device。

在这里插入图片描述
6.2注册spi driver
spi设备树中的节点,会被转换为一个spi device结构体。
需要编写一个spi driver来支持它。
参考spidev.c来编写设备驱动程序。
基于spi bus模型来编写驱动程序。
在这里插入图片描述
6.3怎么发起传输
6.3.1在函数spi.h中

Linux-4.9.88\include\linux\spi\spi.h

/*** spi_write - SPI synchronous write* @spi: device to which data will be written* @buf: data buffer* @len: data buffer size* Context: can sleep** This function writes the buffer @buf.* Callable only from contexts that can sleep.** Return: zero on success, else a negative error code.*/
static inline int
spi_write(struct spi_device *spi, const void *buf, size_t len)
{struct spi_transfer	t = {.tx_buf		= buf,.len		= len,};return spi_sync_transfer(spi, &t, 1);
}

/*** spi_read - SPI synchronous read* @spi: device from which data will be read* @buf: data buffer* @len: data buffer size* Context: can sleep** This function reads the buffer @buf.* Callable only from contexts that can sleep.** Return: zero on success, else a negative error code.*/
static inline int
spi_read(struct spi_device *spi, void *buf, size_t len)
{struct spi_transfer	t = {.rx_buf		= buf,.len		= len,};return spi_sync_transfer(spi, &t, 1);
}

/* this copies txbuf and rxbuf data; for small transfers only! */
extern int spi_write_then_read(struct spi_device *spi,const void *txbuf, unsigned n_tx,void *rxbuf, unsigned n_rx);

/*** spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read* @spi: device with which data will be exchanged* @cmd: command to be written before data is read back* Context: can sleep** Callable only from contexts that can sleep.** Return: the (unsigned) eight bit number returned by the* device, or else a negative error code.*/
static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
{ssize_t			status;u8			result;status = spi_write_then_read(spi, &cmd, 1, &result, 1);/* return negative errno or unsigned value */return (status < 0) ? status : result;
}

/*** spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read* @spi: device with which data will be exchanged* @cmd: command to be written before data is read back* Context: can sleep** The number is returned in wire-order, which is at least sometimes* big-endian.** Callable only from contexts that can sleep.** Return: the (unsigned) sixteen bit number returned by the* device, or else a negative error code.*/
static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
{ssize_t			status;u16			result;status = spi_write_then_read(spi, &cmd, 1, &result, 2);/* return negative errno or unsigned value */return (status < 0) ? status : result;
}

/*** spi_w8r16be - SPI synchronous 8 bit write followed by 16 bit big-endian read* @spi: device with which data will be exchanged* @cmd: command to be written before data is read back* Context: can sleep** This function is similar to spi_w8r16, with the exception that it will* convert the read 16 bit data word from big-endian to native endianness.** Callable only from contexts that can sleep.** Return: the (unsigned) sixteen bit number returned by the device in cpu* endianness, or else a negative error code.*/
static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd){ssize_t status;__be16 result;status = spi_write_then_read(spi, &cmd, 1, &result, 2);if (status < 0)return status;return be16_to_cpu(result);
}

6.3.2函数解析
在spi子系统中,用spi_transfer结构体描述一个传输,用spi_message管理整个传输。
在这里插入图片描述
spi_transfer结构体:
在这里插入图片描述
spi_message结构体在这里插入图片描述
spi传输示例 在这里插入图片描述
7.编写spi DAC模块驱动程序
7.1基于spi master spi device设备驱动模型来编写设备的驱动程序。

1.查看原理图,看spi device在哪个spi master下边,
然后再设备树中对应的master下边添加设备节点。
2.编写驱动程序,注册一个spi device。
3.编写测试程序。

1.将DAC模块连接到SPI_A上边
在这里插入图片描述
2.在设备树中创建子节点
在这里插入图片描述
3.编写spi_device设备驱动程序


#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>#include <linux/uaccess.h>#define SPI_IOC_WR 123/*-------------------------------------------------------------------------*/static struct spi_device *dac;
static int major;static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{int val;int err;unsigned char tx_buf[2];	unsigned char rx_buf[2];	struct spi_message	msg;struct spi_transfer	xfer[1];int status;memset(&xfer[0], 0, sizeof(xfer));/* copy_from_user */err = copy_from_user(&val, (const void __user *)arg, sizeof(int));printk("spidev_ioctl get val from user: %d\n", val);/* 发起SPI传输:     *//* 1. 把val修改为正确的格式 */val <<= 2;     /* bit0,bit1 = 0b00 */val &= 0xFFC;  /* 只保留10bit */tx_buf[1] = val & 0xff;tx_buf[0] = (val>>8) & 0xff;	/* 2. 发起SPI传输同时写\读 *//* 2.1 构造transfer* 2.2 加入message* 2.3 调用spi_sync*/xfer[0].tx_buf = tx_buf;xfer[0].rx_buf = rx_buf;xfer[0].len = 2;spi_message_init(&msg);spi_message_add_tail(&xfer[0], &msg);status = spi_sync(dac, &msg);/* 3. 修改读到的数据的格式 */val = (rx_buf[0] << 8) | (rx_buf[1]);val >>= 2;printk("spidev_ioctl get val to user: %d\n", val);/* copy_to_user */err = copy_to_user((void __user *)arg, &val, sizeof(int));return 0;
}static const struct file_operations spidev_fops = {.owner =	THIS_MODULE,/* REVISIT switch to aio primitives, so that userspace* gets more complete API coverage.  It'll simplify things* too, except for the locking.*/.unlocked_ioctl = spidev_ioctl,
};static struct class *spidev_class;static const struct of_device_id spidev_dt_ids[] = {{ .compatible = "100ask,dac" },{},
};/*-------------------------------------------------------------------------*/static int spidev_probe(struct spi_device *spi)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* 1. 记录spi_device */dac = spi;/* 2. 注册字符设备 */major = register_chrdev(0, "100ask_dac", &spidev_fops);spidev_class = class_create(THIS_MODULE, "100ask_dac");device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "100ask_dac");	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static int spidev_remove(struct spi_device *spi)
{/* 反注册字符设备 */device_destroy(spidev_class, MKDEV(major, 0));class_destroy(spidev_class);unregister_chrdev(major, "100ask_dac");printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static struct spi_driver spidev_spi_driver = {.driver = {.name =		"100ask,dac",.of_match_table = of_match_ptr(spidev_dt_ids),},.probe =	spidev_probe,.remove =	spidev_remove,
};/*-------------------------------------------------------------------------*/static int __init spidev_init(void)
{int status;printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);status = spi_register_driver(&spidev_spi_driver);if (status < 0) {}return status;
}
module_init(spidev_init);static void __exit spidev_exit(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);MODULE_LICENSE("GPL");

4.测试程序

/* 参考: tools\spi\spidev_fdx.c */#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>#include <linux/types.h>#define SPI_IOC_WR 123/* dac_test /dev/100ask_dac <val> */int main(int argc, char **argv)
{int fd;unsigned int val;int status;unsigned char tx_buf[2];	unsigned char rx_buf[2];	if (argc != 3){printf("Usage: %s /dev/100ask_dac <val>\n", argv[0]);return 0;}fd = open(argv[1], O_RDWR);if (fd < 0) {printf("can not open %s\n", argv[1]);return 1;}val = strtoul(argv[2], NULL, 0);status = ioctl(fd, SPI_IOC_WR, &val);if (status < 0) {printf("SPI_IOC_WR\n");return -1;}/* 打印 */printf("Pre val = %d\n", val);return 0;
}

5.Makefile

KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88all:make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o dac_test dac_test.cclean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.order dac_testobj-m	+= dac_drv.o

8.spi master的实现

1.修改设备树
2.编写驱动分配、设置、注册spi_master

8.1spi传输概述
使用spi传输时,最小的传输单位是spi_transfer
一个设备,可以传输多个spi_transfer, 这些spi_tranfer会放在一个spi_message中。
spi_master中传输函数
在这里插入图片描述
代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/spi/spi.h>static struct spi_master *g_virtual_master;
static struct work_struct g_virtual_ws;static const struct of_device_id spi_virtual_dt_ids[] = {{ .compatible = "100ask,virtual_spi_master", },{ /* sentinel */ }
};static void spi_virtual_work(struct work_struct *work)
{struct spi_message *mesg;while (!list_empty(&g_virtual_master->queue)) {mesg = list_entry(g_virtual_master->queue.next, struct spi_message, queue);list_del_init(&mesg->queue);/* 假装硬件传输已经完成 */mesg->status = 0;if (mesg->complete)mesg->complete(mesg->context);}	
}static int spi_virtual_transfer(struct spi_device *spi, struct spi_message *mesg)
{
#if 0	/* 方法1: 直接实现spi传输 *//* 假装传输完成, 直接唤醒 */mesg->status = 0;mesg->complete(mesg->context);return 0;#else/* 方法2: 使用工作队列启动SPI传输、等待完成 *//* 把消息放入队列 */mesg->actual_length = 0;mesg->status = -EINPROGRESS;list_add_tail(&mesg->queue, &spi->master->queue);/* 启动工作队列 */schedule_work(&g_virtual_ws);/* 直接返回 */return 0;
#endif	
}static int spi_virtual_probe(struct platform_device *pdev)
{struct spi_master *master;int ret;/* 分配/设置/注册spi_master */g_virtual_master = master = spi_alloc_master(&pdev->dev, 0);if (master == NULL) {dev_err(&pdev->dev, "spi_alloc_master error.\n");return -ENOMEM;}master->transfer = spi_virtual_transfer;INIT_WORK(&g_virtual_ws, spi_virtual_work);master->dev.of_node = pdev->dev.of_node;ret = spi_register_master(master);if (ret < 0) {printk(KERN_ERR "spi_register_master error.\n");spi_master_put(master);return ret;}return 0;}static int spi_virtual_remove(struct platform_device *pdev)
{/* 反注册spi_master */spi_unregister_master(g_virtual_master);return 0;
}static struct platform_driver spi_virtual_driver = {.probe = spi_virtual_probe,.remove = spi_virtual_remove,.driver = {.name = "virtual_spi",.of_match_table = spi_virtual_dt_ids,},
};static int virtual_master_init(void)
{return platform_driver_register(&spi_virtual_driver);
}static void virtual_master_exit(void)
{platform_driver_unregister(&spi_virtual_driver);
}module_init(virtual_master_init);
module_exit(virtual_master_exit);MODULE_DESCRIPTION("Virtual SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("www.100ask.net");

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
之后,再在master函数中实现这个传输函数。

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

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

相关文章

基于SSM+小程序的计算机实验室排课与查询管理系统(实验室2)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 1、管理员功能有个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;实验室信息管理&#xff0c;实验室预约管理&#xff0c;取消预约管理&#xff0c;实验课程管理&#xff0…

Netty核心源码与优化

1.Netty的优化 1.1 使用EventLoop的任务调度 直接使用 channel.writeAndFlush(data) 可能会导致线程切换&#xff0c;这是因为如果当前线程并不是该 Channel 所绑定的 EventLoop 线程&#xff0c;那么 writeAndFlush() 操作会将任务重新提交给关联的 EventLoop 线程执行&#…

selinux介绍和Linux中的防火墙

selinux 1、selinux的说明 2、selinux的工作原理 3、selinux的启动、关闭与查看 防火墙 1、什么是防火墙 2、iptables &#xff08;1&#xff09;iptables介绍 参数说明 3、firewalld firewalld-cmd的参数说明

JavaScript。—关于语法基础的理解—

一、程序控制语句 JavaScript 提供了 if 、if else 和 switch 3种条件语句&#xff0c;条件语句也可以嵌套。 &#xff08;一&#xff09;、条件语句 1、单向判断 &#xff1a; if... &#xff08;1&#xff09;概述 < if >元素用于在判断该语句是否满足特定条…

yarn 下载安装、下载依赖、通过 vscode 运行服务(Windows11)

目录 yarn工具前置要求&#xff1a;安装node.js并配置好国内镜像源下载安装下载依赖特别的&#xff1a; 启动服务 yarn 工具 系统&#xff1a;Windows 11 前置要求&#xff1a;安装node.js并配置好国内镜像源 参考&#xff1a;本人写的《node.js下载、安装、设置国内镜像源…

SQL,力扣题目1596,每位顾客最经常订购的商品【窗口函数】

一、力扣链接 LeetCode_1596 二、题目描述 表&#xff1a;Customers ------------------------ | Column Name | Type | ------------------------ | customer_id | int | | name | varchar | ------------------------ customer_id 是该表具有唯一值的…

2025上海市公务员考试报名流程详细教程

2025年上海市公务员考试报名马上就要开始了&#xff0c;有想要参加上海公务员考试的姐妹们&#xff0c;可以提前了解一下考试报名流程&#xff0c;和报名照制作尺寸要求 报名时间&#xff1a;11月2日0:00至11月8日12:00 南核时间&#xff1a;11月2日0:00至11月8日14:00 缴费…

【云原生】Docker搭建开源翻译组件Deepl使用详解

目录 一、前言 二、微服务项目使用翻译组件的场景 2.1 多语言用户界面 2.2 业务逻辑中的翻译需求 2.3 满足实时通信的要求 2.4 内容管理系统 2.5 个性化推荐系统 2.6 日志和监控 三、开源类翻译组件解决方案 3.1 国内翻译组件方案汇总 3.1.1 百度翻译 3.1.2 腾讯翻…

数据库原理上机实验4(数据更新实验){insert;update;delete;is null的使用}

本次实验用到的一些基本关键字 1、insert into 插入数据 INSERT INTO 语句可以有两种编写形式。 第一种形式无需指定要插入数据的列名&#xff0c;只需提供被插入的值即可&#xff1a; INSERT INTO table_name VALUES (value1,value2,value3,...); 第二种形式需要指定列名…

第03章 MySQL的简单使用命令

一、MySQL的登录 1.1 服务的启动与停止 MySQL安装完毕之后&#xff0c;需要启动服务器进程&#xff0c;不然客户端无法连接数据库。 在前面的配置过程中&#xff0c;已经将MySQL安装为Windows服务&#xff0c;并且勾选当Windows启动、停止时&#xff0c;MySQL也 自动启动、停止…

ubuntu 24 (wayland)如何实现无显示器远程桌面

ubuntu 24默认采用的是wayland而非x11&#xff0c;查过文档vnc对wayland的支持不是很好&#xff0c;折腾了好久&#xff0c;弄了一个如下的方案供参考&#xff1a; 硬件条件 需要一个显卡欺骗器或者可以接HDMI口作为视频信号源输出的设备。 将ubuntu的主机的HDMI输出接到该硬…

Python Matplotlib 如何处理大数据集的绘制,提高绘图效率

Python Matplotlib 如何处理大数据集的绘制&#xff0c;提高绘图效率 在数据分析和可视化的过程中&#xff0c;处理大数据集常常是我们面临的挑战。绘制大数据集不仅需要时间和计算资源&#xff0c;还可能导致图形显示不流畅&#xff0c;甚至崩溃。Matplotlib 是 Python 中一个…

【Linux】网络编程:初识协议,序列化与反序列化——基于json串实现,网络通信计算器中简单协议的实现、手写序列化与反序列化

目录 一、什么是协议&#xff1f; 二、为什么需要有协议呢&#xff1f; 三、协议的应用 四、序列化与反序列化的引入 什么是序列化和反序列化&#xff1f; 为什么需要序列化和反序列化&#xff1f; 五、序列化推荐格式之一&#xff1a;JSON介绍 六、网络版计算器编程逻…

ZYNQ7045之YOLO部署——FPGA-ZYNQ Soc实战笔记1

一、简介 1、目标检测概念 2、目标检测应用 3、目标检测发展历程 二、YOLO V1 1、输入 必须为448x448分辨率 2、网络结构 卷积 池化 卷积 池化 3、输出 最终7x7x30表示&#xff0c;7x7个各自&#xff0c;每个格子有30个数据&#xff0c;30个数据包含两个部分 1&#xff1a;…

服务器数据恢复—SAN环境中LUN映射错误导致文件系统一致性出错的数据恢复案例

服务器数据恢复环境&#xff1a; SAN光纤网络环境&#xff0c;存储由一组6块硬盘组建的RAID6阵列构成&#xff0c;划分为若干LUN&#xff0c;MAP到跑不同业务的SUN SOLARIS操作系统服务器上。 服务器故障&分析&#xff1a; 因为业务需要&#xff0c;用户在该光纤存储环境中…

聪明的你能从千门八将108局学到什么,对你的未来人生有哪些深远的影响?

千门八将108局&#xff1a;智慧的启迪与人生指引 在古老智慧的宝库中&#xff0c;千门八将108局犹如璀璨星辰&#xff0c;闪耀着神秘而深邃的光芒。那些认真钻研过这些局的人&#xff0c;仿佛经历了一场穿越时空的智慧洗礼&#xff0c;从中收获了无价的人生财富。 一、从千门八…

Launcher3 去掉桌面搜索索框

文章目录 需求实现需求说明 参考资料修改文件实现思路首页显示的搜索框去除应用列表中的搜索框去除解决方案代码跟踪代码扩展 需求 Launcher3 去掉搜桌面索框 实现需求说明 每个平台平台源码有区别&#xff0c;比如&#xff1a;MTK、高通、展讯、RK、谷歌…单个平台下 不同A…

qt QDoubleSpinBox详解

1、概述 QDoubleSpinBox是Qt框架中的一个控件&#xff0c;专门用于浮点数&#xff08;即小数&#xff09;的输入和调节。它提供了一个用户界面元素&#xff0c;允许用户在预设的范围内通过拖动滑块、点击箭头或使用键盘来递增或递减浮点数值。QDoubleSpinBox通常用于需要精确数…

NVR小程序接入平台/设备EasyNVR多个NVR同时管理视频监控新选择

在数字化转型的浪潮中&#xff0c;视频监控作为安防领域的核心组成部分&#xff0c;正经历着前所未有的技术革新。随着技术的不断进步和应用场景的不断拓展&#xff0c;视频监控系统的兼容性、稳定性以及安全性成为了用户关注的焦点。NVR小程序接入平台/设备EasyNVR&#xff0c…

qt QAction详解

1、概述 QAction是Qt框架中的一个抽象类&#xff0c;用于表示用户界面中的一个动作&#xff08;action&#xff09;。这些动作可以绑定到菜单项、工具栏按钮或快捷键上&#xff0c;提供了一种灵活的方式来处理用户交互。QAction不仅包含了动作的名称、图标、提示信息等属性&am…