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/TM4C123GH6PM:在我的代码中使用"float&quot 时、结果不稳定

Guru**** 2604115 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/747027/ccs-tm4c123gh6pm-unstable-results-while-using-float-in-my-code

器件型号:TM4C123GH6PM

工具/软件:Code Composer Studio

您好!

我使用以下程序从 MPU6050传感器读取、平均值并在屏幕上打印值

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include 
#include 
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/pwm.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "inc/hw_gpio.h"
#include "#include "包含"hw_map.h"#include "#include


#include //使用 NULL 指针

#define PWM_FREQUENCY 55

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//我的 I2C 定义并包括
#include "driverlib/i2c.h"
#include "driverlib/interrv.h"
#include "inc/hw_i2c.h"
#include
"sensorlib/i2cm_drv.h"
#include "sensorlib/mpu6050.h"////

/////////////////////////////////////////////////////////////#////#//////////////////////////#//////////////////////////#///////////////////////////////////////////



//我的 UART 定义并包括
#include "driverlib/uartstdio.h"
#include "utils/uartstdio.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "definitions _mpu6050.h"

tI2CMInstance g_sI2CInst;// I2C 主驱动程序结构。 "tI2CMInstance"是在 i2cm_drv.h 文件中定义的。
tMPU6050 g_sMPU6050Inst;// MPU6050传感器驱动程序结构。 "tMPU6050"在 mpu6050.h 文件中定义。
volatile unsigned long g_vui8DataFlag;//数据就绪标志
volatile unsigned long g_vui8ErrorFlag;//错误标志

void
ISL29023I2CIntHandler (void)
{
I2CMIntHandler (&g_sI2CInst);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main (void)
{
fAccel[3]、fGyro[3]={0.0};
uint8_t register_mpu6050_o_pwr_mgmt_1;//用于调试
uint8_t register_mpu6050_o_卫生 组织_am_i;//用于调试

uint8_t 索引= 0;
uint32_t 计数器= 0;
int32_t i32IntegerPart = 0;
int32_t i32FractionPart = 0;


//配置时钟
SysCtlClockSet (SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTAL_16MHz|SYSCTL_OSC_MAIN);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//我的 I2C 初始化代码

//启用包含 I2C 2的 GPIO 外设
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);

//启用 I2C 模块2
SysCtlPeripheralEnable (SYSCTL_Periph_I2C2);

//为端口 E4和 E5上的 I2C2功能配置引脚多路复用。
GPIOPinConfigure (GPIO_PE4_I2C2SCL);
GPIOPinConfigure (GPIO_PE5_I2C2SDA);

//为这些引脚选择 I2C 功能。
GPIOPinTypeI2CSCL (GPIO_Porte _BASE、GPIO_PIN_4);
GPIOPinTypeI2C (GPIO_Porte _BASE、GPIO_PIN_5);

IntMasterEnable();

// USER_I2CMInit (&G) sI2CInst、I2C2_base、INT_I2C2、0xFF、 0xFF、SysCtlClockGet ();//将 SCL 设置为100KHz 而不是原始400kHz。
I2CMInit (&g_sI2CInst、I2C2_base、INT_I2C2、0xFF、0xFF、 SysCtlClockGet ();

SysCtlDelay (SysCtlClockGet ()/3);

//如果使用该变量的函数成功,USER_MPU6050Callback 会将 g_BMPU6050Done 变量修改为 true。

//初始化 MPU6050
G_bMPU6050Done = false;
MPU6050Init (&g_sMPU6050Inst、&g_sI2CInst、MPU6050_I2C_ADDRESS、USER_MPU6050Callback、0);
while (!g_bMPU6050Done){}
// SysCtlDelay (SysCtlClockGet ()/ 3);

G_bMPU6050Done = false;
MPU6050Read (&g_sMPU6050Inst、MPU6050_O_WH_AM_I、&register_mpu6050_o_WH_AM_I、1、USER_MPU6050Callback、0);
while (!g_bMPU6050Done){}
SysCtlDelay (SysCtlClockGet ()/3);

G_bMPU6050Done = false;
MPU6050Read (&g_sMPU6050Inst、MPU6050_O_PWR_Mgmt_1、&register_mpu6050_o_pwr_mgmt_1、1、USER_MPU6050Callback、0); //有人忘记将设备从睡眠状态中取出。
while (!g_bMPU6050Done){}
SysCtlDelay (SysCtlClockGet ()/3);

G_bMPU6050Done = false;

//写入0x01会将器件从睡眠状态唤醒、并使具有 X 轴陀螺仪基准的主时钟 PLL 变为睡眠状态。
MPU6050Write (&g_sMPU6050Inst、MPU6050_O_PWR_Mgmt_1、0x01、1、USER_MPU6050Callback、 0);
while (!g_bMPU6050Done){}
SysCtlDelay (SysCtlClockGet ()/3);

G_bMPU6050Done = false;
MPU6050Read (&g_sMPU6050Inst、MPU6050_O_PWR_Mgmt_1、&register_mpu6050_o_pwr_mgmt_1、1、USER_MPU6050Callback、0);
while (!g_bMPU6050Done){}
SysCtlDelay (SysCtlClockGet ()/3);

G_bMPU6050Done = false;
//将 MPU6050配置为+/- 4 g 加速计范围。
MPU6050ReadModifyWrite (&G) sMPU6050Inst、MPU6050_O_ACCEL_CONFIG、~MPU6050_ACCEL_CONFIG_AFS_SEL_M、MPU6050_ACCEL_CONFIG_AFS_SEL_2G、USER_MPU6050Callback、 0);
while (!g_bMPU6050Done){}
SysCtlDelay (SysCtlClockGet ()/ 3);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//我的 UART 初始化代码
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);
UARTStdioConfig (0、115200、16000000);
UARTprintf ("UART 工作正常\n");

while (1)
{
G_bMPU6050Done = false;

while (计数器< 1000000)
{
计数器++;
}
计数器= 0;

//获取新的加速计和陀螺仪读数。
// MPU6050DataAccelGetFloat (&g_sMPU6050Inst、&fAccel[0]、&fAccel[1]、&fAccel[2]);
// MPU6050DataGyroGetFloat (&G) sMPU6050Inst、&fGyro[0]、&fGyro[1]、&fGyro[2]);


SAMPLE_accumulation_average
(
&g_sMPU6050Inst、
8. 、
加速 、
fGyro
) ;

//将浮点转换为整数并通过 UART 发送

对于(index = 0;index <= 2;index ++)
{
i32IntegerPart =(int32_t) fAccel[index];
i32FractionPart =(int32_t)(fAccel[index]* 1000.0f);
i32FractionPart = i32FractionPart -(i32IntegerPart * 1000);

if (i32FractionPart < 0)
{
i32FractionPart *=-1;
}

如果(索引=0)
{
UARTprintf ("加速计 X:%3d.%03d\t\n"、i32IntegerPart、i32FractionPart);
}

如果(索引==1)
{
UARTprintf ("加速计 Y:%3d.%03d\t\n"、i32IntegerPart、i32FractionPart);
}

如果(索引==2)
{
UARTprintf ("加速计 Z:%3d.%03d\t\n"、i32IntegerPart、i32FractionPart);
}
}

对于(index = 0;index <= 2;index ++)
{
i32IntegerPart =(int32_t) fGyro[索引];
i32FractionPart =(int32_t)(fGyro[index]* 1000.0f);
i32FractionPart = i32FractionPart -(i32IntegerPart * 1000);

if (i32FractionPart < 0)
{
i32FractionPart *=-1;
}

如果(索引=0)
{
UARTprintf ("Gyro X:%3d.%03d\t\n"、i32IntegerPart、i32FractionPart);
}

如果(索引==1)
{
UARTprintf ("Gyro Y:%3d.%03d\t\n"、i32IntegerPart、i32FractionPart);
}

如果(索引==2)
{
UARTprintf ("陀螺仪 Z:%3d.%03d\t\n\n\n\n\n"、i32IntegerPart、i32FractionPart);
}
}

//清除累积值以准备新周期。
fAccel[0]= 0.0;
fAccel[1]= 0.0;
fAccel[2]= 0.0;
fGyro[0]= 0.0;
fGyro[1]=0.0;
fGyro[2]= 0.0;
}
} 

这是"SAMPLE_accumulation_averity"函数的代码

void sample_accumulation_average (tMPU6050 * g_sMPU6050Inst、int number_for_samples、float *加速计_average、float * gyro_average)//该函数作为指向3个元素的数组
的参数指针{
浮点加速计读数[3]、gyro_reading[3]={0.0};
int sample 计数器;
int axy_number;
对于(SAMPLE_COUNTER = 0;SAMPLE_COUNTER < NUMBER_OL_SAMPples;SAMPLE_COUNTER ++)
{
MPU6050DataRead (g_sMPU6050Inst、USER_MPU6050Callback、0);
while (!g_bMPU6050Done){}
MPU6050DataAccelGetFloat (g_sMPU6050Inst、&accister_reading[0]、&accister_reading[1]、&accister_reading[2]);
MPU6050DataGyroGetFloat (g_sMPU6050Inst、&gyro_reading[0]、&gyro_reading[1]、&gyro_reading[2]);
对于(AXIC_NUMBER = 0;AXIC_NUMBER < 3;AXIC_NUMBER ++)
{
加速计平均值[ AXIAL_NUMBER ]=加速计平均值[ AXIAL_NUMBER ]+加速计读数[ AXIAL_NUMBER ];//累加加速计读数
gyro_average [ axis _number ]= gyro_average [ axis _number ]+ gyro_reading [ axis _number ];//累加 gyro 读数
}
}
对于(AXIC_NUMBER = 0;AXIC_NUMBER < 3;AXIC_NUMBER ++)
{
加速计平均值[ AXIS 编号]=加速计平均值[ AXIS 编号]/ NUMBER_OW_SAples;
gyro_average [ axy_number ]= gyro_average [ axis _number ]/ number_for_samples;
}
} 

程序将运行并在屏幕上打印值。 但它对我选择平均的样本数非常敏感(上面代码中有8个)。

当我将该值设置为1 (无平均值计算)时、将显示正确的值。

当我增加该值(以引起平均值计算)时-例如、增加到8。  打印错误值。

我认为这与我使用浮点值并累加浮点值相关-可能是某种溢出。

你怎么看?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    关闭多少钱? 您能否用1到8个样本的数量显示平均值与预期值之间的关系表?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Shai、

    [引用 USER="SHai KON"]浮点加速计_读数[3]、gyro_reading[3]={0.0};[/quot]

    浮点数组值是奇数、如果 这两个值都是 i2c FIFO POP、那么 原始数据可能是16位整数?   也许 Charles 可能会解释 浮动 数组值的语法是/不是正确的、而 FPU 预制数学则是从  数组索引读取的算法变量。  编译 器调用 (float)似乎必须对 数组数据执行几个神奇的技巧。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我使用 float、因为 sensorlib MPU6050DataAccelGetFloat 和 MPU6050DataGyroGetFloat 为我提供了什么...
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我在调试这个问题上取得了一些进展。

    如果我在之间添加足够长的延迟、似乎不会发生这种情况

    while (!g_bMPU6050Done){} 

    MPU6050DataAccelGetFloat (g_sMPU6050Inst、&accister_reading[0]、&accister_reading[1]、&accister_reading[2]); 

    这是具有延迟的代码:

    void sample_accumulation_average (tMPU6050 * g_sMPU6050Inst、int number_for_samples、float *加速计_average、float * gyro_average)//该函数作为指向3个元素的数组
    的参数指针{
    浮点加速计读数[3]、gyro_reading[3]={0.0};
    int sample 计数器;
    int axy_number;
    int 计数器=0;
    对于(SAMPLE_COUNTER = 0;SAMPLE_COUNTER < NUMBER_OL_SAMPples;SAMPLE_COUNTER ++)
    {
    MPU6050DataRead (g_sMPU6050Inst、USER_MPU6050Callback、0);
    while (!g_bMPU6050Done){}
    
    而(计数器< 1000)//此延迟似乎解决了问题
    {
    计数器++;
    }
    计数器= 0;
    
    MPU6050DataAccelGetFloat (g_sMPU6050Inst、&accister_reading[0]、&accister_reading[1]、&accister_reading[2]);
    MPU6050DataGyroGetFloat (g_sMPU6050Inst、&gyro_reading[0]、&gyro_reading[1]、&gyro_reading[2]);
    对于(AXIC_NUMBER = 0;AXIC_NUMBER < 3;AXIC_NUMBER ++)
    {
    加速计平均值[ AXIAL_NUMBER ]=加速计平均值[ AXIAL_NUMBER ]+加速计读数[ AXIAL_NUMBER ];//累加加速计读数
    gyro_average [ axis _number ]= gyro_average [ axis _number ]+ gyro_reading [ axis _number ];//累加 gyro 读数
    }
    }
    对于(AXIC_NUMBER = 0;AXIC_NUMBER < 3;AXIC_NUMBER ++)
    {
    加速计平均值[ AXIS 编号]=加速计平均值[ AXIS 编号]/ NUMBER_OW_SAples;
    gyro_average [ axy_number ]= gyro_average [ axis _number ]/ number_for_samples;
    }
    } 
    您是否理解其中的原因? 
    尽管 I2C 事务完成-数据仍然未就绪,这怎么可能呢?
    我认为 I2C 功能正在阻断、直到数据就绪才会返回...
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您能否在调用 MPU6050DataAccelGetFloat 之前在 g_bMPU6050Done 上执行 UARTprintf 以查看 MPU6050是否真正完成?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    嗯...我可以-但是这种测试背后的动机是什么??
    如果 g_bMPU6050Done 为 false,则代码必须停留在 while 循环中-不打印 anything...can 在 g_bMPU6050Done 为 false 并且代码不停留在 while 循环中时,您会想到这样的情况??

    请查看 TM4C Launchpad 技术讲座中的 ISL29023传感器示例。
    www.cse.iitb.ac.in/.../TM4C123G_LaunchPad_Workshop_Workbook.pdf
    第24页
    在每个 I2C 事务之后使用函数 ISL29023AppI2CWait -也许这是一个线索...
    但是、Sensorlib PDF 中的 mpu6050示例不使用此类函数。

    你怎么看?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    在调用 MPU6050DataRead 之前、是否需要先将 g_bMPU6050Done 设置为 false? 否则、第二次调用 MPU6050DataRead 时、g_bMPU6050Done 从上次调用开始始终为 true。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    哎呀。

    错过了这个-我将添加 g_bMPU6050Done 清除 、并删除等待循环以查看问题是否得到解决。

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

    [引用 user="Shai kon"]如果我在 while (!g_bMPU6050Done){}之间添加足够长的延迟、似乎不会发生这种情况

    g_bMPU6050Done 是否定义为布尔开关? 我不知道在哪里多次被设置为 false。 如果实际上是 变量或寄存器标志、 则为逻辑(!) 可能 无法按位正常工作&(~g_bMPU6050Done)

    关于浮点数组[] 从未讨论 过能够  处理浮点整数的 C++语法数组结构。 因此    、从6050读取返回的变量(&V)可能更明智。  对我来说、这不是只从  该浮点 查询调用返回的变量的回调。 必须对 浮点变量输入 CCS 调试检查、以查看 FPU 是否实际添加了小数点、它将 显示在 鼠标悬停中。  如果没有小数点、则 float 指令不起作用。

    祝您好运!

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

    正如 Charles 所建议的、问题是 我在进行呼叫后忘记将 g_bMPU6050Done 设置为 false。  我现在工作得很好。

    我不理解您的意思:

    "关于浮点数组[] 从未讨论 过能够  处理浮点整数的 C++语法数组结构。"

    您是否建议 C 不能用于处理浮点数组??

    请详细说明。