【ESP32 idf 硬件I2C驱动MPU6050获取六轴数值】

目录

  • I2C
    • 介绍
    • 配置
    • 安装驱动
    • 通信
      • 创建&删除命令链接容器
      • 起始时序
      • 写数据
      • 读数据
      • 结束时序
      • 开始命令
  • mpu6050 硬件i2c驱动代码&调试
    • 代码
    • 调试

I2C

介绍

介绍部分可以看我写的【ESP32 idf 软件模拟I2C驱动MPU6050实现六轴加速度的获取】,这个是使用软件模拟的I2C时序从而实现的,这次是硬件idf实现。

在这里插入图片描述
步骤:

在这里插入图片描述
在这里插入图片描述

配置

在这里插入图片描述
在这里插入图片描述

代码:

    uint8_t res;i2c_config_t i2c_config_InitStructure;i2c_config_InitStructure.clk_flags = 0; // 采用默认时钟i2c_config_InitStructure.master.clk_speed = 50000; // 通信速度 分为标准速度100kbps和快速400kbps,这里用50kbps即可i2c_config_InitStructure.mode = I2C_MODE_MASTER; // 主机模式i2c_config_InitStructure.scl_io_num = MPU6050_SCL_Pin; // 通信引脚,scli2c_config_InitStructure.scl_pullup_en = GPIO_PULLUP_ENABLE; // scl 上拉使能i2c_config_InitStructure.sda_io_num = MPU6050_SDA_Pin; // sda引脚i2c_config_InitStructure.sda_pullup_en = GPIO_PULLUP_ENABLE; // sda 上拉使能res = i2c_param_config(i2c_port, &i2c_config_InitStructure);//配置参数if (res == ESP_OK) {ESP_LOGI(TAG, "i2c_param_config success");} else {ESP_LOGE(TAG, "i2c_param_config failed with error: %d", res);}

安装驱动

在这里插入图片描述
代码

    res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, 0, 0, 0); // 安装驱动if (res == ESP_OK) {ESP_LOGI(TAG, "i2c_driver_install success");} else {ESP_LOGE(TAG, "i2c_driver_install failed with error: %d", res);}

参数一选择I2C资源,和上面配置的保持一致。

参数二选择主从模式。

如果是主机的话,后三个的参数都可以不需要,塞个0即可。

通信

在这里插入图片描述
在这里插入图片描述

创建&删除命令链接容器

在这里插入图片描述
删除命令容器可以减少资源浪费。

起始时序

在这里插入图片描述

写数据

写数据有以下两种方式,当然了,都是主模式使用的。
区别在于第一个函数是写一个Byte,而第二个函数可以写多个Byte。
在这里插入图片描述

读数据

在这里插入图片描述

结束时序

在这里插入图片描述

开始命令

既然上面的容器配置好了,必然需要开启该容器
在这里插入图片描述

mpu6050 硬件i2c驱动代码&调试

代码

MPU6050.c

/** @Author: i want to 舞动乾坤* @Date: 2024-07-26 08:52:56* @LastEditors: i want to 舞动乾坤* @LastEditTime: 2024-07-26 16:42:29* @FilePath: \i2c_hardware_driver_mpu6050\main\MPU6050.c* @Description: * * Copyright (c) 2024 by i want to 舞动乾坤, All Rights Reserved. */#include <stdint.h>
#include "MPU6050_REG.h"
#include <driver/i2c.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>#define MPU6050_Address 0x68 // MPU6050 的 7 位地址
#define MPU6050_SCL_Pin GPIO_NUM_22
#define MPU6050_SDA_Pin GPIO_NUM_21
#define i2c_port I2C_NUM_0static const char* TAG = "MPU6050";/*** @description: MPU6050写寄存器* @param {uint8_t} RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述* @param {uint8_t} Data 要写入寄存器的数据,范围:0x00~0xFF* @tip:设备地址通常是一个 7 位地址。当在软件中使用该地址时,通常需要将其左移一位(即乘以 2)以适应 I2C 总线传输格式。具体来说:I2C 总线上的设备地址总共是 8 位:前 7 位是设备的地址。第 8 位(最低位)是读/写位(R/W),用于指示这次操作是读还是写。0 表示写操作(I2C_MASTER_WRITE)。1 表示读操作(I2C_MASTER_READ)。所以,当你指定设备地址时,需要将其左移一位,并将读/写位添加到最低位。例如,对于一个 7 位设备地址 0x68:写操作:地址为 0x68 << 1 | I2C_MASTER_WRITE,即 0xD0。读操作:地址为 0x68 << 1 | I2C_MASTER_READ,即 0xD1。这是为什么需要左移一位的原因。* @return {*}无*/
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{uint8_t res;i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 创建链接,装载容器i2c_master_start(cmd); // 产生起始信号i2c_master_write_byte(cmd, (MPU6050_Address << 1) | I2C_MASTER_WRITE, true); // 发送从机地址,并产生应答i2c_master_write_byte(cmd, RegAddress, true); // 发送从机数据寄存器的地址,并产生应答i2c_master_write_byte(cmd, Data, true); // 写入数据 并产生应答i2c_master_stop(cmd); // 产生停止信号res = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_PERIOD_MS); // 启动容器,开始工作i2c_cmd_link_delete(cmd); // 删除链接容器,避免占用资源if (res == ESP_OK) {ESP_LOGI(TAG, "MPU6050_WriteReg success - RegAddress: 0x%02X, Data: 0x%02X", RegAddress, Data);} else {ESP_LOGE(TAG, "MPU6050_WriteReg failed with error: %d - RegAddress: 0x%02X, Data: 0x%02X", res, RegAddress, Data);}
}/*** @description: 读寄存器的数据* * @param {uint8_t} RegAddress  寄存器地址,范围:参考MPU6050手册的寄存器描述* @return {*}读取寄存器的数据,范围:0x00~0xFF*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data = 0;uint8_t res;i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 创建链接,装载容器i2c_master_start(cmd); // 产生起始信号i2c_master_write_byte(cmd, (MPU6050_Address << 1) | I2C_MASTER_WRITE, true); // 发送从机地址,并产生应答i2c_master_write_byte(cmd, RegAddress, true); // 发送从机数据寄存器的地址,并产生应答// 开始在该寄存器下读数据i2c_master_start(cmd); // 产生起始信号i2c_master_write_byte(cmd, (MPU6050_Address << 1) | I2C_MASTER_READ, true); // 发送从机地址,读写位为1,表示即将读取,并产生应答i2c_master_read_byte(cmd, &Data, I2C_MASTER_LAST_NACK); // 读一个字节的数据至Data内,并且非应答i2c_master_stop(cmd); // 发送停止信号res = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_PERIOD_MS); // 启动容器,开始工作i2c_cmd_link_delete(cmd); // 删除链接,保证资源不会被一直占用if (res == ESP_OK) {ESP_LOGI(TAG, "MPU6050_ReadReg success - RegAddress: 0x%02X, Data: 0x%02X", RegAddress, Data);} else {ESP_LOGE(TAG, "MPU6050_ReadReg failed with error: %d - RegAddress: 0x%02X, retrying...", res, RegAddress);vTaskDelay(10 / portTICK_PERIOD_MS); // 延迟10ms后重试}return Data;
}/*** @description: MPU5050初始化* @return {*}无*/
void MPU6050_Init(void)
{uint8_t res;i2c_config_t i2c_config_InitStructure;i2c_config_InitStructure.clk_flags = 0; // 采用默认时钟i2c_config_InitStructure.master.clk_speed = 50000; // 通信速度 分为标准速度100kbps和快速400kbps,这里用标准速度即可i2c_config_InitStructure.mode = I2C_MODE_MASTER; // 主机模式i2c_config_InitStructure.scl_io_num = MPU6050_SCL_Pin; // 通信引脚,scli2c_config_InitStructure.scl_pullup_en = GPIO_PULLUP_ENABLE; // scl 上拉使能i2c_config_InitStructure.sda_io_num = MPU6050_SDA_Pin; // sda引脚i2c_config_InitStructure.sda_pullup_en = GPIO_PULLUP_ENABLE; // sda 上拉使能res = i2c_param_config(i2c_port, &i2c_config_InitStructure);//配置参数if (res == ESP_OK) {ESP_LOGI(TAG, "i2c_param_config success");} else {ESP_LOGE(TAG, "i2c_param_config failed with error: %d", res);}res = i2c_driver_install(i2c_port, I2C_MODE_MASTER, 0, 0, 0); // 安装驱动if (res == ESP_OK) {ESP_LOGI(TAG, "i2c_driver_install success");} else {ESP_LOGE(TAG, "i2c_driver_install failed with error: %d", res);}MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); // 唤醒mpu6050MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); // 10分频MPU6050_WriteReg(MPU6050_CONFIG, 0x06); // 数字低通滤波器MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); // 陀螺仪寄存器MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); // 加速度寄存器 最大量程
}/*** 函    数:MPU6050获取ID号* 参    数:无* 返 回 值:MPU6050的ID号*/
uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);}/*** 函    数:MPU6050获取数据* 参    数:AccX AccY AccZ 加速度计X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767* 参    数:GyroX GyroY GyroZ 陀螺仪X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767* 返 回 值:无* 具体选择转的角速度是多少 是通过比例公式计算出来的  读取的数据/32768  =  x /满量程  求x*/
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{uint8_t DataH,DataL;//读取加速度x轴寄存器的高八位DataH=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//读取加速度x轴寄存器的低八位DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX=(DataH<<8) | DataL;//读取//读取加速度y轴寄存器的高八位DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);//读取加速度y轴寄存器的低八位DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY=(DataH<<8) | DataL;  //返回出去//读取加速度z轴寄存器的高八位DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//读取加速度z轴寄存器的低八位       DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ=(DataH<<8) | DataL;  //返回出去//读取加速度z轴寄存器的高八位DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//读取加速度z轴寄存器的低八位       DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ=(DataH<<8) | DataL;  //返回出去DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);		//读取陀螺仪X轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);		//读取陀螺仪X轴的低8位数据*GyroX = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);		//读取陀螺仪Y轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);		//读取陀螺仪Y轴的低8位数据*GyroY = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);		//读取陀螺仪Z轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);		//读取陀螺仪Z轴的低8位数据*GyroZ = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回
}

MPU6050.h

#ifndef __MPU6050_H__
#define __MPU6050_H__
void MPU6050_Init(void);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);
uint8_t MPU6050_GetID(void);#endif

MPU6050_REG.h

#ifndef __MPU6050_REG_H__
#define __MPU6050_REG_H__
//存放MPU6050常用的寄存器地址
#define	MPU6050_SMPLRT_DIV		0x19   //分频值,值越小越快
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48#define	MPU6050_PWR_MGMT_1		0x6B
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75#endif

main.c

/** @Author: i want to 舞动乾坤* @Date: 2024-07-25 21:29:11* @LastEditors: i want to 舞动乾坤* @LastEditTime: 2024-07-26 09:26:14* @FilePath: \i2c_hardware_driver_mpu6050\main\main.c* @Description: * * Copyright (c) 2024 by i want to 舞动乾坤, All Rights Reserved. */
#include <stdio.h>
#include "MPU6050.h"
#include <esp_log.h>
#include <freeRtos/FreeRTOS.h>
#include <freeRtos/task.h>
uint8_t ID;								//定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ;			//定义用于存放各个数据的变量
void app_main(void)
{MPU6050_Init();ID=MPU6050_GetID();//获取设备IDESP_LOGI("MPU6050 ID","#%x\n",ID);while(1){MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);//把六个变量的地址传递过去//显示六元组数据ESP_LOGI("AX value is","%d\n",AX);ESP_LOGI("AY value is","%d\n",AY);ESP_LOGI("AZ value is","%d\n",AZ);ESP_LOGI("GX value is","%d\n",GX);ESP_LOGI("GY value is","%d\n",GY);ESP_LOGI("GZ value is","%d\n",GZ);vTaskDelay(1000/portTICK_PERIOD_MS);//1000ms获取一次}
}

调试

在这里插入图片描述
参考大佬文章:【快速上手ESP32(基于ESP-IDF&VSCode)】

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

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

相关文章

python在类中手动定义标准化输出函数

在深度学习等训练框架中&#xff0c;有时候需要对模型的名称、参数量、训练进度、中间结果等进行标准化输出&#xff0c;从而方便实时查看代码运行情况&#xff0c;这时&#xff0c;可以在类中手动定义如下标准化的输出函数&#xff0c;然后在需要输出的地方进行调用即可。 首…

鸿蒙北向开发 DevEco Studio 4.1 下载安装傻瓜式教程

开篇 由于鸿蒙处于快速发展中,鸿蒙的api快速迭代更新,老版本的DevEco studio无法支持更新版本的api,因此华为官网放弃了老版本的维护.直接从华为开发者官网无法下载老版本,当前华为开发者官网已经推出next版本了 DevEco studio3.1安装教程 上述教程提供的华为开发者官网地址已经…

linux怎么创建python

第一步&#xff0c;创建一个test文件夹。 第二步&#xff0c;打开终端进入该文件。 第三步&#xff0c;vim test.py。 第四步&#xff0c;编写代码。 第五步&#xff0c;编辑好之后&#xff0c;按Esc键切换到命令模式&#xff0c;然后输入:wq&#xff0c;再按回车键即可自动保存…

探索 SPL-404 协议标准:NFT 与 DeFi 的融合

在快速发展的数字资产领域中&#xff0c;NFT 协议标准持续演变&#xff0c;改变了我们对数字所有权和互动方式的理解。从 Art 到 Gamefi 等等&#xff0c;NFT 已经演变成数字经济的重要组成部分&#xff0c;吸引了广泛关注。遵循 ERC404 协议&#xff0c;SPL404 概念在 Solana …

AvaloniaUI的学习

相关网站 github:https://github.com/AvaloniaUI/Avalonia 官方中文文档&#xff1a;https://docs.avaloniaui.net/zh-Hans/docs/welcome IDE选择 VS2022VSCodeRider 以上三种我都尝试过&#xff0c;体验Rider最好。VS2022的提示功能不好&#xff0c;VSCode太慢&#xff0c…

flex/lex使用和学习

flex/lex用于生成解析配置文件的C代码&#xff0c;我们可以不用自己手动去做解析的工作&#xff0c;交由他们生成的代码去做。 假设&#xff0c;我有如下一个配置文件config.xml 配置文件中定义了三种channel,分别为SSIF, IPMB, NET&#xff0c;每一种channel都有4个int属性&a…

生成式AI:对话系统(Chat)与自主代理(Agent)的和谐共舞

生成式AI&#xff1a;对话与行动的和谐共舞 我们正站在一个令人激动的时代门槛上——生成式AI技术飞速发展&#xff0c;带来了无限的可能性。一个关键问题浮现&#xff1a;AI的未来是对话系统&#xff08;Chat&#xff09;的天下&#xff0c;还是自主代理&#xff08;Agent&am…

实时同步:使用 Canal 和 Kafka 解决 MySQL 与缓存的数据一致性问题

目录 1. 准备工作 2. 将需要缓存的数据存储 Redis 3. 监听 canal 存储在 Kafka Topic 中数据 1. 准备工作 1. 开启并配置MySQL的 BinLog&#xff08;MySQL 8.0 默认开启&#xff09; 修改配置&#xff1a;C:\ProgramData\MySQL\MySQL Server 8.0\my.ini log-bin"HELO…

【Git】merge合并分支

两个分支未修改同一个文件的同一处位置: Git自动合并 两个分支修改了同一个文件的同一处位置:产生冲突 例&#xff1a; 在master分支修改了main同时&#xff0c;feat分支也修改了相同的文件 合并的时候就会产生冲突 解决方法: Step1- 手工修改冲突文件&#xff0c;合并冲突内容…

立仪光谱共焦传感器应用测量之:汽车连接器高度差测量

01 检测要求&#xff0c;要求测量汽车连接器的高度差 02 检测方式 根据观察&#xff0c;我们采用立仪科技光谱共焦H4UC控制器搭配D65A52系列镜头&#xff0c;角度最大&#xff0c;外径最大&#xff0c;量程大&#xff0c;可以有效应用于测量弧面&#xff0c;大角度面等零件。 0…

会员信息管理系统-计算机毕业设计源码38258

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3开发技术 1.3.1 Spring Boot框架 1.3.2 Java语言 1.3.3 MySQL数据库 1.4论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 登录流程 2.2.2数据删除流程 2.3 系统功能分析 2.4 系统用例分析…

视频去水印免费电脑版 pdf压缩在线免费网页版 pdf压缩在线免费 简单工具软件详细方法步骤分享

消除视频中的恼人水印&#xff0c;是许多视频编辑爱好者的常见需求。在这篇文章中&#xff0c;我们将探讨几种视频去水印的技巧&#xff0c;在数字化时代&#xff0c;视频和图片的传播越来越方便&#xff0c;但随之而来的水印问题也让人头疼。本文将为您详细介绍视频剪辑去水印…

Web开发:ASP.NET CORE中前端使用Ajax定时获取后端数据

一、低难度&#xff08;刷新a标签&#xff09; 1、需求 给a标签每15s刷新一次&#xff0c;显示最新的时间&#xff08;时间必须由后端获取&#xff09; 应该如何操作呢 2、代码 后端 using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Mi…

医疗器械维修行业发展及趋势

医疗器械维修的前景是广阔的。‌ 随着医疗技术的不断发展和进步&#xff0c;‌医疗器械的种类和数量持续增加&#xff0c;‌对专业维修人员的需求也在不断上升。‌无论是医院、‌诊所等医疗机构&#xff0c;‌还是医疗器械生产企业、‌销售企业等&#xff0c;‌都需要专业的维修…

System.identityHashCode(Object obj) 和 obj.hashCode() 的区别

System.identityHashCode(Object obj) 和 obj.hashCode() 都用于获取对象的哈希码&#xff0c;但它们有显著的区别&#xff1a; System.identityHashCode(Object obj): 返回对象的默认哈希码&#xff0c;这个哈希码是基于对象的内存地址生成的&#xff0c;而不受对象的 hashC…

快速入门了解Ajax

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Ajax的初识 意义&#xff1a;AJAX&#xff08;Asynchronous JavaScript and…

leetcode-79. 单词搜索

题目描述 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相…

Linux安装TrueNAS(网络附加存储)教程 –第1部分

TrueNAS CORE&#xff08;原名FreeNAS&#xff09;是一款流行的存储系统&#xff0c;可帮助您构建自己的高质量存储设置&#xff0c;而无需支付软件费用。您可以将其安装在计算机硬件或虚拟机 (VM) 上&#xff0c;以获得开源存储的好处。 您可以在家中、办公室或数据中心使用T…

个性化音频生成GPT-SoVits部署使用和API调用

一、训练自己的音色模型步骤 1、准备好要训练的数据&#xff0c;放在Data文件夹中&#xff0c;按照文件模板中的结构进行存放数据 2、双击打开go-webui.bat文件&#xff0c;等待页面跳转 3、页面打开后&#xff0c;开始训练自己的模型 &#xff08;1&#xff09;、人声伴奏分…

RV1126 Linux 系统,接外设,时好时坏(一)应该从哪些方面排查问题

在 Linux 系统中接外设时,遇到“时好时坏”的问题,可能是由多种因素引起的。以下是一些排查问题的建议。 1. 硬件方面的排查 1.1 连接检查 物理连接: 确保外设与主板之间的连接良好,检查插头、插座及线缆是否牢固。引脚配置: 确认设备树中引脚的配置是否正确,尤其是引脚…