This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/EK-TM4C123GXL:连接 Tiva 至 MPU6050加速计/陀螺仪时出现问题

Guru**** 2465890 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/680730/ccs-ek-tm4c123gxl-problems-interfacing-tiva-to-mpu6050-accelerometer-gyroscope

器件型号:EK-TM4C123GXL

工具/软件:Code Composer Studio

大家好、

我尝试从 MPU6050模块读取传感器值、但有时代码会挂起(强制我对 Tiva 进行下电上电、重置是徒劳的)或读取错误的值(看起来是一致的、但不是它应该是什么)。

我已经尝试使用 Arduino、传感器与 Uno 完美配合。 我还使用3V3将传感器与 ATmega328P 连接到试验电路板上、以查看是否是导致问题的电压、但它也可以在那里工作。 因此使用3V3时没有问题。

由于 sensorlib 没有很好地解释如何从 MPU6050读取(在这里不是尝试意义上的意思、但存在一些问题、包括文件、修改 μ I²C 代码以使用 I2CM 等)、我决定使用 μ I²C 作为"传统方式"、手动从寄存器读取/写入。

以下是我的代码:

#include 
#include 
#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/interrupt.h"
#include "driverlib.rom.driverlib"
#define "driverlib_rom.ide"#define "driverlib_rom.ide"#define "driverlib_rom.ide"#define "driverlib_rom.ide"#define #include "driverlib_rom.ide"#define #include "driverlib.ide"#define "driverlib_ine.h"#include "driverlib_ine.h





0x68

volatile Int32_t g_ACXH;
volatile Int32_t g_ACXL;
volatile Int32_t g_ACX;

volatile Int32_t g_ACYH;
volatile Int32_t g_ACYL;
volatile int32_t g_acy;

volatile int32_t g_acZH;
volatile int32_t g_acZL;
volatile int32_t g_acz;

volatile int32_t g_TempH;
volatile int32_t g_temp;
volatile int32_t g_Temp;
volatile int32_t g_temperature = 0;

volatile int32_t g_g_gxH;
volatile int32_t g_g_gcxl;
volatile int32_t g_g_gcyH

;
volatile int32_t g_gcyL;
volatile int32_t g_gcyy;

volatile int32_t g_gczh;
volatile int32_t g_gczL;
volatile int32_t g_g_gcz;

//init UART 控制台波特115200
内联 void InitConsole (void)
{
//
//启用用于 UART0引脚的 GPIO 端口 A。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
MAP_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOA);
MAP_SysCtlPeripheralReset (SYSCTL_Periph_GPIOA);
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
while (!map_SysCtlPeripheralReady (SYSCTL_Periph_GPIOA));

//
//为端口 A0和 A1上的 UART0功能配置引脚复用。
//如果您的器件不支持引脚复用、则无需执行此步骤。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
MAP_GPIOPinConfigure (GPIO_PA0_U0RX);
MAP_GPIOPinConfigure (GPIO_PA1_U0TX);

//
//启用 UART0以便我们可以配置时钟。
//
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

//
//使用内部16MHz 振荡器作为 UART 时钟源。
//
MAP_UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);

//
//为这些引脚选择替代(UART)功能。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
MAP_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

//
//初始化控制台 I/O 的 UART
//
UARTStdioConfig (0、115200、16000000);
}

//main 程序
int main (void)
{
//将系统时钟设置为80MHz
MAP_SysCtlClockSet (SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHz|SYSCTL_OSC_MAIN);

//初始化 UART
InitConsole();

//清除屏幕
UARTprintf ("\033[2J");
//将光标移动到位置0,0
UARTprintf ("\033[0;0H");

//初始化 I2C0和 GPIOB
MAP_SysCtlPeripheralDisable (SYSCTL_Periph_I2C0);
MAP_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOB);
MAP_SysCtlPeripheralReset (SYSCTL_Periph_I2C0);
MAP_SysCtlPeripheralReset (SYSCTL_Periph_GPIOB);
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_I2C0);
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
while (!map_SysCtlPeripheralReady (SYSCTL_Periph_I2C0)||!map_SysCtlPeripheralReady (SYSCTL_Periph_GPIOB));

//将 PB2配置为 SCL 和 PB3 SDA
MAP_GPIOPinConfigure (GPIO_PB2_I2C0SCL);
MAP_GPIOPinConfigure (GPIO_PB3_I2C0SDA);
MAP_GPIOPinTypeI2CSCL (GPIO_PORTB_BASE、GPIO_PIN_2);
MAP_GPIOPinTypeI2C (GPIO_PORTB_BASE、GPIO_PIN_3);

///init I2C 主设备、100kbps (如果为真、则为400kbps)
MAP_I2CMasterInitExpClk (I2C0_BASE、MAP_SysCtlClockGet ()、TRUE);

//设置从器件地址,主器件正在从从器件读取(如果为 false 则写入)
MAP_I2CMasterSlaveAddrSet (I2C0_BASE、SLAVE_ADDRESS、FALSE);

//初始化 MPU
I2CMasterDataPut (I2C0_BASE、0x6B);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_SEND_START);
while (I2CMasterBusy (I2C0_BASE));

I2CMasterDataPut (I2C0_BASE、0x00);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_SEND_FINISH);
while (I2CMasterBusy (I2C0_BASE));

for (;;)
{
//请求从寄存器0x3B 读取
I2CMasterDataPut (I2C0_BASE、0x3B);
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_SINGLE_SEND);
while (I2CMasterBusy (I2C0_BASE));

//主器件正在从从器件读取数据
MAP_I2CMasterSlaveAddrSet (I2C0_BASE、SLAVE_ADDRESS、TRUE);

//开始读取寄存器
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_start);
while (I2CMasterBusy (I2C0_BASE));

//移动“较高”位
G_ACXH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_ACXL = MAP_I2CMasterDataGet (I2C0_BASE);

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_ACYH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_ACYL = MAP_I2CMasterDataGet (I2C0_BASE);

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_ACZH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_ACZL = MAP_I2CMasterDataGet (I2C0_BASE);

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_TempH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_Templ = MAP_I2CMasterDataGet (I2C0_BASE);

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_GCXH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_GCXL = MAP_I2CMasterDataGet (I2C0_BASE);

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_GCYH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_GCYL = MAP_I2CMasterDataGet (I2C0_BASE);

I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_CONT);
while (I2CMasterBusy (I2C0_BASE));

G_GCZH = MAP_I2CMasterDataGet (I2C0_BASE)<< 8;

//完成对寄存器的读取
I2CMasterControl (I2C0_BASE、I2C_MASTER_CMD_BURST_Receive_finish);
while (I2CMasterBusy (I2C0_BASE));

G_GCZL = MAP_I2CMasterDataGet (I2C0_BASE);

//将两个8位变量加入一个16位
G_ACx = g_ACXH | g_ACXL;
G_ACY = g_ACYH | g_ACYL;
G_ACZ = g_ACZH | g_ACZL;
G_Temp = g_TempH | g_Templ;
G_GCx = g_GCXH | g_GCXL;
G_GCY = g_GCYH | g_GCYL;
G_GCZ = g_GCZH | g_GCZL;

//主设备正在写入从设备
MAP_I2CMasterSlaveAddrSet (I2C0_BASE、SLAVE_ADDRESS、FALSE);

//转换为温度
g_temperature =(g_Temp/340.00f)+36.53f;

UARTprintf ("ACX:\t%d\n"、g_ACX);
UARTprintf ("ACY:\t%d\n"、g_ACY);
UARTprintf ("ACZ:\t%d\n"、g_ACZ);
UARTprintf ("温度:\t%d\n"、g_temperature);
UARTprintf ("GCX:\t%d\n"、g_GCX);
UARTprintf ("GCY:\t%d\n"、g_GCY);
UARTprintf ("GCZ:\t%d\n"、g_GCZ);

//将光标移动到位置0,0
UARTprintf ("\033[0;0H");

MAP_SysCtlDelay (MAP_SysCtlClockGet ()/3*0.01);
}
}

我在 MPU6050上进行读数所执行的步骤:

  • 已初始化 GPIO、μ I²C 和 UART
  • 已初始化 μ I²C 主机写入模式400kbps
  • 已初始化 MPU、向寄存器0x6B 写入0x00
  • 向地址0x3B 发送写入请求
  • 将 μ I²C 更改为读取模式
  • 读取寄存器并将内容放置到变量中
  • 合并了变量、使16bitvariable = 8bitvariable_H << 8 | 8bitvariable_L
  • 根据 MPU 寄存器映射第30页显示的公式计算温度  
  • 打印了变量
  • 将 μ I²C 更改为写入、向地址0x3B 发送写入请求并再次执行所有读数  

减少了挂起的东西:改变了我读取变量的方式。 我在 I2CMasterDataGet ()调用中没有在代码中的后面移动"H"寄存器上剩余的8位、而是直接移动了它。 它只是在我不在环路中插入延迟时偶尔挂起。

Arduino 输出:

Tiva 上的输出:

导致这种奇怪行为的原因是什么?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    以下某些(或多个)可能会有所帮助:

    • 如果您的从 I2C 器件允许-下拉至"更多放弃" 100Kbps (最好谨慎地开始)
    • 您是否已安装"必需"外部(~10K 上拉电阻)@ SCL 和 SDA?   (MCU 内部电阻超过50K -不建议这样做)
    • 示波器电容-尤其是显示2个或2个左右的"成功读取数据"-后跟 "不成功读取数据"-每个"CAP"都" 尽可能"(启用宽松识别) -应突出显示差异-是否不是这样?
    • 您在每个 MCU 板和从器件之间的"电缆/电线连接"是否相同?  您必须"尽量减少任何/所有可控制的差异"。   使用(相同)电缆。
    • 此问题是否会在第二个"123 LPAD"中继续出现?   只测试一个电路板-这可能有缺陷-"旋转您的轮子"-以及无电帮助的电路板
    • 示波器盖-"品牌 A"下的"传感器 I2C 引脚处"和"123将会有所帮助
    • 请描述电源-在"brand A"(品牌 A)下、然后在"123"下-可能会导致"临界电压/电流"导致您陷入困境?   假设没有任何变化。
    • 删除在123板上运行的"任何其他代码"。  (包括 UART 代码-如果可能... UART 经常"吃"-在这种情况下始终可疑)

    实际测量-需要电流(今天/明天)测量!  (对您"相信"的衡量标准(过去几个月)是不可接受的、这对您的帮助者来说是不公平的 crüe!)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    目前、我的选项有限、但我将尝试至少借用另一个 Launchpad。

    下降到100Kbps 没有什么变化。 MPU 模块包括一个2.2k Ω 上拉电阻。 我使用的电缆始终是相同的、因此无需担心。

    sigh...如果我只使用示波器...但我购买了逻辑分析仪(eBay 上基于8050 MCU 的 Cheapos)、我希望将来它会很有用。 唯一让我感到疯狂的是我们在巴西的这种荒谬、缓慢和低质量的邮政服务。 在有时间时、还会尝试在大学的示波器上进行读数。

    电源是由我的 PC 提供的 USB (USB2.0端口)。 禁用 UART 并在 CCS 调试部分进行验证、但值仍然为奇数。。。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 user="Helder Sales">尝试读取传感器值... 但 有时代码会挂起[/quot]

    您(快速)注意-"位速率降低75%、"无变化"-在您提供的情况下 (有时)、您的评论是"意外!"   最常出现的问题-当问题发生时(有时)、问题会显示为 "与时间相关"。   我不知道您如何"测试/验证"您的问题(如此快速)-当故障被描述为仅发生时(有时!)   

    您在描述电缆互连时使用的语言 ("始终相同 电缆")并不清楚地注意从 工作系统中卸下的"相同或相同电缆"(奇异)的使用以及 (然后)连接到您的'123板。  电缆是导致许多系统故障/或间歇性操作的原因、这就是"消除电缆变量"证明如此重要的原因。

    您的示波器捕获-尽可能重复-然后以整齐(精确) 的"垂直偏移"呈现在这里-然而(否则) "叠加和对齐" 的方式-显示(成功和失败)-将证明是非常有价值的。   (请注意、"精确度尝试"-在上一句中、您的分析和报告构成-必须努力实现其相同...)

    您是否曾尝试在命令写入之间向您的传感器强制执行更多延迟?   怀疑您的 ARM 在较小的 MCU 周围"运行响铃"-并可能违反传感器的"所需设置时间"。  您添加延迟(几乎无处不在)而不愉快-可能会证明是有洞察力的。

    各种串行接口提供的更少互连功能非常引人注目、但确实会迫使您根据"测试和诊断"提出更高的需求。

    减去那些整齐覆盖的电容器-相对示波器电容器-我们的"辅助候选器"是"在黑暗中"-并且诊断有限...

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 user="CB1_MOBIST"]最常-当问题发生时(有时)、问题会显示为 "与计时相关"。   我不知道您如何"测试/验证"您的问题(如此快速)-当故障被描述为仅发生(有时!)

    多次复位 Tiva 有时会让我挂起(为了纠正这一点、只对电路板进行下电上电)。 当问题经常出现时、我会尝试将其视为"与计时有关"的问题、这是您给我的一个很好的提示。

    [引用 user="CB1_MOBIT)]您在描述电缆互连时使用的语言 ("始终相同      电缆")并不清楚地注意 从工作系统中移除的"相同或相同电缆"(奇异电缆)的使用 - 以及 (然后)连接到您的'123 板。  电缆 是导致许多系统故障 和 /或间歇性操作 的原因、这就是"消除电缆变量证明如此重要的原因。[/引述]

    很抱歉、我想说同一根电缆。 一封信改变了一切吗?

    [报价 USER="CB1_MOBILE]]您是否曾尝试在命令写入之间向传感器强制执行更多延迟?   怀疑您的 ARM 在较小的 MCU 周围"运行响铃"-并可能违反传感器的"所需设置时间"。  您添加了延迟(几乎无处不在)、但却感到不愉快-可能会证明是有洞察力的。

    这实际上使这些宿醉消失了(谢谢!)。   我想 I2CMasterBusy()调用还不够,因此需要在这方面做更多的研究 I²C。 不确定如何确定所需的最短时间(由于数据表中说它支持100/400Kbps、我假设我不需要插入一些延迟)。

    [引用 user="CB1_MOBIST"] 根据       您的"测试和诊断"、由各种串行接口提供的简化互连功能非常引人注目、但确实会强制要求更高。[/quot]

    是的、一切都要付出代价。 此外,就价格而言,这些模块很脏很便宜,所以我买了它们(我知道有时最便宜的东西不是最好的,但我被强迫买便宜的便宜货)。

    至于读数,问题是  I2CMasterDataGet () 返回一个无符号整数。 即使我放入有符号整数、我也需要再次将其转换为有符号值。 完全错过了这一点、因为我根据使用 PCF8074A 中学到的知识进行了编码、当时我没有使用带符号的 INT。 我只想了解为什么我应该再次进行转换、这看起来很奇怪(与 UART 在有符号整型中打印65000一样的模式)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 user="Helder Sales"[报价用户="Helder Sales]"、这实际上使停机时间变了(谢谢!)。 我想  I2CMasterBusy () 调用 不够

    您可以通过查看"I2CMasterBusy"呈现的源代码来受益、并查看它是否是来自从器件的"测试正确的响应"。   如果不是、则可能是从属设备正在出现、"提示输入数据"、并且不能始终"满足您的需求"。

    许多人对您使用该传感器的情况很好奇。   据报道, "伊帕内马的女孩"(身高高、可爱)被(反复)"嗡嗡"。  (也许是您的无人机-与 MPU6050摔跤?)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗯、展示它会很有趣! 也许有一天我会把它用在无人机上、用于"科学"!

    满足您(和读者)的好奇心、这些将(希望)应用于小型 Baja 原型、作为一些大学扩展项目的一部分。

    我计划使用这些传感器中的一小部分。 4其中、我希望从悬浮液中获得一些影响数据、也许更多的是陀螺仪。 其中一个将测量位于后部的应力杆的横向加速度。 最后、我将测量发动机怠速时先导座椅的振动(被要求阅读此内容以评估先导舒适性...)。

    为什么我选择使用 MPU6050而不使用 ADXL335或另一种? 嗯、对于 eBay 上的1美元传感器(也集成了陀螺仪)、不能说不了、尤其是在资金较低的情况下。

    奖励-以下是我们最近两款原型车辆的一些照片、我参加了由汽车工程师学会(SAE)举办的两场比赛:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    这里的一些人(从不是莫伊人)可能不得不"重新考虑"他们的感觉、即您"飞越"伊帕内马的海滩-寻找"自然奇观"。 (真实故事——我在20英尺的巴西“亚得里亚纳利马”中——在“芝加哥市中心”活动中,“失去了言语的力量”(比正常情况“更”)——甚至在20英尺的距离……)

    虽然我"理解"成本下降"的"拉动"-许多此类电子设备-如您所描述的那样来源-是"谬误"和/或甚至是"假冒"-但价格本身确实会带来高风险(有时非常高)。