STM32F4-Discovery Board:在 PC 屏幕上从连接的传感器打印数据
Posted
技术标签:
【中文标题】STM32F4-Discovery Board:在 PC 屏幕上从连接的传感器打印数据【英文标题】:STM32F4-Discovery Board: Print out data from connected sensor on the PC screen 【发布时间】:2015-12-02 09:04:00 【问题描述】:我使用的 IDE 是“Keil µVision5”。
我拥有一块 STM32F429ZIT-Discovery Board(板上有一个 LCD 显示器),我连接了一个 Bosch Sensortec BNO055 9-Axis IMU。我希望它们通过 I²C 相互通信,因此我已经建立了所需的连接,如下所示:
Vin(传感器)-> 5V(发现板) GND(传感器)-> GND(发现 董事会) SDA(传感器)-> PB7(发现板) SCL(传感器)-> PB6 (探索板)我下载了 BNO055_driver,其中包含文件“bno055_support.c”(其中包含有关如何从传感器获取数据的代码示例)。
我觉得这很令人困惑。我不确切知道我需要在我的项目中包含哪些代码行。 我试过了,我还包括了一些应该与 I²C 相关的行。
我必须说我在编程和一般微控制器方面非常缺乏经验,很明显。这就像一堆我乱七八糟的代码,可能没有任何意义。请多多包涵。在这里你可以看到我尝试的代码。
到目前为止我遇到的麻烦:
#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: 块中的可执行语句后可能不会出现声明 uint8_t data = I2C_ReceiveData(I2Cx);
main.c(124): error: #268: 可执行文件后可能不会出现声明 块中的语句 uint8_t data = I2C_ReceiveData(I2Cx);
main.c(140): error: #268: 声明可能不会出现在可执行文件之后 块中的语句 uint8_t received_data(2);
main.c(140):警告:#550-D:变量“received_data”已设置但 从未使用过 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):错误:#20:标识符“power_mode”未定义 power_mode = POWER_MODE_NORMAL; /* 设置电源模式为 NORMAL*/
main.c(220):警告:#9-D:不允许嵌套注释 /************************* 开始读取原始传感器数据****************/
main.c(255):错误:#20:标识符“d_linear_accel_datax”是 未定义的comres += bno055_convert_double_linear_accel_x_msq(&d_linear_accel_datax);
main.c(256):错误:#20:标识符“d_linear_accel_datay”是 未定义的comres += bno055_convert_double_linear_accel_y_msq(&d_linear_accel_datay);
main.c(257):错误:#20:标识符“d_linear_accel_dataz”是 未定义的comres += bno055_convert_double_linear_accel_z_msq(&d_linear_accel_dataz);
main.c(258):错误:#20:标识符“d_linear_accel_xyz”未定义 comres += bno055_convert_double_linear_accel_xyz_msq(&d_linear_accel_xyz);
main.c(375):警告:#1-D:文件的最后一行以没有换行符结束
endif
“BNO055 传感器”内置传感器融合算法(将加速度计、磁力计和陀螺仪数据混合成稳定的三轴方向输出)。所以它可以输出我需要的数据。我想接收“X、Y 和 Z 线性加速度数据为 m/s2”并在计算机屏幕上打印出来。我不知道是否可以在我的 PC 屏幕上打印数据,因为我通过 USB 将 Discovery Board 连接到我的计算机。如果不能,那么也许可以在 Discovery Board 的内置 LCD 显示器上打印出来。
非常欢迎任何帮助澄清我的担忧。
【问题讨论】:
tl;dr,但是:液晶显示器显示器?提供minimal reproducible example。 SO 不是咨询网站。您有具体的问题吗? 编译错误通常与应用程序本身的细节无关——它们只是编码错误。 【参考方案1】:第一个错误是抱怨函数调用
init_I2C1();
在声明之前
uint8_t received_data[2];
一些编译器允许这样做,而其他编译器(比如你的)必须在函数中的任何可执行代码之前声明所有变量。
第二个错误属于同一类型
uint8_t data = I2C_ReceiveData(I2Cx);
但更复杂,因为您正在定义变量并使用可执行代码设置其值。你应该把两者分开
uint8_t data;
// ... more code
data = I2C_ReceiveData(I2Cx);
我不会全部介绍,大部分都是不言自明的,比如"nested comments not allowed"
。
【讨论】:
谢谢,这很有帮助,但我仍然无法弄清楚如何正确定义标识符 下一个错误类型是comres
undefined。它将某些函数的值求和,如果它们是状态位,那将是不好的,因为如果相同的状态位被添加两次,它将移动到下一个位。但是comres
可能会计算(不)成功的调用:它是无证的。它由s32 bno055_data_readout_template(void)
返回,所以s32 comres;
应该被定义但不是本地的。您将不得不查找调用的函数以了解它们的返回值的含义。我是否可以建议您一块一块地构建您的项目,而不是试图强制整个示例工作?
如何查找调用的函数以查看它们的返回值是什么?我需要寻找什么以及在哪里寻找?【参考方案2】:
我计划在接下来的几周内为这个 IMU 编写一个 STM32 Discovery 端口。在那之前,我建议从 Adafruit 提供的 Arduino 示例开始,并开始用适当的 STM32 Discovery I2C 调用替换 Arduino I2C 调用。另一方面,如果您不需要使用 Discovery 板并且只希望 IMU 与微控制器一起使用,我建议您只使用 Arduino。示例项目和库已经存在:https://github.com/adafruit/Adafruit_BNO055
【讨论】:
以上是关于STM32F4-Discovery Board:在 PC 屏幕上从连接的传感器打印数据的主要内容,如果未能解决你的问题,请参考以下文章
带有 HAL 库的 STM32F4-Discovery (STM32F429ZIT6) 上的 RS232 (UART)?
STM32F4-Discovery资料汇总 (转载自http://blog.163.com/thinki_cao/blog/static/83944875201362493134992/)
为啥我的 LED(stm32f3-discovery board)在应用延迟后不发光?