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

韦东山嵌入式linux系列-具体单板的按键驱动程序(查询方式)

1 GPIO 操作回顾

(1)使能模块;

(2)设置引脚的模式(工作于GPIO模式);

(3)设置GPIO本身(输入/输出);

(4)GPIO作为输入引脚时,读某个data寄存器获得引脚的电平。

2 百问网 STM32MP157 的按键驱动程序(查询方式)

在 STM32MP157 开发板上,我们为它设计了 2 个按键。

2.1 先看原理图确定引脚及操作方法

平时按键电平为低,按下按键后电平为高。

按键引脚为 GPIOG_IO03、 GPIOG_IO02。

2.2 再看芯片手册确定寄存器及操作方法

步骤1:使能GPIOG

下图为针对 APU 的 GPIOA 至 K 的时钟使能寄存器,低11位有效。为了使用GPIOG,我们需要将对应的 b[6]位设置为 1

英文明明写的是MPU

MPU/MCU -- Microprocessor/Micro controller Unit, 微处理器/微控制器,一般用于低计算应用的RISC计算机体系架构产品,如ARM-M系列处理器。

APU、BPU、CPU、DPU、FPU、GPU、HPU、IPU、MPU、NPU、RPU、TPU、VPU、WPU、XPU、ZPU 都是什么? - 一杯清酒邀明月 - 博客园 (cnblogs.com)

地址偏移量:0xA28
复位值:0x0000 0000

该寄存器用于将相应外设的外设时钟使能位设置为“1”。它将用于为MPU分配外设。写“0”没有作用,读有作用,返回相应位的有效值。写入'1'将相应的位设置为'1'

Bits 31:11保留,必须保持在复位值。
bit10 GPIOKEN: GPIOK外设时钟使能软件设置。
0:写“0”无效,读“0”表示禁用外设时钟
1:写“1”使能外设时钟,读“1”使能外设时钟

其他位一样

步骤2:设置GPIOG_IO03、 GPIOG_IO02为GPIO输入模式

GPIOx_MODER用于配置GPIO的模式,包括输入、通用输出、多功能和模拟共四种模式。该寄存器共32位,涉及16个GPIO,每个GPIO对应 2 位。GPIOx_MODER 的各位定义如下,在这里分别选择00和01两种,各自对应输入和输出模式。(上电默认为输入悬空模式)。其中 00 对应输入功能, 01 对应输出功能

设置 b[7:6]为00就可以配置GPIOG_IO03为输入模式,

配置 b[5:4]为00就可以配置GPIOG_IO02为输入模式。

步骤 3:读取GPIOG_IO02、GPIOG_IO03引脚电平

寄存器地址为:

在参考手册搜关键字gpio

读取 IDR 寄存器获取引脚状态寄存器,得到引脚电平

Bits 31:16保留,必须保持复位值。
bit 15:0 IDR[15:0]:端口x输入数据I/O引脚y (y = 15 ~ 0),这些位是只读的。它们包含相应I/O端口的输入值。

3 代码

board_drv.c

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>#include "button_drv.h"// 1主设备号
static int major = 0;
static struct class* button_class;
static struct button_operations *p_button_operations;void register_button_operations(struct button_operations *opr)
{int i;p_button_operations = opr;for (i = 0; i < opr->count; i++){device_create(button_class, NULL, MKDEV(major, i), NULL, "winter_button@%d", i);}
}void unregister_button_operations(void)
{int i;for (i = 0; i < p_button_operations->count; i++){device_destroy(button_class, MKDEV(major, i));}
}EXPORT_SYMBOL(register_button_operations);
EXPORT_SYMBOL(unregister_button_operations);// 3实现open/read函数
static int button_open (struct inode *inode, struct file *file)
{int minor = iminor(inode);// 利用此设备号初始化p_button_operations->init(minor);return 0;
}static ssize_t button_read (struct file *file, char __user *buf, size_t size, loff_t *off)
{unsigned int minor = iminor(file_inode(file));char level;int err;level = p_button_operations->read(minor);// 将内核数据拷贝到用户空间,也就是读数据err = copy_to_user(buf, &level, 1);return 1;
}// 2file_operations结构体
static struct file_operations button_operations = {.open = button_open,.read = button_read,
};// 4在入口函数中注册file_operations结构体
int button_init(void)
{// 注册file_operations结构体major = register_chrdev(0, "winter_button", &button_operations);// 注册结点button_class = class_create(THIS_MODULE, "winter_button");if (IS_ERR(button_class))return -1;return 0;}// 出口函数
void button_exit(void)
{class_destroy(button_class);unregister_chrdev(major, "winter_button");
}module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");

board_drv.h

#ifndef BUTTON_DRV_H
#define BUTTON_DRV_Hstruct button_operations {int count;void (*init) (int which);int (*read) (int which);
};void register_button_operations(struct button_operations *opr);
void unregister_button_operations(void);#endif

board_xxx.c

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>#include "button_drv.h"static void board_xxx_button_init_gpio (int which)
{printk("%s %s %d, init gpio for button %d\n", __FILE__, __FUNCTION__, __LINE__, which);
}static int board_xxx_button_read_gpio (int which)
{printk("%s %s %d, read gpio for button %d\n", __FILE__, __FUNCTION__, __LINE__, which);return 1;
}static struct button_operations my_buttons_ops ={.count = 2,.init  = board_xxx_button_init_gpio,.read  = board_xxx_button_read_gpio,
};int board_xxx_button_init(void)
{register_button_operations(&my_buttons_ops);return 0;
}void board_xxx_button_exit(void)
{unregister_button_operations();
}module_init(board_xxx_button_init);
module_exit(board_xxx_button_exit);
MODULE_LICENSE("GPL");

board_test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/** ./button_test /dev/100ask_button0**/
int main(int argc, char **argv)
{int fd;char val;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s <dev>\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}/* 3. 写文件 */read(fd, &val, 1);printf("get button : %d\n", val);close(fd);return 0;
}

上面4个和之前的都一样,主要不同在board_100ask_stm32mp157.c

主要看 board_100ask_stm32mp157-pro.c。涉及的寄存器挺多,一个一个去执行 ioremap 效率太低。先定义结构体,然后对结构体指针进行 ioremap。对于 GPIO,可以如下定义:

struct stm32mp157_gpio {volatile unsigned int MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */volatile unsigned int OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */volatile unsigned int OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */volatile unsigned int PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */volatile unsigned int IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */volatile unsigned int ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */volatile unsigned int BSRR;     /*!< GPIO port bit set/reset,               Address offset: 0x18      */volatile unsigned int LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */volatile unsigned int AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} ;

这个顺序是按照偏移量列出的

看一个驱动程序,先看它的入口函数, 下列代码向上层驱动注册一个button_operations 结构体,代码如下。

static struct button_operations my_buttons_ops = {.count = 2,.init = board_stm32mp157_button_init,.read = board_stm32mp157_button_read,
};
// 入口函数
int board_stm32mp157_button_drv_init(void)
{register_button_operations(&my_buttons_ops);return 0;
}void board_stm32mp157_button_drv_exit(void)
{unregister_button_operations();
}

button_operations 结 构 体 中 有 init 函 数 指 针 , 它 指 向board_stm32mp157_button_init 函数,在里面将会初始化 LED 引脚:使能、设置为 GPIO 模式、设置为输出引脚。代码如下。
值得关注的下列代码中对 ioremap 函数的使用,它们是得到寄存器的虚拟地址,以后使用虚拟地址访问寄存器。

/* RCC_PLL4CR */
static volatile unsigned int *RCC_PLL4CR; /* RCC_MP_AHB4ENSETR */
static volatile unsigned int *RCC_MP_AHB4ENSETR;/* KEY1: PG3, KEY2: PG2 */
static struct stm32mp157_gpio *gpiog;/* 初始化button, which-哪个button */
static void board_stm32mp157_button_init (int which)
{// 没有使能if (!RCC_PLL4CR){RCC_PLL4CR = ioremap(0x50000000 + 0x894, 4);RCC_MP_AHB4ENSETR = ioremap(0x50000000 + 0xA28, 4);gpiog = ioremap(0x50008000, sizeof(struct stm32mp157_gpio));}if (which == 0){/* 1. enable PLL4 * CG15, b[31:30] = 0b11*/*RCC_PLL4CR |= (1<<0);while((*RCC_PLL4CR & (1<<1)) == 0);/* 2. enable GPIOG */*RCC_MP_AHB4ENSETR |= (1<<6);/* 3. 设置PG3为GPIO模式, 输入模式 */gpiog->MODER &= ~(3<<6);}else if(which == 1){/* 1. enable PLL4 * CG15, b[31:30] = 0b11*/*RCC_PLL4CR |= (1<<0);while((*RCC_PLL4CR & (1<<1)) == 0);/* 2. enable GPIOG */*RCC_MP_AHB4ENSETR |= (1<<6);/* 3. 设置PG2为GPIO模式, 输入模式 */gpiog->MODER &= ~(3<<4);}}

button_operations 结 构 体 中 还 有 有 read 函 数 指 针 , 它 指 向board_stm32mp157_button_read 函数,在里面将会读取并返回按键引脚的电平。代码如下

static int board_stm32mp157_button_read (int which) /* 读button, which-哪个 */
{//printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);if (which == 0)return (gpiog->IDR & (1<<3)) ? 1 : 0;elsereturn (gpiog->IDR & (1<<2)) ? 1 : 0;
}

参考:韦东山嵌入式linux系列-LED驱动程序-CSDN博客

board_100ask_stm32mp157.c

#include <linux/module.h>#include <linux/fs.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/io.h>#include "button_drv.h"/* RCC_PLL4CR */
static volatile unsigned int* RCC_PLL4CR; /* RCC_MP_AHB4ENSETR */
static volatile unsigned int* RCC_MP_AHB4ENSETR; /* KEY1: PG3, KEY2: PG2 */
static struct stm32mp157_gpio* gpiog;struct stm32mp157_gpio {volatile unsigned int MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */volatile unsigned int OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */volatile unsigned int OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */volatile unsigned int PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */volatile unsigned int IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */volatile unsigned int ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */volatile unsigned int BSRR;     /*!< GPIO port bit set/reset,               Address offset: 0x18      */volatile unsigned int LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */volatile unsigned int AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
};/* 初始化button, which-哪个button */      
static void board_stm32mp157_button_init (int which) 
{if (!RCC_PLL4CR){RCC_PLL4CR = ioremap(0x50000000 + 0x894, 4);RCC_MP_AHB4ENSETR = ioremap(0x50000000 + 0xA28, 4);gpiog = ioremap(0x50008000, sizeof(struct stm32mp157_gpio));}if (which == 0){/* 1. enable PLL4 * CG15, b[31:30] = 0b11*/*RCC_PLL4CR |= (1<<0);while((*RCC_PLL4CR & (1<<1)) == 0);/* 2. enable GPIOG */*RCC_MP_AHB4ENSETR |= (1<<6);/* 3. 设置PG3为GPIO模式, 输入模式 */gpiog->MODER &= ~(3<<6);}else if(which == 1){/* 1. enable PLL4 * CG15, b[31:30] = 0b11*/*RCC_PLL4CR |= (1<<0);while((*RCC_PLL4CR & (1<<1)) == 0);/* 2. enable GPIOG */*RCC_MP_AHB4ENSETR |= (1<<6);/* 3. 设置PG2为GPIO模式, 输入模式 */gpiog->MODER &= ~(3<<4);}
}/* 读button, which-哪个 */
static int board_stm32mp157_button_read (int which)
{//printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);if (which == 0){return (gpiog->IDR & (1<<3)) ? 1 : 0;}else{return (gpiog->IDR & (1<<2)) ? 1 : 0;}
}static struct button_operations my_buttons_ops = {.count = 2,.init = board_stm32mp157_button_init,.read = board_stm32mp157_button_read,
};int board_stm32mp157_button_drv_init(void)
{register_button_operations(&my_buttons_ops);return 0;
}void board_stm32mp157_button_drv_exit(void)
{unregister_button_operations();
}module_init(board_stm32mp157_button_drv_init);
module_exit(board_stm32mp157_button_drv_exit);MODULE_LICENSE("GPL");

编译

4 测试

在开发板挂载 Ubuntu 的NFS目录

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs/ /mnt

将ko文件和测试代码拷贝到挂载目录,安装驱动

insmod button_drv.ko
insmod board_100ask_stm32mp157.ko

执行测试程序观察它的返回值(执行测试程序的同时操作按键):

./button_test /dev/winter_button@0
./button_test /dev/winter_button@1

执行程序的同时,按下按键,输出是0

相关文章:

韦东山嵌入式linux系列-具体单板的按键驱动程序(查询方式)

1 GPIO 操作回顾 &#xff08;1&#xff09;使能模块&#xff1b; &#xff08;2&#xff09;设置引脚的模式&#xff08;工作于GPIO模式&#xff09;&#xff1b; &#xff08;3&#xff09;设置GPIO本身&#xff08;输入/输出&#xff09;&#xff1b; &#xff08;4&…...

如何使用 API list 极狐GitLab 群组中的镜像仓库?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…...

PHP设计模式-简单工厂模式

核心&#xff1a; 一、定义一个接口类里面写规定好的方法。 interface Message{public function send(array $params);public function getMessage(array $params);public function getCode(array $params);} 二、定义产品类 、产品类继承接口类 class AlliYunSms implements …...

C语言航空售票系统

以下是系统部分页面 以下是部分源码&#xff0c;需要源码的私信 #include<stdio.h> #include<stdlib.h> #include<string.h> #define max_user 100 typedef struct ft {char name[50];//名字char start_place[50];//出发地char end_place[50];//目的地char …...

Oracle 19c打Datapatch数据补丁报错处理

Oracle 19c打Datapatch数据补丁报错处理 错误分析重新编译补丁验证安装完数据库补丁后,在数据补丁的步骤收到以下报错: Connecting to database...OK Gathering database info...done Bootstrapping registry and package to current versions...done Determining current s…...

Linux shell编程学习笔记66:ping命令 超详细的选项说明

0 前言 网络信息是电脑网络信息安全检查中的一块重要内容&#xff0c;Linux和基于Linux的操作系统&#xff0c;提供了很多的网络命令&#xff0c;今天我们研究最常用的ping命令。 1 ping命令 的功能、格式和选项说明 1.1 ping命令 的功能 简单来说&#xff0c; ping 命令 会…...

SSL/TLS和SSL VPN

1、SSL/TLS SSL安全套接字层&#xff1a;是一种加密协议&#xff0c;用于在网络通信中建立安全连接。它在应用层和传输层&#xff08;TCP/IP&#xff09;之间提供数据加密、服务器身份验证以及信息完整性验证 SSL只保护TCP流量&#xff0c;不保护UDP协议 TLS&#xff1a;传输层…...

浅谈WebSerice

一. 什么是WebService Web Service也称为web服务&#xff0c;它是一种跨编程语言和操作系统平台的远程调用技术。Web Service采用标准的SOAP协议传输&#xff08;SOAP&#xff1a;Simple Object Access Protocol简单对象访问协议&#xff0c;soap属于w3c标准。并且soap协议是基…...

linux快速入门-学习笔记

linux快速入门-学习笔记 第一章&#xff1a;Linux系统概念及命令学习Linux系统基本概念命令终端介绍命令格式介绍Linux系统辨别目录与文件的方法通过文件详细属性辨别ls 查看目录/文件命令Linux 系统下的归属关系命令行编辑技巧Linux 基本权限的类别课后练习 第二章&#xff1a…...

科普文:5种Linux下软件部署方式说明

在Linux世界里&#xff0c;高效、灵活地安装和管理软件是每个系统管理员和开发者的基本功。从传统的RPM包管理&#xff0c;到便捷的YUM软件仓库&#xff0c;再到颠覆性的Docker容器技术&#xff0c;Snap&#xff0c;源码安装&#xff0c;每一种方法都有其独到之处&#xff0c;适…...

Redisson中的RBlockingQueue的使用场景及例子

Redisson 的 RBlockingQueue 是一个实现了 Java BlockingQueue 接口的分布式队列&#xff0c;它可以用于在分布式系统中实现生产者-消费者模式。RBlockingQueue 提供了线程安全的阻塞队列操作&#xff0c;允许生产者在队列满时阻塞&#xff0c;消费者在队列空时阻塞&#xff0c…...

【办公软件】Office 2019以上版本PPT 做平滑切换

Office2019以上版本可以在切页面时做平滑切换&#xff0c;做到一些简单的动画效果。如下在快捷菜单栏中的切换里选择平滑。 比如&#xff0c;在两页PPT中&#xff0c;使用同一个形状对象&#xff0c;修改了大小和颜色。 选择切换为平滑后&#xff0c;可以完成如下的动画显示。 …...

connect-multiparty中间件用法以及实例--文件上传中间件(保姆级别教学)

connect-multiparty中间件的用法包括安装和引入、基本设置、路由应用、文件处理以及安全和优化等步骤。 connect-multiparty是一个专为Connect和Express框架设计的文件上传中间件&#xff0c;它基于multiparty库&#xff0c;用于处理多部分表单数据&#xff0c;尤其针对文件上传…...

0503触发器的电路结构和工作原理

触发器的电路结构和工作原理 如何区分锁存器还是触发器&#xff0c; 看有没有这个三角符号&#xff0c;告诉是上升沿触发还是下降沿触发&#xff0c;没有三角符号就是电平触发。低电平触发就画个小圈。高电平触发就不画小圈。有小圈的三角就是下降沿触发 setup建立时间 hold 保…...

LeetCode:二叉树的中序遍历(C语言)

1、前序遍历&#xff1a;根左右 2、中序遍历&#xff1a;左根右 3、后序遍历&#xff1a;左右根 1、问题概述&#xff1a;二叉树中序遍历 2、示例 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a; 输入&#xff1a;root […...

MySQL数据库基本安装与部署

目录 概念 数据库的基本概念 关系型数据库 非关系型数据库 MySQL 商业版与社区版 示例 初始化MySQL 添加系统服务 概念 数据库的基本概念 数据&#xff08;Data&#xff09; 描述事物的符号记录包括数字、文字、图形、图像、声音、档案记录等以“记录”形式按统一的…...

paraFoam 运行 报错 usr/lib/x86_64-linux-gnu/libQt5Core.so 已解决

在日常项目开发中。使用ubuntu 视图开发的时候。报错 缺少 libQt5Core 核心组件&#xff01; whereis libQt5Core.so.5sudo strip --remove-section.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 完美解决&#xff0c;并且能正常打开&#xff0c;前提是&#xff0c…...

科技前沿:Llama 3.1的突破与革新

在科技的长河中&#xff0c;每一次模型的更新都是对人类智慧的致敬。今天&#xff0c;我们将聚焦于Meta公司最新发布的Llama 3.1系列模型&#xff0c;探索其在AI领域的前沿突破。 新模型的诞生 自去年以来&#xff0c;Meta公司不断推进人工智能技术的发展&#xff0c;终于在近…...

每天一个数据分析题(四百四十七)- 业务系统

业务系统往往因为系统故障、设备故障、人为失误等原因导致数据中存在异常数据&#xff0c;下列哪一项方法对于发现异常值有帮助&#xff08; &#xff09; A. 计算均值加减三倍标准差的范围 B. 梯度下降法 C. 相关性分析 D. 计算四分位距 数据分析认证考试介绍&#xff1a…...

如何保护你的网络安全?

在2024年4月&#xff0c;一次创纪录的DDoS&#xff08;分布式拒绝服务&#xff09;攻击震惊了网络世界&#xff0c;这次攻击达到每秒840百万数据包&#xff08;Mpps&#xff09;。你可能会问&#xff0c;DDoS攻击到底是什么&#xff1f;为什么它这么重要呢&#xff1f; 什么是…...

从SuperGlue到LoFTR:无检测器特征匹配是如何“卷”出来的?技术演进深度解读

从SuperGlue到LoFTR&#xff1a;无检测器特征匹配的技术革命与范式迁移 在计算机视觉领域&#xff0c;特征匹配一直是三维重建、SLAM、图像配准等任务的核心基础。传统方法如SIFT、ORB等基于手工设计的特征检测与描述算法&#xff0c;在过去二十年里主导了这一领域。然而&#…...

罚到肉疼!2026“两个细则”大考:你的风电场还在用“注定不准”的方法做预测吗?

当95%置信概率成为国家标准&#xff0c;单点预测的时代彻底终结2026年的春天&#xff0c;对于新能源发电企业而言&#xff0c;比以往任何时候都要“寒冷”。山东、四川等地新版“两个细则”正式施行&#xff0c;国家发改委“136号文”深入落地&#xff0c;新能源全面进入电力市…...

嵌入式Linux开发必备远程连接工具详解

1. 嵌入式Linux开发常用远程连接工具技术解析1.1 远程连接工具在嵌入式开发中的重要性嵌入式Linux开发过程中&#xff0c;开发人员经常需要远程访问目标设备进行调试、文件传输或系统监控。由于嵌入式设备通常资源有限且缺乏本地交互界面&#xff0c;远程连接工具成为开发流程中…...

ImageMagick安装后报错‘vcomp140.dll缺失’?手把手教你彻底解决Visual C++依赖问题

ImageMagick安装后报错‘vcomp140.dll缺失’&#xff1f;手把手教你彻底解决Visual C依赖问题 当你兴冲冲下载完ImageMagick准备大展身手时&#xff0c;命令行却突然弹出一串红色错误提示——"无法启动程序&#xff0c;因为计算机中丢失vcomp140.dll"。这种场景对于…...

ai辅助开发comfyui:让快马ai成为你构建复杂工作流的智能编程伙伴

最近在折腾ComfyUI时&#xff0c;发现构建复杂工作流特别容易卡在细节问题上。比如想同时用Canny边缘检测和Openpose控制生成效果&#xff0c;光是调试节点连接和参数就花了大半天。后来尝试用InsCode(快马)平台的AI辅助功能&#xff0c;发现能省下不少重复劳动。这里分享下用A…...

开发提效新组合:用Cursor生成代码片段,在快马一键集成与部署

最近在做一个数据整理的小工具时&#xff0c;发现了一个特别高效的工作流组合&#xff1a;先用Cursor快速生成核心代码片段&#xff0c;再用InsCode(快马)平台一键整合部署。整个过程就像搭积木一样顺畅&#xff0c;特别适合需要快速实现功能模块的场景。 需求分析 我们经常要处…...

3步释放华硕笔记本潜能:G-Helper轻量化控制工具的极致优化指南

3步释放华硕笔记本潜能&#xff1a;G-Helper轻量化控制工具的极致优化指南 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops. Control tool for ROG Zephyrus G14, G15, G16, M16, Flow X13, Flow X16, TUF, Strix, Scar and other models …...

Java AI开发避坑!

文章目录一、当"龙虾"突然发狂二、解剖这场"史诗级翻车"第一刀&#xff1a;插件生态大迁徙第二刀&#xff1a;API 接口一锅端第三刀&#xff1a;安全沙箱锁死第四刀&#xff1a;目录结构洗牌三、Java 开发者的至暗时刻WebSocket 连接闪断MCP 适配器失效技能…...

Atomics探究(四)-- atomic flag

本篇将研究atomic_flag相关函数底层汇编指令,以及与其他原子操作函数进行比较,探讨其存在的意义。 1、标准描述: 2、定义 gcc 头文件中定义如下 typedef _Atomic struct { #if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1_Bool __val; #elseunsigned char __val; #endif } at…...

算法基础篇(11)Floyd算法

Floyd算法本质是动态规划&#xff0c;用来求任意两点之间的最短路&#xff0c;也称为插点法。通过不断在两点之间加入新的点来更新最短路。1、状态表示&#xff1a;f[k][i][j]表示&#xff1a;仅仅经过1~k这些点&#xff0c;结点i走到结点j的最短路径的长度。2、状态转移方程&a…...