当前位置: 首页 > news >正文

【嵌入式Linux学习笔记】基于Linux官方库的标准外设驱动

在这里插入图片描述

对于标准的外设如LED,KEY,PWM等,以及标准通信协议,Linux都自带有标准的驱动库,不需要我们自行编写,只需要配置好相应的GPIO属性和电气属性,即可匹配相应的驱动,在应用程序中直接使用相应的外设。

学习视频地址:【正点原子】STM32MP157开发板

驱动流程

  1. 使能Linux内核相关库,make menuconfig
  2. 编写GPIO电气属性,文件路径:Linux内核路径/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
  3. 添加设备树节点,匹配属性及驱动,文件路径:Linux内核路径/arch/arm/boot/dts/stm32mp157d-atk.dts
  4. 编写相应的应用程序或者直接命令行调用

LED

驱动使能
在这里插入图片描述
在这里插入图片描述

电气属性

/* gpio led config */
led_pins_a: gpioled-0 {pins {pinmux = <STM32_PINMUX('I', 0, GPIO)>, /* LED0 */<STM32_PINMUX('F', 3, GPIO)>; /* LED1 */drive-push-pull;bias-pull-up;output-high;slew-rate = <0>;};
};

设备树节点

gpio-leds{compatible = "gpio-leds";pinctrl-0 = <&led_pins_a>;led0 {label = "red";gpios = <&gpioi 0 GPIO_ACTIVE_LOW>;linux,default-trigger = "heartbeat";default-state = "on";};led1 {label = "green";gpios = <&gpiof 3 GPIO_ACTIVE_LOW>;default-state = "off";};}; 

应用指令

echo 1 > /sys/class/leds/red/brightness #打开 LED0
echo 0 > /sys/class/leds/red/brightness #关闭 LED0

KEY

驱动使能
在这里插入图片描述

电气属性

/* gpio key config */key_pins_a: key_pins-0 {pins1 {pinmux = <STM32_PINMUX('G', 3, GPIO)>,	/* KEY0 */<STM32_PINMUX('H', 7, GPIO)>;	/* KEY1 */bias-pull-up;slew-rate = <0>;};pins2 {pinmux = <STM32_PINMUX('A', 0, GPIO)>;	/* WK_UP */bias-pull-down;slew-rate = <0>;};};

设备树节点

gpio-keys{compatible = "gpio-keys";pinctrl-names = "default";pinctrl-0 = <&key_pins_a>;autorepeat;  /* 支持连按 */key0{label = "GPIO KEY L";linux,code = <KEY_L>;gpios = <&gpiog 3 GPIO_ACTIVE_LOW>;};key1{label = "GPIO KEY S";linux,code = <KEY_L>;gpios = <&gpioh 7 GPIO_ACTIVE_LOW>;};wkup{label = "GPIO KEY Enter";linux,code = <KEY_ENTER>;gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>;gpio-key,wakeup;};
};

应用指令

hexdump /dev/input/event0 #查看按键事件的原始值

PWM

驱动使能
在这里插入图片描述
电气属性

/* pwm1 config */
pwm1_pins_a: pwm1-0 {pins {pinmux = <STM32_PINMUX('A', 10, AF1)>; /* TIM1_CH3 */bias-pull-down;drive-push-pull;slew-rate = <0>;};
};pwm1_sleep_pins_a: pwm1-sleep-0 {pins {pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* TIM1_CH3 */};
};

设备树节点

/* 官方文件中已有定时器节点,但是默认是失能的,所以需要在应用时追加定时器配置 */
&timers1 {status = "okay";/* spare all DMA channels since they are not needed for PWM output *//delete-property/dmas;/delete-property/dma-names;pwm1: pwm {pinctrl-0 = <&pwm1_pins_a>;pinctrl-1 = <&pwm1_sleep_pins_a>;pinctrl-names = "default", "sleep";#pwm-cells = <2>;status = "okay";};
};

检验

因为我们需要调用pwm下的pwmchipx来控制某路PWM,所以我们需要先确认pwmchipx是否对应我们使用的定时器timer。

cd pwmchip0

这时会打印出以下信息,我们需要匹配定时器的寄存器地址以及该pwm设备的寄存器地址。可以看到,地址都是44000000,说明这个pwm设备对应的定时器就是timer1。
在这里插入图片描述在这里插入图片描述
应用指令

echo 2 > /sys/class/pwm/pwmchip0/export 				# 开启TIM1_CH3
echo 50000 > /sys/class/pwm/pwmchip0/pwm2/period 		# 设置周期值为50000ns
echo 10000 > /sys/class/pwm/pwmchip0/pwm2/duty_cycle 	# 设置一个周期值中高电平的时间,即间接设置占空比
echo 1 > /sys/class/pwm/pwmchip0/pwm2/enable 			# 使能PWM,需要设置好周期和占空比再使能,否则会报错
echo "inversed" > /sys/class/pwm/pwmchip0/pwm2/polarity #极性反转
echo "normal" > /sys/class/pwm/pwmchip0/pwm2/polarity 	#极性恢复

I2C

I2C子系统架构
在这里插入图片描述I2C适配器驱动SOC厂商已经写好了,所以我们只需要写I2C设备驱动即可。
电气属性

i2c5_pins_a: i2c5-0 {pins {pinmux = <STM32_PINMUX('A', 11, AF4)>, 	/* I2C5_SCL */<STM32_PINMUX('A', 12, AF4)>; 		/* I2C5_SDA */bias-disable;drive-open-drain;slew-rate = <0>;};
};i2c5_pins_sleep_a: i2c5-1 {pins {pinmux = <STM32_PINMUX('A', 11, ANALOG)>, 	/* I2C5_SCL */<STM32_PINMUX('A', 12, ANALOG)>; 		/* I2C5_SDA */};
};

设备树节点
以正点原子STM32MP1开发板上的AP3216C传感器为例,它挂载在I2C5总线上。

&i2c5 {pinctrl-names = "default", "sleep";pinctrl-0 = <&i2c5_pins_a>;pinctrl-1 = <&i2c5_pins_sleep_a>;status = "okay";/* 1e代表器件地址 */ap3216c@1e {compatible = "alientek,ap3216c";reg = <0x1e>;};
};

驱动代码
下面的两个函数是i2c设备最主要的数据读写函数,设备的驱动就在这个基础上通过对不同寄存器的读写实现。i2c总线设备的操作与platform总线类似。

/** @description	: 从ap3216c读取寄存器数据* @param - dev:  ap3216c设备* @param - reg:  要读取的寄存器首地址* @param - val:  读取到的数据* @param - len:  要读取的数据长度* @return 		: 操作结果*/
static int ap3216c_read_regs(struct ap3216c_dev *dev, u8 reg, void *val, int len)
{int ret;struct i2c_msg msg[2];struct i2c_client *client = (struct i2c_client *)dev->client;/* msg[0]为发送要读取的首地址 */msg[0].addr = client->addr;			/* ap3216c地址 */msg[0].flags = 0;					/* 标记为发送数据 */msg[0].buf = &reg;					/* 读取的首地址 */msg[0].len = 1;						/* reg长度*//* msg[1]读取数据 */msg[1].addr = client->addr;			/* ap3216c地址 */msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/msg[1].buf = val;					/* 读取数据缓冲区 */msg[1].len = len;					/* 要读取的数据长度*/ret = i2c_transfer(client->adapter, msg, 2);if(ret == 2) {ret = 0;} else {printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);ret = -EREMOTEIO;}return ret;
}/** @description	: 向ap3216c寄存器写入数据* @param - dev:  ap3216c设备* @param - reg:  要写入的寄存器首地址* @param - val:  要写入的数据缓冲区* @param - len:  要写入的数据长度* @return 	  :   操作结果*/
static s32 ap3216c_write_regs(struct ap3216c_dev *dev, u8 reg, u8 *buf, u8 len)
{u8 b[256];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)dev->client;b[0] = reg;					/* 寄存器首地址 */memcpy(&b[1],buf,len);		/* 将要写入的数据拷贝到数组b里面 */msg.addr = client->addr;	/* ap3216c地址 */msg.flags = 0;				/* 标记为写数据 */msg.buf = b;				/* 要写入的数据缓冲区 */msg.len = len + 1;			/* 要写入的数据长度 */return i2c_transfer(client->adapter, &msg, 1);
}

SPI

SPI总线的操作与I2C总线操作相似。
电气属性

spi1_pins_a: spi1-0 {pins1 {pinmux = <STM32_PINMUX('Z', 0, AF5)>, /* SPI1_SCK */<STM32_PINMUX('Z', 2, AF5)>; /* SPI1_MOSI */bias-disable;drive-push-pull;slew-rate = <1>;};pins2 {pinmux = <STM32_PINMUX('Z', 1, AF5)>; /* SPI1_MISO */bias-disable;};pins3 {pinmux = <STM32_PINMUX('Z', 3, GPIO)>; /* SPI1_NSS */bias-pull-up;drive-push-pull;output-high;slew-rate = <0>;};
};spi1_sleep_pins_a: spi1-sleep-0 {pins {pinmux = <STM32_PINMUX('Z', 0, ANALOG)>, /* SPI1_SCK */<STM32_PINMUX('Z', 1, ANALOG)>, /* SPI1_MISO */<STM32_PINMUX('Z', 2, ANALOG)>; /* SPI1_MOSI */<STM32_PINMUX('Z', 3, ANALOG)>; /* SPI1_NSS */};
};

设备树节点

&spi1 {pinctrl-names = "default", "sleep";pinctrl-0 = <&spi1_pins_a>;pinctrl-1 = <&spi1_sleep_pins_a>;cs-gpios = <&gpioz 3 GPIO_ACTIVE_LOW>;status = "okay";spidev: icm20608@0 {compatible = "alientek,icm20608";reg = <0>; /* CS #0 */spi-max-frequency = <8000000>;};
};

驱动代码

/** @description	: 从icm20608读取多个寄存器数据* @param - dev:  icm20608设备* @param - reg:  要读取的寄存器首地址* @param - val:  读取到的数据* @param - len:  要读取的数据长度* @return 		: 操作结果*/
static int icm20608_read_regs(struct icm20608_dev *dev, u8 reg, void *buf, int len)
{int ret = -1;unsigned char txdata[1];unsigned char * rxdata;struct spi_message m;struct spi_transfer *t;struct spi_device *spi = (struct spi_device *)dev->spi;t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */if(!t) {return -ENOMEM;}rxdata = kzalloc(sizeof(char) * len, GFP_KERNEL);	/* 申请内存 */if(!rxdata) {goto out1;}/* 一共发送len+1个字节的数据,第一个字节为寄存器首地址,一共要读取len个字节长度的数据,*/txdata[0] = reg | 0x80;		/* 写数据的时候首寄存器地址bit8要置1 */			t->tx_buf = txdata;			/* 要发送的数据 */t->rx_buf = rxdata;			/* 要读取的数据 */t->len = len+1;				/* t->len=发送的长度+读取的长度 */spi_message_init(&m);		/* 初始化spi_message */spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */ret = spi_sync(spi, &m);	/* 同步发送 */if(ret) {goto out2;}memcpy(buf , rxdata+1, len);  /* 只需要读取的数据 */out2:kfree(rxdata);					/* 释放内存 */
out1:	kfree(t);						/* 释放内存 */return ret;
}/** @description	: 向icm20608多个寄存器写入数据* @param - dev:  icm20608设备* @param - reg:  要写入的寄存器首地址* @param - val:  要写入的数据缓冲区* @param - len:  要写入的数据长度* @return 	  :   操作结果*/
static s32 icm20608_write_regs(struct icm20608_dev *dev, u8 reg, u8 *buf, u8 len)
{int ret = -1;unsigned char *txdata;struct spi_message m;struct spi_transfer *t;struct spi_device *spi = (struct spi_device *)dev->spi;t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */if(!t) {return -ENOMEM;}txdata = kzalloc(sizeof(char)+len, GFP_KERNEL);if(!txdata) {goto out1;}/* 一共发送len+1个字节的数据,第一个字节为寄存器首地址,len为要写入的寄存器的集合,*/*txdata = reg & ~0x80;	/* 写数据的时候首寄存器地址bit8要清零 */memcpy(txdata+1, buf, len);	/* 把len个寄存器拷贝到txdata里,等待发送 */t->tx_buf = txdata;			/* 要发送的数据 */t->len = len+1;				/* t->len=发送的长度+读取的长度 */spi_message_init(&m);		/* 初始化spi_message */spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */ret = spi_sync(spi, &m);	/* 同步发送 */if(ret) {goto out2;}out2:kfree(txdata);				/* 释放内存 */
out1:kfree(t);					/* 释放内存 */return ret;
}

UART/RS232/RS485

Linux也提供了串口相关的驱动库供我们使用。

usart3_pins_c: usart3-2 {pins1 {pinmux = <STM32_PINMUX('D', 8, AF7)>; /* USART3_TX */bias-disable;drive-push-pull;slew-rate = <0>;};pins2 {pinmux = <STM32_PINMUX('D', 9, AF7)>; /* USART3_RX */bias-disable;};
};usart5_pins_a: usart5-0 {pins1 {pinmux = <STM32_PINMUX('B', 13, AF14)>; /* USART5_TX */bias-disable;drive-push-pull;slew-rate = <0>;};pins2 {pinmux = <STM32_PINMUX('B', 12, AF14)>; /* USART5_RX */bias-disable;};
};

设备树节点
aliases节点用于设置串口别名,串口驱动会读取aliases节点数据,表示在系统启动生成一个名为“/dev/ttySTM0”的设备文件,serial1就会生成“/dev/ttySTM1”如此类推,最多 8 个。

# 这个在根节点下
/{
......aliases {serial0 = &uart4;serial1 = &uart5;serial2 = &usart3;};
......
};&usart3 {pinctrl-names = "default";pinctrl-0 = <&usart3_pins_c>;status = "okay";
};&uart5 {pinctrl-names = "default";pinctrl-0 = <&usart5_pins_a>;status = "okay";
};

串口软件移植
minicom 类似我们常用的串口调试助手,是 Linux 下很常用的一个串口工具,builroot里面已经集成了这个软件,所以只需重新配置builroot就行。
在这里插入图片描述在这里插入图片描述

sudo make # 保持上述配置后,进行编译
cd output/images/  #进入到 output/images 目录
sudo tar -axvf rootfs.tar -C /home/jozenlee/arm_linux/nfs/rootfs #解压到 nfsroot 目录

minicom配置

minicom -s #打开配置界面

CAN

STM32MP1提供的是功能更强大的FDCAN控制器,支持数据高速传输,并且数据量从8位加到了64位
电气属性

m_can1_pins_a: m-can1-0 {pins1 {pinmux = <STM32_PINMUX('H', 13, AF9)>; /* CAN1_TX */slew-rate = <1>;drive-push-pull;bias-disable;};pins2 {pinmux = <STM32_PINMUX('I', 9, AF9)>; /* CAN1_RX */bias-disable;};
};m_can1_sleep_pins_a: m_can1-sleep-0 {pins {pinmux = <STM32_PINMUX('H', 13, ANALOG)>, /* CAN1_TX */<STM32_PINMUX('I', 9, ANALOG)>; /* CAN1_RX */};
};

设备树节点

&m_can1 {pinctrl-names = "default", "sleep";pinctrl-0 = <&m_can1_pins_a>;pinctrl-1 = <&m_can1_sleep_pins_a>;status = "okay";
};

软件移植
iproute2
在这里插入图片描述在这里插入图片描述
can-utils
在这里插入图片描述
应用指令

# 设置 can0 速度为 1000Kbit/s,使用的是一般模式
ip link set can0 type can bitrate 1000000 # 设置 can0 速度为 1000Kbit/s,数据波特率为 5000 kBit/s,使用FDCAN
ip link set can0 up type can bitrate 1000000 dbitrate 5000000 fd on
ip link set can0 up type can bitrate 200000 dbitrate 1000000 fd on
ip link set can0 up type can bitrate 100000 dbitrate 500000 fd on# 打开can0
ifconfig can0 up# 关闭can0
ifconfig can0 down# 接收数据
candump can0# 发送数据
cansend can0 5A1#11.22.33.44.55.66.77.88

相关文章:

【嵌入式Linux学习笔记】基于Linux官方库的标准外设驱动

对于标准的外设如LED&#xff0c;KEY&#xff0c;PWM等&#xff0c;以及标准通信协议&#xff0c;Linux都自带有标准的驱动库&#xff0c;不需要我们自行编写&#xff0c;只需要配置好相应的GPIO属性和电气属性&#xff0c;即可匹配相应的驱动&#xff0c;在应用程序中直接使用…...

网络爬虫抓包工具

&#x1f4da;介绍&#xff1a;Charles是著名的抓包工具&#x1f402;&#xff0c;可以抓取移动端与pc端网络访问&#x1f577;的所有数据。我们将使用它抓取我们与小程序交互的所有信息。&#x1f387;我们可以百度搜索Charles官网下载适用于自己系统的Charles安装包&#x1f…...

蓝桥杯倒计时 | 倒计时17天

作者&#x1f575;️‍♂️&#xff1a;让机器理解语言か 专栏&#x1f387;&#xff1a;蓝桥杯倒计时冲刺 描述&#x1f3a8;&#xff1a;蓝桥杯冲刺阶段&#xff0c;一定要沉住气&#xff0c;一步一个脚印&#xff0c;胜利就在前方&#xff01; 寄语&#x1f493;&#xff1a…...

【Spring Cloud Alibaba】7.Sentinel熔断器仪表盘监控

文章目录简介什么是 Sentinel控制台获取源码方式下载jar包方式启动访问服务配置项目&#xff0c;启用Sentinel完整配置测试简介 接下来我们通过Sentinel控制台来实现对服务消费者提供的熔断机制进行监控和控制&#xff0c;本操作先要完成之前的步骤&#xff0c;详情请参照【Sp…...

个人博客系统项目测试报告

项目背景介绍 背景&#xff1a;当在学习一项技能的时候&#xff0c;我们总会习惯通过博客来记录所学的知识点&#xff0c;方便后期遗忘时随时查看和快速复习。本次开发的Web网站程序便是为了更加轻量和方便地记录自己的学习笔记 概述&#xff1a;一个Web网站程序&#xff0c;…...

flutter安装自用笔记

参照文章&#xff1a; 开发环境搭建 Flutter环境配置步骤&#xff1a; 1.系统配置要求 2.Java环境 3.Flutter SDK 4.Android 开发环境一、系统配置要求 操作系统&#xff1a;Windows 7 SP1 或更高的版本&#xff08;基于 x86-64 的 64 位操作系统&#xff09; 磁盘空间&…...

tomcat线程池以及在SpringBoot中的启动过程

tomcat两大组件&#xff1a;连接器Connector&#xff0c;容器Container tomcat线程池 Tomcat线程池扩展了ThreadPoolExecutor&#xff0c;行为稍有不同 重写了ThreadPoolExecutor的execute方法 如果总线程数达到maximumPoolSize&#xff0c;不会立刻抛RejectedExecutionExcept…...

第十四届中国大学生创新创业大赛

文章目录比赛官网比赛题目含金量非常高建议参加的学生推荐几个我感兴趣的题目联系比赛官网 官网地址&#xff1a;http://www.fwwb.org.cn/ 实际叫做&#xff1a;中国大学生创新创业大赛 比赛题目 题目公布查看地址&#xff1a;http://www.fwwb.org.cn/topic/index 题目有…...

LeetCode:322. 零钱兑换——动态规划从案例入门

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340;算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;322. 零钱兑换 题目描述&#xff1a;给你一个整数数组coins&#xff0c;…...

【lwIP(第四章)】网络接口

目录一、lwIP网络接口简介二、lwIP的netif结构三、lwIP的netif相关函数1. lwIP网络接口的全局变量2. netif_add()函数3. netif_remove()函数4. netif_set_default()函数一、lwIP网络接口简介 lwIP协议栈支持多种不同的网络接口&#xff08;网卡&#xff09;&#xff0c;由于网卡…...

Vue3 pinia入门篇(一)

系列文章目录 主要为了记录如何使用Pinia在Vue3中的使用方式&#xff08;下面会介绍为什么使用Vue3选型&#xff09; 文章目录系列文章目录不用Vue2使用Pinia举例子&#xff1f;1.笔者的个人看法&#xff1a;2.总结一、Pinia是什么1.状态管理工具&#xff08;类比Vuex&#xff…...

python面向对象编程解释

python是一个面向对象的编程语言 面向过程的开发语言有C&#xff0c;面向对象除了python还有java等语言 具体来讲&#xff1a; 面向过程 &#xff1a;举个例子&#xff0c;比如说&#xff0c;把大象装进冰箱总共分几步&#xff0c;第一步&#xff0c;把冰箱门打开&#xff0c…...

ARM(IMX6U)嵌入式软件裸机开发之环境搭建与配置

目录 前沿 Ubuntu 和 Windows 文件互传 Ubuntu 下 NFS 和 SSH 服务开启 Ubuntu 交叉编译工具链安装 Source Insight 软件安装和使用 Visual Studio Code 软件的安装和使用 前沿 为什么我们要学习裸机开发呢&#xff1f; 1、裸机开发是了解所使用的 CPU 最直接、最简单的方…...

Java文件复制多种方法

1、InputStream与OutputStream 创建两个文件 - 源和目标。然后我们从源创建InputStream并使用OutputStream将其写入目标文件进行 java 复制文件操作。 private static void copyFileUsingStream(File source, File dest) throws IOException {InputStream is null;OutputStr…...

Java语言-----封装、继承、抽象、多态、接口

目录 前言 一.封装 1.1封装的定义 1.2访问修饰符的使用 二.继承 2.1继承的定义 2.2继承的方法 2.3继承使用注意点 三.多态 3,1多态的定义 3.2动态绑定 3.3方法重写 3.4向上&#xff08;向下&#xff09;转型 四.抽象 4.1抽象的概述和定义 4.2抽象的使用 五…...

基于深度学习的瓶子检测软件(UI界面+YOLOv5+训练数据集)

摘要&#xff1a;基于深度学习的瓶子检测软件用于自动化瓶子检测与识别&#xff0c;对于各种场景下的塑料瓶、玻璃瓶等进行检测并计数&#xff0c;辅助计算机瓶子生产回收等工序。本文详细介绍深度学习的瓶子检测软件&#xff0c;在介绍算法原理的同时&#xff0c;给出Python的…...

仿网易云小程序(一)

目录 一、项目准备 二、项目初始化 1.新建项目 2.封装service请求 三、底部导航栏的设计 四、MV页面的设计 1.将获取到的数据进行渲染 2.播放量数据进行处理转换 3.时长数据进行处理转换 五、MV组件的抽离封装 六、请求的抽离video 七、下拉重新请求新的数据 八、跳转到…...

【C++】vector模拟实现及其应用

文章目录vector的介绍vector的使用及其实现vector的定义vector iterator 的使用vector空间增长问题vector的增删查改vector的介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素…...

JS看这一篇就够啦,JS基础大全,可用于快速回顾知识,面试首选

1 JS简介 更多JS内容可以看MDN&#xff1a;点击传送 浏览器分成两部分&#xff1a;渲染引擎和 JS 引擎 渲染引擎&#xff1a;用来解析HTML与CSS&#xff0c;俗称内核&#xff0c;比如 chrome 浏览器的 blink &#xff0c;老版本的 webkitJS 引擎&#xff1a;也称为 JS 解释器…...

武汉凯迪正大GB4208外壳防护等级试具

一、IP1X 试验探棒 产品概述&#xff1a; 符合IEC61032图1试具A、GB16842试具A、GB4208IP1、IEC60529IP1、IEC60065 等标准要求。用于防止手背触及的防护检验。 技术参数&#xff1a; 1、探球直径&#xff1a;50mm 2、挡板直径&#xff1a;45mm 3、挡板厚度&#xff1a;…...

FPU 检测技术:从 8086 到 286 的演进与挑战跨越

【导语&#xff1a;本文围绕 FPU 检测技术展开&#xff0c;从 8086 到 286 及后续 CPU 的 FPU 检测工作原理进行深入探讨&#xff0c;揭示了技术演进中的变化、难点及实际应用情况&#xff0c;对理解早期计算机浮点运算相关技术有重要意义。】8086 时代 FPU 检测的独特设计在 8…...

iOS开发效率工具:设备支持文件管理完全指南 - 无需升级Xcode的解决方案

iOS开发效率工具&#xff1a;设备支持文件管理完全指南 - 无需升级Xcode的解决方案 【免费下载链接】iOSDeviceSupport All versions of iOS Device Support 项目地址: https://gitcode.com/gh_mirrors/ios/iOSDeviceSupport 作为iOS开发者&#xff0c;你是否曾遭遇这样…...

如何轻松实现单机游戏分屏多人:Nucleus Co-Op完整指南

如何轻松实现单机游戏分屏多人&#xff1a;Nucleus Co-Op完整指南 【免费下载链接】nucleuscoop Starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/nu/nucleuscoop 还在为找不到联机伙伴而烦恼吗&a…...

低代码组件“看似简单,上线即崩”?20年专家拆解5个被90%团队忽略的线程安全与事务传播陷阱

第一章&#xff1a;低代码组件“看似简单&#xff0c;上线即崩”的真相低代码平台承诺“拖拽即交付”&#xff0c;但真实生产环境中&#xff0c;大量业务系统在上线后数小时内便出现表单提交失败、数据丢失、权限错乱或页面白屏等问题。这些故障并非源于复杂逻辑&#xff0c;而…...

从零搭建PointRCNN:Linux环境配置与3D检测可视化实战

1. 环境准备&#xff1a;从零搭建Linux深度学习工作站 第一次在Linux系统上配置深度学习环境时&#xff0c;我盯着命令行界面手足无措的样子还历历在目。现在回想起来&#xff0c;其实只要掌握几个关键步骤&#xff0c;就能快速搭建好PointRCNN所需的运行环境。我们以配备NVIDI…...

忍者像素绘卷参数详解:CFG/Steps/画幅三要素调优指南

忍者像素绘卷参数详解&#xff1a;CFG/Steps/画幅三要素调优指南 1. 认识忍者像素绘卷 忍者像素绘卷是一款基于Z-Image-Turbo深度优化的图像生成工作站&#xff0c;它将忍者的热血意志与16-Bit复古游戏美学完美融合。这款工具采用明亮的"云端"视觉设计&#xff0c;…...

8种Prompt优化技巧:解决大模型输出不稳定痛点

8种Prompt优化技巧&#xff1a;解决大模型输出不稳定痛点 在大模型应用落地过程中&#xff0c;开发者常遇到输出结果不可控的问题&#xff1a;同样的需求多次调用返回内容差异巨大、回答偏离核心要求、格式混乱无法直接解析&#xff0c;这些问题严重影响业务流程的稳定性和用户…...

Redis 用错接口反而更慢?高并发下这几个坑,90% 后端都踩过

前言线上出过一个特别反直觉的故障&#xff1a;接口本来直连 MySQL 跑得好好的&#xff0c;加上 Redis 缓存后&#xff0c;响应时间直接翻倍&#xff0c;CPU 还往上飘。一开始怀疑网络、怀疑 Redis 性能、怀疑代码 Bug&#xff0c;排查一整天才发现&#xff1a;缓存逻辑没错&am…...

LFM2.5-1.2B-Thinking-GGUF部署教程:Ubuntu/CentOS/Debian三平台通用安装步骤

LFM2.5-1.2B-Thinking-GGUF部署教程&#xff1a;Ubuntu/CentOS/Debian三平台通用安装步骤 1. 平台简介 LFM2.5-1.2B-Thinking-GGUF是Liquid AI推出的轻量级文本生成模型&#xff0c;特别适合在资源有限的环境中快速部署。该镜像内置了GGUF模型文件和llama.cpp运行时&#xff…...

FCOS3D vs PGD:单目3D检测两大算法核心差异与选型指南

FCOS3D与PGD&#xff1a;单目3D检测技术深度对比与工程实践指南 1. 技术背景与核心挑战 在自动驾驶和机器人感知领域&#xff0c;单目3D目标检测技术因其硬件成本优势和部署便捷性&#xff0c;正成为工业界关注的焦点。这项技术仅需单个摄像头即可实现对三维空间中物体的定位和…...