结课作业01. 用户空间 MPU6050 体感鼠标驱动程序

目录

一. qt界面实现

二. 虚拟设备模拟模拟鼠标实现体感鼠标

2.1 函数声明

2.2 虚拟鼠标实现

2.2.1 虚拟鼠标创建函数

2.2.2 鼠标移动函数

2.2.3 鼠标点击函数

2.3 mpu6050相关函数实现

2.3.1 i2c设备初始化

2.3.2 mpu6050寄存器写入

2.3.3 mpu6050寄存器读取

2.3.4 mpu6050初始化

2.3.5 read_accel 加速度数据获取及处理函数

2.4 按键模拟鼠标点击功能实现

2.4.1 导出export按键对应的gpio

2.4.2 将gpio方向direction设置为输入

2.4.3 读取按键gpio状态,来控制鼠标按键

2.5 资源清理函数

2.6 主函数实现(伪代码)

2.7 源代码及执行步骤


        使用uinput虚拟设备实现体感鼠标,通过用户空间 input 设备测试程序读取/dev/event*文件获取鼠标状态,鼠标移动数据能随开发板倾角运动改变。

        鼠标按键可以使用 Key_DOWN、Key_RIGHT、Key_LEFT、Key_UP 四个按键中任选两个 实现,四个按键的 GPIO 编号为 960 – 963.(本实验使用Key_RIGHT、Key_LEFT分别实现鼠标的右键和左键)

一. qt界面实现

        为了测试虚拟鼠标的功能,使用qt软件画了一个窗口,通过以下指令将 .ui文件 转换成python可执行文件。

pyuic5 -x windows_mouse.ui -o windows_mouse.py

         qt完整python代码如下

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'windows_mouse.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
# windows_mouse.pyfrom PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Form(object):def setupUi(self, Form):Form.setObjectName("Form")Form.resize(480, 272)  # 调整窗口高度以容纳新控件self.verticalLayout = QtWidgets.QVBoxLayout(Form)self.verticalLayout.setObjectName("verticalLayout")# 原有的 right 按钮和进度条self.right = QtWidgets.QPushButton(Form)self.right.setObjectName("right")self.verticalLayout.addWidget(self.right)self.progressBarRight = QtWidgets.QProgressBar(Form)self.progressBarRight.setProperty("value", 0)  # 初始值设为 0self.progressBarRight.setObjectName("progressBarRight")self.verticalLayout.addWidget(self.progressBarRight)# 新增的 left 按钮和进度条self.left = QtWidgets.QPushButton(Form)self.left.setObjectName("left")self.verticalLayout.addWidget(self.left)self.progressBarLeft = QtWidgets.QProgressBar(Form)self.progressBarLeft.setProperty("value", 0)  # 初始值设为 0self.progressBarLeft.setObjectName("progressBarLeft")self.verticalLayout.addWidget(self.progressBarLeft)self.Exit = QtWidgets.QPushButton(Form)self.Exit.setObjectName("Exit")self.verticalLayout.addWidget(self.Exit)self.retranslateUi(Form)self.Exit.clicked.connect(Form.close)# 设置 right 按钮右键菜单self.right.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)self.right.customContextMenuRequested.connect(self.right_button_clicked)# 设置 left 按钮左键点击事件self.left.clicked.connect(self.left_button_clicked)QtCore.QMetaObject.connectSlotsByName(Form)def retranslateUi(self, Form):_translate = QtCore.QCoreApplication.translateForm.setWindowTitle(_translate("Form", "Form"))self.right.setText(_translate("Form", "right"))self.left.setText(_translate("Form", "left"))self.Exit.setText(_translate("Form", "left - Exit"))def right_button_clicked(self, pos):# right 按钮右键点击事件处理if self.progressBarRight.value() == 0:self.progressBarRight.setValue(100)  # 进度条加满else:self.progressBarRight.setValue(0)  # 进度条变为 0def left_button_clicked(self):# left 按钮左键点击事件处理if self.progressBarLeft.value() == 0:self.progressBarLeft.setValue(100)  # 进度条加满else:self.progressBarLeft.setValue(0)  # 进度条变为 0if __name__ == "__main__":import sysapp = QtWidgets.QApplication(sys.argv)Form = QtWidgets.QWidget()ui = Ui_Form()ui.setupUi(Form)Form.show()sys.exit(app.exec_())

        运行python windows_mouse.py出现以下界面。其中right按键只能鼠标右键点击,left按键只能鼠标左键点击,left-Exit为鼠标左键点击的退出按键。

二. 虚拟设备模拟模拟鼠标实现体感鼠标

2.1 函数声明

        总共分为四个部分,分别是mpu6050设备初始化及信息获取、虚拟鼠标实现、gpio设备初始化及按键gpio信息获取、资源清理clean。

/* 函数声明 */
// mpu6050和i2c的初始化和功能函数
int i2c_init(const char* i2c_dev);
void mpu6050_write(int fd, uint8_t reg, uint8_t val);
void mpu6050_read(int fd, uint8_t reg, uint8_t* buf, int len);
void mpu6050_init(int fd);
void read_accel(int fd, float* accel);
// 清理
void cleanup_handler(int sig);
// 虚拟鼠标创建及移动、点击
int create_virtual_mouse(const char* dev_name);
void send_mouse_move(int fd, int dx, int dy);
int send_mouse_click(int fd, int button_code);// 按键对应鼠标点击
void set_gpio_direction(int gpio, const char *direction);
char read_gpio_value(int gpio);
void export_gpio(int gpio);
void unexport_gpio(int gpio);

2.2 虚拟鼠标实现

2.2.1 虚拟鼠标创建函数

        1. 创建虚拟鼠标需要:配置鼠标移动按键事件、初始化设备信息、提交设备配置 三个步骤。

int create_virtual_mouse(const char* dev_name) {struct uinput_user_dev uidev;int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);/* 配置基础事件类型 */    // 此处没有错误处理,代码里有// 鼠标移动事件ioctl(fd, UI_SET_EVBIT, EV_REL);ioctl(fd, UI_SET_RELBIT, REL_X);ioctl(fd, UI_SET_RELBIT, REL_Y);// 鼠标按键事件ioctl(fd, UI_SET_EVBIT, EV_KEY);ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);/* 初始化设备信息 */memset(&uidev, 0, sizeof(uidev));snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "%s", dev_name);uidev.id.bustype = BUS_USB;uidev.id.version = 4;/* 提交设备配置 */ioctl(fd, UI_DEV_SETUP, &uidev);    // 提交设备配置ioctl(fd, UI_DEV_CREATE);           // 创建设备
}

2.2.2 鼠标移动函数

void send_mouse_move(int fd, int dx, int dy) {struct input_event ev[3];struct timeval tv;gettimeofday(&tv, NULL);    // 此函数是获取时间戳// X轴移动memset(&ev[0], 0, sizeof(ev[0]));	// 初始化ev[0]的所有成员为0ev[0].type = EV_REL;ev[0].code = REL_X;ev[0].value = dx;ev[0].time = tv;// Y轴移动memset(&ev[1], 0, sizeof(ev[1]));ev[1].type = EV_REL;ev[1].code = REL_Y;ev[1].value = dy;ev[1].time = tv;// 同步事件memset(&ev[2], 0, sizeof(ev[2]));ev[2].type = EV_SYN;ev[2].code = SYN_REPORT;ev[2].value = 0;ev[2].time = tv;
}

        1. 使用到的结构体 input_event 结构体介绍

#include <linux/input.h>struct input_event {struct timeval time;  // 时间戳__u16 type;           // 事件类型__u16 code;           // 事件代码__s32 value;          // 事件值
};
变量名类型功能
timestruct timeval记录输入事件发生的时间戳,包含秒(tv_sec)和微秒(tv_usec),通常用于事件排序或性能分析
type__u16

表示输入事件的类型,如按键事件(EV_KEY)、相对位置事件(EV_REL)

、(EV_SYN)同步事件(标记批次结束)

code__u16

与 type 结合,具体化事件含义,如具体按键、轴或输入元素

EV_KEY 类型

BTN_LEFT  // 鼠标左键(0x110)、

BTN_RIGHT // 鼠标右键(0x111)、

KEY_ENTER  // 回车键(0x1c)

EV_REL 类型

REL_X  // X轴相对移动、

(0x00)REL_Y  // Y轴相对移动(0x01)、

REL_WHEEL  // 滚轮滚动(0x08)

EV_ABS 类型

ABS_X  // X轴绝对坐标、(

0x00)ABS_Y  // Y轴绝对坐标(0x01)

value__s32

表示与事件相关的具体值,含义取决于 event 的 type 和 code

EV_KEY 事件:

value = 1:按键按下

value = 0:按键释放

value = 2:按键长按(部分设备支持)

EV_REL 事件:

value = 10:X轴向右移动10像素

value = -5:Y轴向下移动5像素

EV_ABS 事件:

value = 500:触摸屏X轴坐标为500

         2. 注意:每次事件完成都要调用同步事件,将鼠标位置和按键状态更新。

2.2.3 鼠标点击函数

        和鼠标移动函数类似,只是将鼠标移动函数中的input_event结构体的参数值给鼠标按键相关的参数即可。

2.3 mpu6050相关函数实现

2.3.1 i2c设备初始化

/* I2C设备初始化 */
int i2c_init(const char* i2c_dev) {int fd = open(i2c_dev, O_RDWR);if (fd < 0) {perror("Failed to open I2C device");return -1;}// 因为ioctl的数据结构体有“从机地址”参数,所以不用单独设置从机地址return fd;
}

2.3.2 mpu6050寄存器写入

/* MPU6050寄存器写操作 */
void mpu6050_write(int fd, uint8_t reg, uint8_t val) {struct i2c_msg msg;uint8_t buf[2] = {reg, val};msg.addr  = MPU6050_ADDR;	// 设备地址msg.flags = 0;		// 写操作msg.len   = 2;		// 数据长度(寄存器地址 + 值)msg.buf   = buf;		// 数据缓冲区struct i2c_rdwr_ioctl_data ioctl_data;ioctl_data.msgs = &msg;	// 消息数组ioctl_data.nmsgs = 1;	// 消息数量if (ioctl(fd, I2C_RDWR, &ioctl_data) < 0)perror("MPU6050 write failed");
}

        1. struct i2c_rdwr_ioctl_data结构体详解

struct i2c_rdwr_ioctl_data {struct i2c_msg* msgs;  /* I2C 消息数组的指针 */int nmsgs;             /* 消息数组的元素个数 */
};
参数名类型功能
msgsstruct i2c_msg*指向一个 i2c_msg 结构体数组的指针,每个数组元素描述了一次 I2C 传输操作(消息)。
nmsgsint表示 msgs 数组中元素的个数,即要执行的 I2C 消息传输操作的次数。

        2.  struct i2c_msg结构体详解

struct i2c_msg {__u16 addr;        /* I2C从设备地址 */__u16 flags;       /* 消息标志 */__u16 len;         /* 数据缓冲区长度 */__u8 *buf;         /* 数据缓冲区指针 */
};
参数名类型功能说明
addr__u16I2C从设备地址,用于指定要通信的从设备的7位或10位地址
flags__u16消息标志,用于指定传输方向等信息,如I2C_M_RD(读取操作),flags=0(写入操作)等
len__u16要传输的数据长度,即buf数组中数据的字节数
buf__u8 *指向数据缓冲区的指针,用于存储要发送的数据或接收到的数据

2.3.3 mpu6050寄存器读取

        将 i2c_msg 的flags标志换成读取操作即可。

        注意:在读取数据之前,主设备(linux开发板)需要先指定要读取的从设备(mpu6050)寄存器地址。所以在读取数据之前需要先进行一次写入。这个写入操作的作用是将寄存器地址发送给 MPU6050,告诉它接下来要从哪个寄存器开始读取数据。

2.3.4 mpu6050初始化

/* MPU6050初始化 (关闭睡眠模式)*/
void mpu6050_init(int fd) {mpu6050_write(fd, ACCEL_CONFIG, 0x00); // ±2g量程mpu6050_write(fd, PWR_MGMT_1, 0x00);   // 退出睡眠模式usleep(100000); // 等待稳定100ms
}

2.3.5 read_accel 加速度数据获取及处理函数

        调用mpu6050_read函数读取加速度数据,并进行处理,转换为m/s²的加速度。

/* 读取加速度数据 (XYZ 三轴)*/
void read_accel(int fd, float* accel) {uint8_t buf[6];mpu6050_read(fd, ACCEL_XOUT_H, buf, 6);// 合并原始数据并转换单位int16_t raw_x = (int16_t)((buf[0] << 8) | buf[1]);	// X 轴int16_t raw_y = (int16_t)((buf[2] << 8) | buf[3]);	// Y 轴int16_t raw_z = (int16_t)((buf[4] << 8) | buf[5]);	// Z 轴// 转换为 m/s²accel[0] = (raw_x / ACCEL_SCALE_2G) * GRAVITY_CM_S2;accel[1] = (raw_y / ACCEL_SCALE_2G) * GRAVITY_CM_S2;accel[2] = (raw_z / ACCEL_SCALE_2G) * GRAVITY_CM_S2;
}

2.4 按键模拟鼠标点击功能实现

2.4.1 导出export按键对应的gpio

        还有对应的撤销导出unexport函数同理。

// 导出gpio
void export_gpio(int gpio) {FILE *fp = fopen(GPIO_EXPORT, "w");if (fp == NULL) {perror("Failed to open export file");fprintf(stderr, "Error code: %d\n", errno);exit(EXIT_FAILURE);}fprintf(fp, "%d", gpio);fclose(fp);
}

2.4.2 将gpio方向direction设置为输入

// 设置gpio方向为输入
void set_gpio_direction(int gpio, const char *direction) {char path[64];snprintf(path, sizeof(path), GPIO_DIRECTION, gpio);FILE *fp = fopen(path, "w");if (fp == NULL) {perror("Failed to open direction file");fprintf(stderr, "Error code: %d\n", errno);exit(EXIT_FAILURE);}fprintf(fp, "%s", direction);fclose(fp);
}

2.4.3 读取按键gpio状态,来控制鼠标按键

char read_gpio_value(int gpio) {char path[64];snprintf(path, sizeof(path), GPIO_VALUE, gpio);FILE *fp = fopen(path, "r");if (fp == NULL) {perror("Failed to open value file");fprintf(stderr, "Error code: %d\n", errno);exit(EXIT_FAILURE);}char value[2];fgets(value, sizeof(value), fp);fclose(fp);return value[0] == '1' ? '1' : '0';
}

2.5 资源清理函数

        销毁虚拟设备、关闭i2c、撤销导出按键gpio。

void cleanup_handler(int sig) {if (uinput_fd >= 0) {// 销毁虚拟设备ioctl(uinput_fd, UI_DEV_DESTROY);close(uinput_fd);printf("\n[Cleanup] Virtual mouse device destroyed\n");}if (i2c_fd >= 0) {  // 新增:关闭I2C设备close(i2c_fd);printf("[Cleanup] I2C device closed\n");i2c_fd = -1;     // 重置描述符}int gpios[] = {960, 961, 962, 963, 964};int num_gpios = sizeof(gpios) / sizeof(gpios[0]);for (int i = 0; i < num_gpios; i++) {unexport_gpio(gpios[i]);}printf("all gpio unexported\n");fflush(stdout); // 强制刷新标准输出exit(EXIT_SUCCESS);
}

2.6 主函数实现(伪代码)

int main() {// 1. 注册信号处理(Ctrl+C)/* 2. 创建虚拟鼠标 *//* 3. 初始化MPU6050 */// 4. 导出五个按键的gpio,并设置方向为输入while (1) {// 调整方向// 发送给虚拟鼠标使其移动// 读取当前按钮状态// 键盘左键对应鼠标左键// 键盘右键对应鼠标右键// 按键消抖}//资源清理
}

2.7 源代码及执行步骤

        源代码:用户空间MPU6050体感虚拟鼠标驱动程序资源-CSDN文库

# 代码编译 -lm 是因为使用了数学公式
gcc mpu_mouse.c -o mpu_mouse.out -lm# 功能实现1:添加需要的环境变量,屏幕和鼠标# Qt-embedded需要的环境变量
# • 指定显示设备
export QT_QPA_PLATFORM=linuxfb
# • 指定输入设备(触摸屏)
export QT_QPA_GENERIC_PLUGINS=evdevtouch:/dev/input/event0
export QWS_MOUSE_PROTO=evdevtouch:/dev/input/event0
# • 指定输入设备(鼠标)
export QT_QPA_GENERIC_PLUGINS=evdevmouse:/dev/input/event0
export QWS_MOUSE_PROTO=evdevmouse:/dev/input/event0# 功能实现2 # "&"符号是因为要放在后台运行,然后运行鼠标控制程序
python windows_mouse.py &
./mpu_mouse.c

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

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

相关文章

[Docker排查] 镜像拉取/容器启动/网络不通?Docker常见错误与解决方案

Docker&#xff0c;这个让无数开发者和运维工程师高呼“真香”的容器化技术&#xff0c;凭借其轻量、快速、可移植的特性&#xff0c;极大地简化了应用的开发、测试和部署流程。但即便是再“香”的技术&#xff0c;也难免有“闹脾气”的时候。你是不是也遇到过这样的“抓狂瞬间…

Oracle如何解决LATCH:CACHE BUFFERS CHAINS

CACHE BUFFERS CHAINS LATCH主要用于保护HASH CHAIN结构。一个CACHE BUFFERS CHAINS LATCH保护着多条HASH CHAIN。可以通过查看隐含参数_db_block_hash_latches的值或者查询vlatch_children视图获得系统中CACHE BUFFER CHAIN LATCH的数量。目前系统中CACHE BUFFER CHAIN LATCH的…

手搓四人麻将程序

一、麻将牌的表示 在麻将游戏中&#xff0c;总共有一百四十四张牌&#xff0c;这些牌被分为多个类别&#xff0c;每个类别又包含了不同的牌型。具体来说&#xff0c;麻将牌主要包括序数牌、字牌和花牌三大类。序数牌中&#xff0c;包含有万子、条子和筒子&#xff0c;每种花色…

spring cloud config更新配置

在开发微服务时&#xff0c;往往需要有开发环境、测试环境和生产环境&#xff0c;手动修改配置环境是一件很麻烦的事情&#xff0c;因此&#xff0c;这里使用spring cloud config管理配置环境。要使用spring cloud config&#xff0c;需要先在GitHub搭建一个仓库。 一、仓库搭…

MySQL 5.7 实战:JSON 字段提取、Base64 解码与引号问题全解析

一、背景与问题场景 在 MySQL 数据库中&#xff0c;存储 JSON 格式数据&#xff08;如用户行为日志、配置参数、扩展信息&#xff09;的场景日益普遍。当需要从 JSON 字段中提取特定键值&#xff08;如info&#xff09;并进行 Base64 解码时&#xff0c;常遇到以下问题&#x…

自研Rise系列之BI简单易用的大屏系统

BI系统是制作可视化大屏报表的常用工具之一&#xff0c;因其具备实时更新、综合分析多来源数据、直观展现分析结果、支持多维自助分析等特点而广受欢迎。在BI系统上设计制作可视化大屏后&#xff0c;只需接入大屏硬件即可&#xff0c;因此BI系统的选择就成了重中之重。 在可视化…

飞桨paddle import fluid报错【已解决】

跟着飞桨的安装指南安装了paddle之后 pip install paddlepaddle有一个验证&#xff1a; import paddle.fluid as fluid fluid.install check.run check()报错情况如下&#xff0c;但是我在pip list中&#xff0c;确实看到了paddle安装上了 我import paddle别的包&#xff0c…

第18天-NumPy + Pandas + Matplotlib多维度直方图

示例1:带样式的柱状图 python 复制 下载 import numpy as np import pandas as pd import matplotlib.pyplot as plt# 生成数据 df = pd.DataFrame(np.random.randint(10, 100, size=(8, 4)),columns=[Spring, Summer, Autumn, Winter],index=[2015, 2016, 2017, 2018, 20…

关于 Web 安全实践:4. 文件上传功能的风险分析与防护

定义&#xff1a;文件上传风险点是指应用程序允许用户上传文件&#xff0c;但没有严格校验上传文件的类型、内容、路径等属性&#xff0c;导致攻击者可以上传并执行恶意代码。 绕过方式&#xff1a; 前端绕过 1. 前端限制的原理 前端限制上传文件类型的常见方式有三种&#…

升级SpringBoot2到3导致的WebServices升级

背景 WebServices 是基于开放标准&#xff08;XML、SOAP、HTTP 等&#xff09;的 Web 应用程序&#xff0c;它们与其他 Web 应 用程序交互以交换数据。WebServices 可以将您现有的应用程序转换为 Web 应用程序。 老代码中有一个19年前的包&#xff0c;由于漏洞原因&#xff0c;…

Vue3中插槽, pinia的安装和使用(超详细教程)

1. 插槽 插槽是指, 将一个组件的代码片段, 引入到另一个组件。 1.1 匿名插槽 通过简单的案例来学习匿名插槽&#xff0c;案例说明&#xff0c;在父组件App.vue中导入了子组件Son1.vue&#xff0c;父组件引用子组件的位置添加了一个片段&#xff0c;比如h2标签&#xff0c;然…

【Redis】AOF日志

目录 1、背景2、工作原理3、核心配置参数4、优缺点5、AOF文件内容 1、背景 AOF&#xff08;Append Only File&#xff09;是redis提供的持久化机制之一&#xff0c;它通过记录所有修改数据库状态的写命令来实现数据库持久化。与RDB&#xff08;快照&#xff09;方式不同&#…

【HTTP】connectionRequestTimeout与connectTimeout的本质区别

今天发现有的伙伴调用第三方 httpclient 的配置中 connectTimeout 和 connectionRequestTimeout 配置的不到 1 S&#xff0c;问了一下他&#xff0c;知不知道这两个参数的意思&#xff0c;他说不知道。那我们今天就来了解一下这两个参数的区别 一、核心概念解析 1.1 connectT…

react中运行 npm run dev 报错,提示vite.config.js出现错误 @esbuild/win32-x64

在React项目中运行npm run dev时&#xff0c;如果遇到vite.config.js报错&#xff0c;提示esbuild/win32-x64在另一个平台中被使用&#xff0c;通常是由于依赖冲突或缓存问题导致的。解决方法是删除node_modules文件夹&#xff0c;并重新安装依赖。 如下图&#xff1a; 解决办…

EMQX开源版安装指南:Linux/Windows全攻略

EMQX开源版安装教程-linux/windows 因最近自己需要使用MQTT&#xff0c;需要搭建一个MQTT服务器&#xff0c;所以想到了很久以前用到的EMQX。但是当时的EMQX使用的是开源版的&#xff0c;在官网可以直接下载。而现在再次打开官网时发现怎么也找不大开源版本了&#xff0c;所以…

Python:操作Excel按行写入

Python按行写入Excel数据,5种实用方法大揭秘! 在日常的数据处理和分析工作中,我们经常需要将数据写入到Excel文件中。Python作为一门强大的编程语言,提供了多种库和方法来实现将数据按行写入Excel文件的功能。本文将详细介绍5种常见的Python按行写入Excel数据的方法,并附上…

vue3中RouterView配合KeepAlive实现组件缓存

KeepAlive组件缓存 为什么需要组件缓存代码展示缓存效果为什么不用v-if 为什么需要组件缓存 业务需求&#xff1a;一般是列表页面通过路由跳转到详情页&#xff0c;跳转回来时&#xff0c;需要列表页面展示上次展示的内容 代码展示 App.vue入口 <script setup lang"…

【JAVA】比较器Comparator与自然排序(28)

JAVA 核心知识点详细解释 Java中比较器Comparator的概念和使用方法 概念 Comparator 是 Java 中的一个函数式接口,位于 java.util 包下。它用于定义对象之间的比较规则,允许我们根据自定义的逻辑对对象进行排序。与对象的自然排序(实现 Comparable 接口)不同,Comparat…

浪潮服务器配置RAID和JBOD

目录 1 配置RAID2 设置硬盘为JBOD模式3 验证结果 1 配置RAID 进入 bios 界面 选择 “高级” - “UEFI-HII配置” 选择 raid 卡 进入 Main Menu 点击 Driver Management&#xff0c;可以查询当前硬盘 返回上一级&#xff0c;点击 Configuration Management - Create virtu…

mongodb管理工具的使用

环境&#xff1a; 远程服务器的操作系统&#xff1a;centOS stream 9; mongoDB version:8.0; 本地电脑 navicat premium 17.2 ; 宝塔上安装了mongoDB 目的&#xff1a;通过本地的navicat链接mongoDB,如何打通链接&#xff0c;分2步&#xff1a; 第一步&#xff1a;宝塔-&…