c - STM32F4-探索板: Print out data from connected sensor on the PC screen

标签 c accelerometer gyroscope i2c stm32f4discovery

我使用的 IDE 是“Keil µVision5”。

我有一个 STM32F429ZIT 探索板(它有一个 LCD 显示器),我连接了一个 Bosch Sensortec BNO055 9-Axis IMU .我希望它们通过 I²C 相互通信,因此我已经按如下方式建立了所需的连接:

  • Vin(传感器)-> 5V(探索板)
  • GND(传感器)-> GND(发现 板)
  • SDA(传感器)-> PB7(发现板)
  • SCL(传感器)-> PB6 (发现板)

我下载了 BNO055_driver,其中包含文件“bno055_support.c” '(它包含有关如何从传感器获取数据的代码示例)。

我觉得这很令人困惑。我不知道我的项目中需要包含哪些代码行。 我试过了,我还包括了一些应该与 I²C 相关的行。

我必须说,我显然在编程和微 Controller 方面非常缺乏经验。而且它就像一堆代码,我把它们拼凑在一起,可能没有任何意义。请多多包涵。在这里你可以看到我试过的代码。

到目前为止我遇到的一团糟:

#include "stm32f4xx.h"                 
#include "system_stm32f4xx.h" 
#include "stm32f4xx_i2c.h"
#include "stm32f4xx_gpio.h"
#include <stdint.h>
#include "bno055.h"
#include "stm32f4xx_rcc.h"

#define SLAVE_ADDRESS 0x29                          // BNO055 Slave Address

void init_I2C1(void){

    GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef I2C_InitStruct;

    // enable APB1 peripheral clock for I2C1
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    // enable clock for SCL and SDA pins
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    /* setup SCL and SDA pins
     * You can connect I2C1 to two different
     * pairs of pins:
     * 1. SCL on PB6 and SDA on PB7 
     * 2. SCL on PB8 and SDA on PB9
     */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // we are going to use PB6 and PB7
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;           // set pins to alternate function
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;      // set GPIO speed
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;         // set output to open drain --> the line has to be only pulled low, not driven high
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;           // enable pull up resistors
    GPIO_Init(GPIOB, &GPIO_InitStruct);                 // init GPIOB

    // Connect I2C1 pins to AF  
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); // SCL
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); // SDA

    // configure I2C1 
    I2C_InitStruct.I2C_ClockSpeed = 100000;         // 100kHz
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;         // I2C mode
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;          // own address, not relevant in master mode
    I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;       // disable acknowledge when reading (can be changed later on)
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
    I2C_Init(I2C1, &I2C_InitStruct);                // init I2C1

    // enable I2C1
    I2C_Cmd(I2C1, ENABLE);
}

/* This function issues a start condition and 
 * transmits the slave address + R/W bit
 * 
 * Parameters:
 *      I2Cx --> the I2C peripheral e.g. I2C1
 *      address --> the 7 bit slave address
 *      direction --> the tranmission direction can be:
 *                      I2C_Direction_Tranmitter for Master transmitter mode
 *                      I2C_Direction_Receiver for Master receiver
 */
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
    // wait until I2C1 is not busy anymore
    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

    // Send I2C1 START condition 
    I2C_GenerateSTART(I2Cx, ENABLE);

    // wait for I2C1 EV5 --> Slave has acknowledged start condition
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    // Send slave Address for write 
    I2C_Send7bitAddress(I2Cx, address, direction);

    /* wait for I2C1 EV6, check if 
     * either Slave has acknowledged Master transmitter or
     * Master receiver mode, depending on the transmission
     * direction
     */ 
    if(direction == I2C_Direction_Transmitter){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    }
    else if(direction == I2C_Direction_Receiver){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    }
}

/* This function transmits one byte to the slave device
 * Parameters:
 *      I2Cx --> the I2C peripheral e.g. I2C1 
 *      data --> the data byte to be transmitted
 */
void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
    I2C_SendData(I2Cx, data);
    // wait for I2C1 EV8_2 --> byte has been transmitted
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}

/* This function reads one byte from the slave device 
 * and acknowledges the byte (requests another byte)
 */
uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
    // enable acknowledge of recieved data
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    // wait until one byte has been received
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    // read data from I2C data register and return data byte
    uint8_t data = I2C_ReceiveData(I2Cx);
    return data;
}

/* This function reads one byte from the slave device
 * and doesn't acknowledge the recieved data 
 */
uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
    // disabe acknowledge of received data
    // nack also generates stop condition after last byte received
    // see reference manual for more info
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    I2C_GenerateSTOP(I2Cx, ENABLE);
    // wait until one byte has been received
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    // read data from I2C data register and return data byte
    uint8_t data = I2C_ReceiveData(I2Cx);
    return data;
}

/* This funtion issues a stop condition and therefore
 * releases the bus
 */
void I2C_stop(I2C_TypeDef* I2Cx){
    // Send I2C1 STOP Condition 
    I2C_GenerateSTOP(I2Cx, ENABLE);
}

int main(void){

    init_I2C1(); // initialize I2C peripheral

    uint8_t received_data[2];

    while(1){

        I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Transmitter); // start a transmission in Master transmitter mode
        I2C_write(I2C1, 0x20); // write one byte to the slave
        I2C_write(I2C1, 0x03); // write another byte to the slave
        I2C_stop(I2C1); // stop the transmission

        I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Receiver); // start a transmission in Master receiver mode
        received_data[0] = I2C_read_ack(I2C1); // read one byte and request another byte
        received_data[1] = I2C_read_nack(I2C1); // read one byte and don't request another byte, stop transmission
    }
}

/*----------------------------------------------------------------------------*
 *  The following functions are used for reading and writing of
 *  sensor data using I2C communication
*----------------------------------------------------------------------------*/
#ifdef  BNO055_API
/*  \Brief: The function is used as I2C bus read
 *  \Return : Status of the I2C read
 *  \param dev_addr : The device address of the sensor
 *  \param reg_addr : Address of the first register, will data is going to be read
 *  \param reg_data : This data read from the sensor, which is hold in an array
 *  \param cnt : The no of byte of data to be read
 */
s8 BNO055_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt);
/*  \Brief: The function is used as SPI bus write
 *  \Return : Status of the SPI write
 *  \param dev_addr : The device address of the sensor
 *  \param reg_addr : Address of the first register, will data is going to be written
 *  \param reg_data : It is a value hold in the array,
 *      will be used for write the value into the register
 *  \param cnt : The no of byte of data to be write
 */
s8 BNO055_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt);
/*
 * \Brief: I2C init routine
*/
s8 I2C_routine(void);
#endif
/********************End of I2C function declarations***********************/
s32 bno055_data_readout_template(void)
{
/*---------------------------------------------------------------------------*
 *********************** START INITIALIZATION ************************
 *--------------------------------------------------------------------------*/
 #ifdef BNO055_API
/*  Based on the user need configure I2C interface.
 *  It is example code to explain how to use the bno055 API*/
    I2C_routine();
 #endif
/*--------------------------------------------------------------------------*
 *  This function used to assign the value/reference of
 *  the following parameters
 *  I2C address
 *  Bus Write
 *  Bus read
 *  Chip id
 *  Page id
 *  Accel revision id
 *  Mag revision id
 *  Gyro revision id
 *  Boot loader revision id
 *  Software revision id
 *-------------------------------------------------------------------------*/
    comres = bno055_init(&bno055);

/*  For initializing the BNO sensor it is required to the operation mode
    of the sensor as NORMAL
    Normal mode can set from the register
    Page - page0
    register - 0x3E
    bit positions - 0 and 1*/
    power_mode = POWER_MODE_NORMAL; /* set the power mode as NORMAL*/
    comres += bno055_set_power_mode(power_mode);
/*--------------------------------------------------------------------------*
************************* END INITIALIZATION *************************

/************************* START READ RAW SENSOR DATA****************/

/*  Using BNO055 sensor we can read the following sensor data and
    virtual sensor data
    Sensor data:
        Accel
        Mag
        Gyro
    Virtual sensor data
        Euler
        Quaternion
        Linear acceleration
        Gravity sensor */
/*  For reading sensor raw data it is required to set the
    operation modes of the sensor
    operation mode can set from the register
    page - page0
    register - 0x3D
    bit - 0 to 3
    for sensor data read following operation mode have to set
     * SENSOR MODE
        *0x01 - OPERATION_MODE_ACCONLY
        *0x02 - OPERATION_MODE_MAGONLY
        *0x03 - OPERATION_MODE_GYRONLY
        *0x04 - OPERATION_MODE_ACCMAG
        *0x05 - OPERATION_MODE_ACCGYRO
        *0x06 - OPERATION_MODE_MAGGYRO
        *0x07 - OPERATION_MODE_AMG
        based on the user need configure the operation mode*/
    comres += bno055_set_operation_mode(OPERATION_MODE_ACCONLY);

/******************START READ CONVERTED SENSOR DATA****************/

/*  API used to read Linear acceleration data output as m/s2
    float functions also available in the BNO055 API */
    comres += bno055_convert_double_linear_accel_x_msq(&d_linear_accel_datax);
    comres += bno055_convert_double_linear_accel_y_msq(&d_linear_accel_datay);
    comres += bno055_convert_double_linear_accel_z_msq(&d_linear_accel_dataz);
    comres += bno055_convert_double_linear_accel_xyz_msq(&d_linear_accel_xyz);

/*-----------------------------------------------------------------------*
************************* START DE-INITIALIZATION ***********************
*-------------------------------------------------------------------------*/
/*  For de - initializing the BNO sensor it is required to the operation mode
    of the sensor as SUSPEND
    Suspend mode can set from the register
    Page - page0
    register - 0x3E
    bit positions - 0 and 1*/
    power_mode = POWER_MODE_SUSPEND; /* set the power mode as SUSPEND*/
    comres += bno055_set_power_mode(power_mode);

/*---------------------------------------------------------------------*
************************* END DE-INITIALIZATION **********************
*---------------------------------------------------------------------*/
return comres;
}

#ifdef  BNO055_API
/*--------------------------------------------------------------------------*
*   The following function is used to map the I2C bus read, write, delay and
*   device address with global structure bno055_t
*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*
 *  By using bno055 the following structure parameter can be accessed
 *  Bus write function pointer: BNO055_WR_FUNC_PTR
 *  Bus read function pointer: BNO055_RD_FUNC_PTR
 *  Delay function pointer: delay_msec
 *  I2C address: dev_addr
 *--------------------------------------------------------------------------*/
 s8 I2C_routine(void) {

    bno055.bus_write = BNO055_I2C_bus_write;
    bno055.bus_read = BNO055_I2C_bus_read;
    bno055.delay_msec = BNO055_delay_msek;
    bno055.dev_addr = BNO055_I2C_ADDR2;

    return BNO055_ZERO_U8X;
}

/************** I2C buffer length******/

#define I2C_BUFFER_LEN 8
#define I2C0 5
/*-------------------------------------------------------------------*
*
*   This is a sample code for read and write the data by using I2C
*   Use either I2C  based on your need
*   The device address defined in the bno055.h file
*
*-----------------------------------------------------------------------*/

/*  \Brief: The function is used as I2C bus write
 *  \Return : Status of the I2C write
 *  \param dev_addr : The device address of the sensor
 *  \param reg_addr : Address of the first register, will data is going to be written
 *  \param reg_data : It is a value hold in the array,
 *      will be used for write the value into the register
 *  \param cnt : The no of byte of data to be write
 */
s8 BNO055_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
    s32 iError = BNO055_ZERO_U8X;
    u8 array[I2C_BUFFER_LEN];
    u8 stringpos = BNO055_ZERO_U8X;
    array[BNO055_ZERO_U8X;] = reg_addr;
    for (stringpos = BNO055_ZERO_U8X; stringpos < cnt; stringpos++) {
        array[stringpos + BNO055_ONE_U8X] = *(reg_data + stringpos);
    }
    /*
    * Please take the below function as your reference for
    * write the data using I2C communication
    * "IERROR = I2C_WRITE_STRING(DEV_ADDR, ARRAY, CNT+1)"
    * add your I2C write function here
    * iError is an return value of I2C read function
    * Please select your valid return value
    * In the driver SUCCESS defined as 0
    * and FAILURE defined as -1
    * Note :
    * This is a full duplex operation,
    * The first read data is discarded, for that extra write operation
    * have to be initiated. For that cnt+1 operation done in the I2C write string function
    * For more information please refer data sheet SPI communication:
    */
    return (s8)iError;
}

 /* \Brief: The function is used as I2C bus read
 *  \Return : Status of the I2C read
 *  \param dev_addr : The device address of the sensor
 *  \param reg_addr : Address of the first register, will data is going to be read
 *  \param reg_data : This data read from the sensor, which is hold in an array
 *  \param cnt : The no of byte of data to be read
 */
s8 BNO055_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
    s32 iError = BNO055_ZERO_U8X;
    u8 array[I2C_BUFFER_LEN] = {BNO055_ZERO_U8X;};
    u8 stringpos = BNO055_ZERO_U8X;
    array[BNO055_ZERO_U8X;] = reg_addr;
    /* Please take the below function as your reference
     * for read the data using I2C communication
     * add your I2C rad function here.
     * "IERROR = I2C_WRITE_READ_STRING(DEV_ADDR, ARRAY, ARRAY, 1, CNT)"
     * iError is an return value of SPI write function
     * Please select your valid return value
     * In the driver SUCCESS defined as 0
     * and FAILURE defined as -1
     */
    for (stringpos = BNO055_ZERO_U8X; stringpos < cnt; stringpos++) {
        *(reg_data + stringpos) = array[stringpos];
    }
    return (s8)iError;
}

#endif

当我尝试编译时当然会收到错误消息:

main.c(108): error: #268: declaration may not appear after executable statement in block uint8_t data = I2C_ReceiveData(I2Cx);

main.c(124): error: #268: declaration may not appear after executable statement in block uint8_t data = I2C_ReceiveData(I2Cx);

main.c(140): error: #268: declaration may not appear after executable statement in block uint8_t received_data(2);

main.c(140): warning: #550-D: variable "received_data" was set but never used uint8_t received_data(2);

main.c(207): error: #20: identifier "comres" is undefined comres = bno055_init(&bno055);

main.c(207): error: #20: identifier "bno055" is undefined comres = bno055_init(&bno055);

main.c(215): error: #20: identifier "power_mode" is undefined
power_mode = POWER_MODE_NORMAL; /* set the power mode as NORMAL*/

main.c(220): warning: #9-D: nested comment is not allowed
/************************* START READ RAW SENSOR DATA****************/

main.c(255): error: #20: identifier "d_linear_accel_datax" is undefined comres += bno055_convert_double_linear_accel_x_msq(&d_linear_accel_datax);

main.c(256): error: #20: identifier "d_linear_accel_datay" is undefined comres += bno055_convert_double_linear_accel_y_msq(&d_linear_accel_datay);

main.c(257): error: #20: identifier "d_linear_accel_dataz" is undefined comres += bno055_convert_double_linear_accel_z_msq(&d_linear_accel_dataz);

main.c(258): error: #20: identifier "d_linear_accel_xyz" is undefined comres += bno055_convert_double_linear_accel_xyz_msq(&d_linear_accel_xyz);

main.c(375): warning: #1-D: last line of file ends without a newline

endif

“BNO055 传感器”具有传感器融合算法(将加速度计、磁力计和陀螺仪数据混合成稳定的三轴方向输出)。所以它可以输出我需要的数据。我想接收“X、Y 和 Z 线性加速度数据作为 m/s2”并将其打印在计算机屏幕上。我不知道是否可以在我的 PC 屏幕上打印出数据,因为我通过 USB 将 Discovery Board 连接到我的电脑。如果不可能,那么也许可以在探索板的内置 LCD 显示屏上将其打印出来。

非常欢迎任何澄清我的担忧的帮助。

最佳答案

第一个错误是提示函数调用

init_I2C1();

先于声明

uint8_t received_data[2];

有些编译器允许这样做,其他编译器(例如您的编译器)必须在函数中的任何可执行代码之前声明所有变量。

第二个错误属于同一类型

uint8_t data = I2C_ReceiveData(I2Cx);

但更复杂,因为您要定义变量并使用可执行代码设置其值。你应该把两者分开

uint8_t data;
// ... more code
data = I2C_ReceiveData(I2Cx);

我不会一一列举,大多数都是不言自明的,例如 “不允许嵌套注释”

关于c - STM32F4-探索板: Print out data from connected sensor on the PC screen,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32427967/

相关文章:

android - 将重力传感器、加速度计或陀螺仪事件注入(inject)正在运行的应用程序

从 C 程序更改堆栈内存

android - 如何将虚假的加速度计值发送到真实设备上的应用程序?

ios - 如何在 Swift 中获取 iPhone 当前的俯仰、偏航和横滚?

ios - 不显示加速度计/陀螺仪 View

java - 计算时差的最可靠方法

java - 我应该使用加速度计还是陀螺仪来测量 z 轴的角度

c - fwrite 和 fprintf 不能在 c 中工作

c - GCC结构变量赋值优化和PLT引用

c - 为什么#pragma pack 也会影响结构自身的对齐方式?