迅为RK3568开发板驱动指南Linux中通用SPI设备驱动
在前面的章节中我们从0开始编写了一个mcp2515的驱动程序,而跟I2C设备类似,在Linux内核中也有着通用SPI设备驱动,在本章节将会讲解通用SPI设备驱动的使用,并讲解如何在应用程序中通过ioctl对SPI进行配置和使用。
硬件:迅为RK3568开发板
193.1 内核和设备树配置
通用SPI设备驱动在迅为提供的Linux内核中默认已经勾选了,具体路径如下所示:
> Device Drivers
> SPI support
除了内核支持之外,还需要修改设备树,由于之前已经使能了SPI0,所以这直接修改之前编写的mcp2515设备树节点,具体设备树为“kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi”,修改完成的mcp2515节点如下所示:rockchip,spidev
&spi0 {
status = "okay";
pinctrl-0 = <&spi0m1_cs0 &spi0m1_pins>;
pinctrl-1 = <&spi0m1_cs0 &spi0m1_pins_hs>;
mcp2515:mcp2515@0 {
compatible = "rockchip,spidev";
reg = <0>;
spi-max-frequency = <10000000>;
status = "okay";
};
};
保存退出之后,重新编译内核源码,最后将编译得到的boot.img烧写到开发板上。
而为了方便起见,迅为已经将修改完成的设备树以及编译完成的内核镜像放到了“iTOP-3568开发板\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\119_mcp2515_07\01_编译好的内核镜像”路径下。
开发板启动之后,如果存在/dev/spidev0.0设备节点,证明设备树及内核配置正确,如下图所示:
/dev/spidev0.0 表示一个 SPI 总线上的具体设备。0.0 是一个标识符,用于区分系统中的不同 SPI 控制器和设备。这个标识符由两部分组成:
第一个数字 0:表示SPI总线的编号。一个系统中可能有多个SPI控制器,每个控制器对应一个总线编号,从0开始。
第二个数字0:表示连接在该SPI总线上的具体设备编号。一个SPI总线上可以连接多个设备,每个设备通过片选信号(Chip Select, CS)进行区分,设备编号从0开始。
在下个小节中,将会讲解内核源码中携带的spidev_test SPI测试程序进行讲解。
193.2 spidev_test工具使用
spidev_test是一个用于测试和调试SPI设备的命令行工具,通常在Linux系统上使用,它允许用户直接通过SPI总线与设备进行通信,可以发送数据并接收来自设备的响应。
spidev_test源码位于Linux源码的kernel/tools/spi目录下,如下图所示:
然后使用以下命令对该工具进行交叉编译
make CC=/home/topeet/Linux/linux_sdk/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc LD=/home/topeet/Linux/linux_sdk/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ld
编译好的文件如下图所示。
然后将编译好的可执行文件spidev_fdx和spidev_test拷贝到开发板上使用即可。接下来介绍一下工具的使用方法
1.spidev_test工具的使用:
基本介绍:spidev_test是一个用于测试和验证Linux中SPI设备驱动程序的用户空间工具。它使用spidev接口与SPI设备通信。这个工具主要用来检查SPI设备是否工作正常,以及对SPI设备进行基本的读写操作。
主要选项和参数
-D /dev/spidevX.Y:指定要测试的 SPI 设备节点。
-s <speed>:设置 SPI 时钟频率(以 Hz 为单位),例如 -s 1000000 表示 1 MHz。
-d <delay>:设置数据传输之间的延迟时间(以微秒为单位)。
-b <bits per word>:设置每个数据字的位数,通常是 8 或 16。
-H:以十六进制模式显示传输的数据。
(3)示例操作
读取设备信息:
spidev_test -D /dev/spidevX.Y -s 1000000
这会使用 1 MHz 的时钟频率从 SPI 设备读取数据,默认情况下以十六进制显示。
写入和读取数据:
spidev_test -D /dev/spidevX.Y -s 1000000 -b 8 -d 1000 -H -p 'hello'
这条命令会向 SPI 设备写入字符串 'hello',并以十六进制模式显示设备的响应数据。-b 8 指定每个字的位数为 8,-d 1000 设置 1000 微秒的延迟。
连续传输:
spidev_test -D /dev/spidevX.Y -s 1000000 -b 8 -p 'abcdefgh'
这个示例将连续发送字节 'abcdefgh' 到 SPI 设备。
2.spidev_fdx工具的使用
(1)基本介绍:spidev_fdx 是一个用于全双工 SPI 通信测试的命令行工具,主要用于在 Linux 系统上与 SPI 设备进行双向数据传输和测试。
(2)主要选项和参数
-D /dev/spidevX.Y:指定要测试的 SPI 设备节点。
-s <speed>:设置 SPI 时钟频率(以 Hz 为单位),例如 -s 1000000 表示 1 MHz。
-w <write_data>:指定要写入到 SPI 设备的数据,可以是十六进制或 ASCII 格式的字符串。
-r <read_size>:指定从 SPI 设备读取的数据大小(以字节为单位)。
-b <bits per word>:设置每个数据字的位数,通常是 8 或 16。
-d <delay>:设置数据传输之间的延迟时间(以微秒为单位)。
(3)示例操作
以下是几个使用 spidev_fdx 工具的示例操作:
发送和接收数据:
spidev_fdx -D /dev/spidevX.Y -s 1000000 -w 'hello' -r 5
这会向 SPI 设备写入字符串 'hello',并从设备读取 5 个字节的响应数据。
设置时钟频率和延迟:
spidev_fdx -D /dev/spidevX.Y -s 500000 -d 200 -w 'abcdef' -r 10
这个示例将 SPI 时钟频率设置为 500 kHz,数据写入延迟为 200 微秒,并向设备写入字符串 'abcdef',然后读取 10 个字节的响应数据。
193.3 应用程序中如何使用SPI
在第一个小节中使能了内核中的通用SPI,而在第二小节讲解了spidev_test工具的使用,在本小节将根据spidev_test工具的源码,编写mcp2515通用SPI驱动程序的应用程序。
在应用程序中可以通过ioctl来获取和配置SPI的相关属性,并实现SPI数据的发送和接收,SPI的ioctl宏定义在“/usr/include/linux/spi/spidev.h”,部分ioctl cmd如下所示:
/* 读取 / 写入 SPI 模式(SPI_MODE_0..SPI_MODE_3)(限制为 8 位) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) // 读取 SPI 模式
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) // 写入 SPI 模式
/* 读取 / 写入 SPI 位顺序 */
#define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8) // 读取 SPI 低位优先
#define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8) // 写入 SPI 低位优先
/* 读取 / 写入 SPI 设备字长(1..N) */
#define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8) // 读取 SPI 每字位数
#define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8) // 写入 SPI 每字位数
/* 读取 / 写入 SPI 设备默认最大速度(Hz) */
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) // 读取 SPI 最大速度(Hz)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) // 写入 SPI 最大速度(Hz)
/* 读取 / 写入 SPI 模式字段 */
#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32) // 读取 SPI 模式(32 位)
#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32) // 写入 SPI 模式(32 位)
可以通过上述ioctl cmd来对SPI设备进行初始化,编写完成的初始化函数如下所示:
int fd; // SPI设备文件描述符
int mode = SPI_MODE_0; // SPI模式
int bits = 8; // 每字比特数
int speed = 10000000; // 最大SPI总线速度(Hz)
int spi_init(void){
int ret;
// 打开SPI设备文件
fd = open("/dev/spidev0.0", O_RDWR);
if(fd < 0){
printf("打开 /dev/spidev0.0 错误\n");
return -1;
}
/*
* 设置SPI模式
*/
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
printf("无法设置SPI模式\n");
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
printf("无法获取SPI模式\n");
/*
* 设置每字比特数
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("无法设置每字比特数\n");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
printf("无法获取每字比特数\n");
/*
* 设置最大传输速度
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("无法设置最大传输速度\n");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("无法获取最大传输速度\n");
printf("SPI模式: 0x%x\n", mode);
printf("每字比特数: %d\n", bits);
printf("最大速度: %d Hz (%d KHz)\n", speed, speed / 1000);
return 0;
}
通过该函数可以设置SPI的模式、比特数以及最大传输速度,然后根据spidev_test工具源码的传输函数来编写传输函数,具体函数内容如下所示:
/*
* 执行SPI数据传输.
* 参数:
* fd - SPI设备文件描述符
* tx - 发送缓冲区
* rx - 接收缓冲区
* len - 数据长度
* 返回0表示成功,-1表示失败.
*/
int transfer(int fd, char *tx, char *rx, int len)
{
int ret;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1){
printf("无法发送SPI消息\n");
return -1;
}
return 0;
}
在前面的章节中一步步的编写了mcp2515的复位函数、配置函数、读函数和写函数,而现在可以直接在应用程序通过刚刚编写的传输函数向SPI设备发送一系列的SPI指令,一个编写完成的mcp2515的应用程序代码如下所示:
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define RESET 0xc0 // 复位命令
#define CANSTAT 0x0e // CAN状态寄存器地址
#define READ 0x03 // 读命令
#define CANCTRL 0x0f // CAN控制寄存器地址
#define WRITE 0x02 // 写命令
int fd; // SPI设备文件描述符
int mode = SPI_MODE_0; // SPI模式
int bits = 8; // 每字比特数
int speed = 10000000; // 最大SPI总线速度(Hz)
int delay; // 延迟时间(微秒)
/*
* 初始化SPI通信.
* 返回0表示成功,-1表示失败.
*/
int spi_init(void){
int ret;
// 打开SPI设备文件
fd = open("/dev/spidev0.0", O_RDWR);
if(fd < 0){
printf("打开 /dev/spidev0.0 错误\n");
return -1;
}
/*
* 设置SPI模式
*/
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
printf("无法设置SPI模式\n");
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
printf("无法获取SPI模式\n");
/*
* 设置每字比特数
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("无法设置每字比特数\n");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
printf("无法获取每字比特数\n");
/*
* 设置最大传输速度
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("无法设置最大传输速度\n");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("无法获取最大传输速度\n");
printf("SPI模式: 0x%x\n", mode);
printf("每字比特数: %d\n", bits);
printf("最大速度: %d Hz (%d KHz)\n", speed, speed / 1000);
return 0;
}
/*
* 执行SPI数据传输.
* 参数:
* fd - SPI设备文件描述符
* tx - 发送缓冲区
* rx - 接收缓冲区
* len - 数据长度
* 返回0表示成功,-1表示失败.
*/
int transfer(int fd, char *tx, char *rx, int len)
{
int ret;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1){
printf("无法发送SPI消息\n");
return -1;
}
return 0;
}
int main(int argc, char *argv[]){
char reset_cmd[1] = {RESET}; // 复位命令数组
char rd_canstat[2] = {READ, CANSTAT}; // 读CAN状态寄存器命令数组
char canstat[4] = {0}; // 存储CAN状态的缓冲区
char wr_canctrl[] = {WRITE, CANCTRL, 0x00}; // 写CAN控制寄存器命令数组
// 初始化SPI通信
spi_init();
// 执行SPI数据传输
// 1. 发送复位命令
transfer(fd, reset_cmd, NULL, sizeof(reset_cmd));
// 2. 读取CAN状态
transfer(fd, rd_canstat, canstat, sizeof(canstat));
printf("CAN状态为 %x\n", canstat[2]);
// 清空canstat缓冲区
memset(canstat, 0, sizeof(canstat));
// 3. 写入CAN控制
transfer(fd, wr_canctrl, NULL, sizeof(wr_canctrl));
// 4. 再次读取CAN状态
transfer(fd, rd_canstat, canstat, sizeof(canstat));
printf("CAN状态为 %x\n", canstat[3]);
return 0;
}
193.4 运行测试
193.4.1 编译应用程序
上一小节编写好的app.c应用程序源码已经放在了“iTOP-3568开发板\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\119_mcp2515_07\02_app”目录下。
首先进行应用程序的编译,因为测试APP是要在开发板上运行的,所以需要aarch64-linux-gnu-gcc来编译,输入以下命令,编译完成以后会生成一个app的可执行程序,如下图所示:
aarch64-linux-gnu-gcc app.c -o app
然后将编译完成的可执行程序拷贝到开发板上.
193.4.2 运行测试
首先将193.1小节编译好的内核镜像烧写到开发板上,然后将可执行程序app文件拷贝到开发板上,拷贝完成如下所示:
然后运行可执行程序app,如下图所示。
在应用程序中,发送完复位指令之后,第一条打印can状态寄存器的值为80,表示mcp2515已经处在了配置模式。第二条打印can状态寄存器的值为00,表示mcp2515已经处于正常模式,这就说明上一小节编写的应用程序正常运行。
至此,关于通用SPI驱动和在应用程序中使用SPI实验就完成了。
相关文章:
迅为RK3568开发板驱动指南Linux中通用SPI设备驱动
在前面的章节中我们从0开始编写了一个mcp2515的驱动程序,而跟I2C设备类似,在Linux内核中也有着通用SPI设备驱动,在本章节将会讲解通用SPI设备驱动的使用,并讲解如何在应用程序中通过ioctl对SPI进行配置和使用。 硬件:迅…...
DDD架构实战第五讲总结:将领域模型转化为代码
云架构师系列课程之DDD架构实战第五讲总结:将领域模型转化为代码 一、引言 在前几讲中,我们讨论了领域模型的重要性及其在业务分析中的渐进获得方法。本讲将聚焦于如何将领域模型转化为代码,使得开发人员能够更轻松地实现用户的领域模型。 二、从模型到代码:领域驱动设计…...
C++----STL(list)
介绍 list的数据结果是一个带头双向链表。 使用 有了前面string、vector的基础,后续关于list使用的讲解主要提及与string和vector的不同之处。 使用文档:cplusplus.com/reference/list/list/?kwlist 迭代器问题 insert以后迭代器不失效 #include…...
软件测试 —— 性能测试(jmeter)
软件测试 —— 性能测试(jmeter) 什么是jmeter安装jmeterjmeter常用组件线程组取样器结果树 我们之前学习了接口测试工具Postman,我们今天要学习的是性能测试工具——jmeter 什么是jmeter Apache JMeter 是一个开源的性能测试工具ÿ…...
Zemax 非序列模式下的颜色检测器和颜色混合
在 Zemax 的非序列模式中,探测器用于捕获系统中射线的信息。可以使用各种类型的探测器来捕获光学系统性能的不同方面,例如矩形探测器,它存储撞击它的 NSC 源射线的能量数据。 另一种经常使用的探测器类型是 Detector Color,它是一…...
DBO优化最近邻分类预测matlab
蜣螂优化算法(Dung Beetle Optimizer,简称 DBO)作为一种新兴的群智能优化算法,于 2022 年末被提出,其灵感主要来源于蜣螂的滚球、跳舞、觅食、偷窃以及繁殖等行为。 本次使用的数据为 Excel 格式的分类数据集。该数据…...
【第二天】零基础入门刷题Python-算法篇-数据结构与算法的介绍-五种常见的排序算法(持续更新)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、Python数据结构与算法的详细介绍1.Python中的常用的排序算法1.排序算法的介绍2.五种详细的排序算法代码 总结 前言 提示:这里可以添加本文要记…...
合并两个有序数组(Leetcode)
解题思路: 三个指针: $p1: 指向 nums1 中的最后一个非零元素。$p2: 指向 nums2 的最后一个元素。$p: 指向 nums1 的最后一位,用于存储合并后的元素。 从后往前填充: 比较 nums1[$p1] 和 nums2[$p2],较大的放入 nums1[…...
特殊类设计
[本节目标] 掌握常见特殊类的设计方式 1.请设计一个类,不能被拷贝 拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 C98 将拷贝构…...
2025.1.20——一、[RCTF2015]EasySQL1 二次注入|报错注入|代码审计
题目来源:buuctf [RCTF2015]EasySQL1 目录 一、打开靶机,整理信息 二、解题思路 step 1:初步思路为二次注入,在页面进行操作 step 2:尝试二次注入 step 3:已知双引号类型的字符型注入,构造…...
【esp32-uniapp】uniapp小程序篇02——引入组件库
一、引入组件库(可自行选择其他组件库) 接下来介绍colorUI、uview plus的安装,其他的安装可自行查找教程 1.colorUI weilanwl/coloruicss: 鲜亮的高饱和色彩,专注视觉的小程序组件库 下载之后解压,将\coloruicss-ma…...
基于单片机的智能小区门禁系统设计(论文+源码)
1总体架构 智能小区门禁系统以STM32单片机和WiFi技术为核心,STM32单片机作为主控单元,通过WiFi模块实现与手机APP的连接,构建整个门禁系统。系统硬件包括RFID模块、指纹识别模块、显示屏、按键以及继电器。通过RFID绑定IC卡、APP面部识别、指…...
tkinter绘制组件(44)——浮出ui控件
tkinter绘制组件(44)——浮出ui控件 引言布局函数结构ui框架对齐方向绑定已有控件出现和隐藏逻辑出现和隐藏动画完整代码函数 效果测试代码最终效果 github项目pip下载 引言 TinUI的浮出ui控件(flyout)其实是一个之间创建在UI框架…...
CDSN 2024博客之星总评选-主题文章创作,我的AI之路-起手篇
CDSN 2024博客之星总评选-主题文章创作,我的AI之路-起手篇 一. 回顾自己的机器学习之路二. 2024年的大模型学习三. 对自己的期望 一. 回顾自己的机器学习之路 自2019年起,我开始涉足机器学习领域,最初接触的是通过模型实现自动化的任务&…...
LLM基础知识
代替你的不是ai,而是会使用ai的人。而在这之上还有会打造ai的人。 1、大语言模型的大体现在哪里 LLM(Large Language Model 大语言模型)的大不仅仅是指训练数据巨大,更指参数数量巨大。 参数即模型内部的变量,…...
Linux 网络:交换芯片 EDSA 以太网帧简介
文章目录 1. 前言2. EDSA 协议以太网帧的发送和接收2.1 什么是 EDSA ?2.2 EDSA 以太网帧的发送2.3 EDSA 以太网帧的接收 3. 验证 1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。 2. EDS…...
【Git版本控制器--3】Git的远程操作
目录 理解分布式版本控制系统 创建远程仓库 仓库被创建后的配置信息 克隆远程仓库 https克隆仓库 ssh克隆仓库 向远程仓库推送 拉取远程仓库 忽略特殊文件 为什么要忽略特殊文件? 如何配置忽略特殊文件? 配置命令别名 标签管理 理…...
深入理解GPT底层原理--从n-gram到RNN到LSTM/GRU到Transformer/GPT的进化
从简单的RNN到复杂的LSTM/GRU,再到引入注意力机制,研究者们一直在努力解决序列建模的核心问题。每一步的进展都为下一步的突破奠定了基础,最终孕育出了革命性的Transformer架构和GPT大模型。 1. 从n-gram到循环神经网络(RNN)的诞生 1.1 N-gram 模型 在深度学习兴起之前,处理…...
【2024年华为OD机试】 (E卷,200分) - 最优资源分配芯片资源占用(JavaScriptJava PythonC/C++)
一、问题描述 题目解析 题目描述 某块业务芯片的最小容量单位为 1.25G,总容量为 M * 1.25G。芯片资源编号为 1, 2, …, M。该芯片支持 3 种不同的配置,分别为 A、B、C: 配置 A:占用容量为 1.25G(1 个单位ÿ…...
Spring Boot(6)解决ruoyi框架连续快速发送post请求时,弹出“数据正在处理,请勿重复提交”提醒的问题
一、整个前言 在基于 Ruoyi 框架进行系统开发的过程中,我们常常会遇到各种有趣且具有挑战性的问题。今天,我们就来深入探讨一个在实际开发中较为常见的问题:当连续快速发送 Post 请求时,前端会弹出 “数据正在处理,请…...
【开源免费】基于Vue和SpringBoot的常规应急物资管理系统(附论文)
本文项目编号 T 159 ,文末自助获取源码 \color{red}{T159,文末自助获取源码} T159,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
差分进化算法 (Differential Evolution) 算法详解及案例分析
差分进化算法 (Differential Evolution) 算法详解及案例分析 目录 差分进化算法 (Differential Evolution) 算法详解及案例分析1. 引言2. 差分进化算法 (DE) 算法原理2.1 基本概念2.2 算法步骤3. 差分进化算法的优势与局限性3.1 优势3.2 局限性4. 案例分析4.1 案例1: 单目标优化…...
优选算法——哈希表
目录 1. 哈希表简介 2. 两数之和 3. 判定是否为字符重排 4. 存在重复元素 5. 字母异位词分组 1. 哈希表简介 2. 两数之和 题目链接:1. 两数之和 - 力扣(LeetCode) 题目展示: 题目分析: 大家来看上面的图&…...
【前端SEO】使用Vue.js + Nuxt 框架构建服务端渲染 (SSR) 应用满足SEO需求
Nuxt.js 是一个基于 Vue.js 的通用应用框架,它简化了使用 Vue 构建服务端渲染 (SSR) 应用的流程。除了 SSR 之外,Nuxt.js 还支持静态站点生成(Static Site Generation, SSG),渐进式网络应用(Progressive We…...
AI学习指南Ollama篇-Ollama简介
一、定义 大语言模型(LLM)是一种基于深度学习的自然语言处理模型,能够生成文本、回答问题、翻译语言、撰写代码等。这些模型通过海量的文本数据进行训练,学习语言的模式和结构,从而能够生成自然流畅的文本内容。随着技术的不断进步,大语言模型在各个领域都展现出了巨大的…...
Python从0到100(八十五):神经网络与迁移学习在猫狗分类中的应用
在人工智能的浩瀚宇宙中,深度学习犹如一颗璀璨的星辰,引领着机器学习和计算机视觉领域的前沿探索。而神经网络,作为深度学习的核心架构,更是以其强大的数据建模能力,成为解决复杂问题的重要工具。今天,我们…...
《最优化理论基础》8课时层次化教案
《最优化理论基础》8课时层次化教案 课程总目标 掌握最优化核心理论(最优性条件、凸分析、对偶理论);能独立实现经典优化算法(梯度法、牛顿法、约束优化建模);理解优化理论与机器学习模型的关联ÿ…...
从源码深入理解One-API框架:适配器模式实现LLM接口对接
1. 概述 one-api 是一个开源的 API 框架,基于go语言开发,旨在提供统一的接口调用封装,支持多种 AI 服务平台的集成。通过 Gin 和 GORM 等框架,框架简化了多种 API 服务的调用流程。通过适配器模式实现了与多种 大模型API 服务的集…...
2025年国产化推进.NET跨平台应用框架推荐
2025年国产化推进.NET跨平台应用框架推荐 1. .NET MAUI NET MAUI是一个开源、免费(MIT License)的跨平台框架(支持Android、iOS、macOS 和 Windows多平台运行),是 Xamarin.Forms 的进化版,从移动场景扩展到…...
Tensor 基本操作4 理解 indexing,加减乘除和 broadcasting 运算 | PyTorch 深度学习实战
前一篇文章,Tensor 基本操作3 理解 shape, stride, storage, view,is_contiguous 和 reshape 操作 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started Tensor 基本使用 索引 indexing示例代码 加减…...
图扑 2024 全年精彩回顾 | 稳步向前
2024 年即将过去,回顾这一年,图扑软件在多个领域取得了显著成就,我们斩获多项行业奖项,稳步提升了市场地位,并在产品创新上推出了一系列新功能,提升了用户体验。与此同时,通过与合作伙伴紧密协作…...
[Python学习日记-79] socket 开发中的粘包现象(解决模拟 SSH 远程执行命令代码中的粘包问题)
[Python学习日记-79] socket 开发中的粘包现象(解决模拟 SSH 远程执行命令代码中的粘包问题) 简介 粘包问题底层原理分析 粘包问题的解决 简介 在Python学习日记-78我们留下了两个问题,一个是服务器端 send() 中使用加号的问题,…...
【数据结构】深入解析:构建父子节点树形数据结构并返回前端
树形数据结构列表 一、前言二、测试数据生成三、树形代码3.1、获取根节点3.2、遍历根节点,递归获取所有子节点3.3、排序3.4、完整代码 一、前言 返回前端VO对象中,有列情况列表展示需要带树形结构,例如基于RBAC权限模型中的菜单返回…...
【统计的思想】假设检验(二)
假设检验是根据人为设定的显著水平,对被测对象的总体质量特性进行统计推断的方法。 如果我们通过假设检验否定了零假设,只是说明在设定的显著水平下,零假设成立的概率比较小,并不是说零假设就肯定不成立。如果零假设事实上是成立…...
IT服务规划设计
1. IT服务设计的作用 1) 设计满足需求的IT服务。 2) 设计SAL,测量方法和指标。 3) 设计服务过程及控制方法。...
高效查找:二分查找算法解析
1.二分查找简介 二分查找算法(Binary Search)是一种高效的查找算法,适用于有序数组或序列。它的基本思想是通过逐步缩小查找范围,将查找区间一分为二,直到找到目标值或确定目标值不存在。 算法原理:在数组…...
电脑办公技巧之如何在 Word 文档中添加文字或图片水印
Microsoft Word是全球最广泛使用的文字处理软件之一,它为用户提供了丰富的编辑功能来美化和保护文档。其中,“水印”是一种特别有用的功能,它可以用于标识文档状态(如“草稿”或“机密”)、公司标志或是版权信息等。本…...
我的求职之路合集
我把我秋招和春招的一些笔面试经验在这里发一下,网友们也可以参考一下。 我的求职之路:(1)如何谈自己的缺点 我的求职之路:(2)找工作时看重的点 我的求职之路:(3&…...
FPGA自分频产生的时钟如何使用?
对于频率比较小的时钟,使用clocking wizard IP往往不能产生,此时就需要我们使用代码进行自分频,自分频产生的时钟首先应该经过BUFG处理,然后还需要进行时钟约束,处理之后才能使用。...
【2025最新计算机毕业设计】基于SpringBoot+Vue爬虫技术的咖啡与茶饮料文化平台(高质量源码,可定制,提供文档,免费部署到本地)
作者简介:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容:🌟Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...
jmeter中对接口进行循环请求后获取相应数据
1、工作中遇到一个场景就是对某个单一接口进行循环请求,并需要获取每次请求后返回的相应数据; 2、首先就在jmeter对接口相关组件进行配置,需要组件有:循环控制器、CSV数据文件设置、计数器、访问接口、HTTP信息头管理器、正则表达…...
RocketMQ 怎么保证消息的可靠性?
目录 1. 消息发送可靠性 1.1 同步发送 1.2 异步发送 1.3 发送重试 1.4 事务消息 2. 消息存储可靠性 2.1 CommitLog 持久化 2.2 刷盘机制 2.3 主从复制 2.4 消息索引 3. 消息消费可靠性 3.1 消费确认机制 3.2 消费重试机制 3.3 消费位点管理 3.4 集群消费与广播消…...
基于 Node.js 的天气查询系统实现(附源码)
项目概述 这是一个基于 Node.js 的全栈应用,前端使用原生 JavaScript 和 CSS,后端使用 Express 框架,通过调用第三方天气 API 实现天气数据的获取和展示。 主要功能 默认显示多个主要城市的天气信息 支持城市天气搜索 响应式布局设计 深色主题界面 优雅的加载动画 技术栈 …...
C++函数初识
文章目录 一、形参带默认值的函数二、inline内联函数三、函数重载 一、形参带默认值的函数 给默认值的时候,从右向左给;调用效率的问题;定义处可以给形参默认值,声明也可以给形参默认值;形参给默认值的时候࿰…...
代码随想录day3
203:移除链表元素:注意虚拟头节点的使用 ListNode* removeElements(ListNode* head, int val) {ListNode* result new ListNode();result->next head;ListNode* current result;while(current ! nullptr && current->next ! nullptr){if(current-…...
论文+AI赋能教育:探索变革路径与创新实践。包括word和pdf格式。
下载地址链接: https://download.csdn.net/download/wanggang130532/90292129https://download.csdn.net/download/wanggang130532/90292129...
ray.rllib 入门实践-5: 训练算法
前面的博客介绍了ray.rllib中算法的配置和构建,也包含了算法训练的代码。 但是rllib中实现算法训练的方式不止一种,本博客对此进行介绍。很多教程使用 PPOTrainer 进行训练,但是 PPOTrainer 在最近的 ray 版本中已经取消了。 方式1࿱…...
uniapp 在线更新应用
在线更新应用及进度条显示 1.比较现安装手机中的apk 与线上apk的版本 getVersion(){var newVersionuni.getStorageSync("newVersion").split(".")var versionplus.runtime.version.split(".") // 获取手机安装的版本var versionNum""…...
中间件安全
一.中间件概述 1.中间件定义 介绍:中间件(Middleware)作为一种软件组件,在不同系统、应用程序或服务间扮演着数据与消息传递的关键角色。它常处于应用程序和操作系统之间,就像一座桥梁,负责不同应用程序间…...
从根源分析,调试,定位和解决MacOS ld: unsupported tapi file type ‘!tapi-tbd‘ in YAML file
你要是遇到同样错误,找一圈都没有解决,建议认真读一下本文,这个应该是最终极的解决办法,从原理上剖析了产生的原因,同时给出来了调试和定位的办法。 maccos使用brew安装了一个gcc14, 结果编译一个最简单的程序都报错&a…...