I2C:
如果没有I2c这类总线,连接方法可能会如下图:
单片机所有的通讯协议,无非是建立在引脚(高低电平的变换+高低电平持续的时间)这二者的组合上,i2c 多了一个clock线,负责为数据传输打节拍。
(i2c 传输数据的格式--读数据)
BMP180:
BMP180是一款由德国博世(Bosch Sensortec)公司开发的高精度数字气压和温度传感器。它采用微电子机械系统(MEMS)技术,能够准确测量大气压力和温度,并具有低功耗、小尺寸、高稳定性的特点。BMP180通过I2C接口与微控制器或单片机通信,提供的气压和温度数据可用于气象观测、气候研究、天气预报、高度测量等多个领域。此外,BMP180还具有温度补偿功能,能减少温度对气压测量的影响,确保测量数据的准确性。
(接线图)
arduion 中:我们用如下这个lib:
example code:
cpp
#include <Adafruit_BMP085.h>
/***************************************************
This is an example for the BMP085 Barometric Pressure & Temp Sensor
Designed specifically to work with the Adafruit BMP085 Breakout
----> https://www.adafruit.com/products/391
These pressure and temperature sensors use I2C to communicate, 2 pins
are required to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
// Connect GND to Ground
// Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5
// Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4
// EOC is not used, it signifies an end of conversion
// XCLR is a reset pin, also not used here
Adafruit_BMP085 bmp;
void setup() {
Serial.begin(9600);
if (!bmp.begin()) {
Serial.println("Could not find a valid BMP085 sensor, check wiring!");
while (1) {}
}
}
void loop() {
Serial.print("Temperature = ");
Serial.print(bmp.readTemperature());
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bmp.readPressure());
Serial.println(" Pa");
// Calculate altitude assuming 'standard' barometric
// pressure of 1013.25 millibar = 101325 Pascal
Serial.print("Altitude = ");
Serial.print(bmp.readAltitude());
Serial.println(" meters");
Serial.print("Pressure at sealevel (calculated) = ");
Serial.print(bmp.readSealevelPressure());
Serial.println(" Pa");
// you can get a more precise measurement of altitude
// if you know the current sea level pressure which will
// vary with weather and such. If it is 1015 millibars
// that is equal to 101500 Pascals.
Serial.print("Real altitude = ");
Serial.print(bmp.readAltitude(101500));
Serial.println(" meters");
Serial.println();
delay(500);
}
代码说明:
这段代码是使用Arduino平台编写的,旨在与Adafruit的BMP085气压和温度传感器进行交互,以读取温度、压力、以及基于这些值计算出的海拔。不过,请注意,虽然代码示例中使用了Adafruit_BMP085 bmp;
来声明对象,但BMP085和BMP180在功能上是相似的,只是不同型号,且BMP085是较旧的型号。Adafruit的库通常能够很好地处理这两种传感器,但具体使用哪个型号取决于你连接的实际传感器。
下面是代码的详细解释:
初始化
-
Serial.begin(9600);
:初始化串口通信,设置波特率为9600。 -
if (!bmp.begin()) {...}
:尝试与BMP085传感器建立通信。如果bmp.begin()
返回false
(即!bmp.begin()
为true
),则表示无法找到有效的BMP085传感器,可能是接线错误或传感器未正确连接。此时,程序会打印一条错误消息并进入无限循环。
循环
在loop()
函数中,程序会不断循环执行以下操作:
-
读取温度 :使用
bmp.readTemperature()
函数读取当前温度(以摄氏度为单位),并通过串口输出。 -
读取压力 :使用
bmp.readPressure()
函数读取当前大气压力(以帕斯卡为单位),并通过串口输出。 -
计算海拔:
-
首先,使用
bmp.readAltitude()
函数计算基于当前气压和标准海平面气压(默认为101325 Pa)的海拔。注意,这个计算假设了海平面气压是一个固定值,但在实际中,它可能会因天气等因素而变化。 -
然后,通过
bmp.readAltitude(101500)
函数,可以提供一个更准确的海拔值,这要求你知道当前的海平面气压(在这个例子中为101500 Pa,即1015毫巴)。
-
-
计算海平面压力(基于当前气压和海拔) :虽然这个功能在代码中直接调用
bmp.readSealevelPressure()
似乎是为了展示或计算某个值,但实际上,这个函数的使用场景可能是在你已经有了某个地点的海拔和当前气压,想要推算出该地点在海平面的气压值。不过,在这个循环的上下文中,它可能并不是特别有用,因为我们已经有了当前的气压值。 -
延时 :
delay(500);
使得每次循环之间有500毫秒的延时,以减少串口输出的速度,使数据更易于阅读。
注意事项
-
确保你的Arduino与BMP085(或BMP180)传感器正确连接,包括电源线、地线以及I2C通信线(SCL和SDA)。
-
如果你使用的是BMP180而不是BMP085,但Adafruit库支持两者,那么代码应该能够正常工作,无需修改。
-
海拔的计算是基于气压的,而气压会受到天气、海拔等多种因素的影响,因此计算出的海拔值可能只是一个近似值。
stm32 单片机上,IIC 编程:
STM32使用I2C通讯的步骤可以归纳如下,这些步骤主要基于STM32CubeIDE或STM32CubeMX等工具进行配置,并结合HAL库函数实现通信。
- 硬件连接
-
确保STM32的I2C引脚(通常为SCL和SDA)正确连接到目标外设的相应引脚。
-
在I2C总线上添加适当的上拉电阻(通常为4.7kΩ),以确保总线在空闲时保持高电平状态。
- 配置STM32CubeIDE或STM32CubeMX
-
创建新项目:打开STM32CubeIDE或STM32CubeMX,创建一个新的项目,并选择合适的STM32微控制器型号。
-
配置I2C外设:
-
在"Pinout & Configuration"选项卡中,找到并选择I2C外设,为其分配正确的引脚(如PB6作为SCL,PB7作为SDA)。
-
在"Configuration"选项卡中,设置I2C的时钟源、时钟速率、工作模式等参数。通常,时钟速率可以根据需要设置为100kHz或400kHz。
-
- 初始化I2C外设
-
在STM32CubeIDE中,通过STM32CubeMX生成的初始化代码,使用
HAL_I2C_Init()
函数初始化I2C外设。 -
配置I2C_HandleTypeDef结构体,包括I2C实例、时钟参数、本地地址等。
- 编写通信代码
-
发送数据 :使用
HAL_I2C_Master_Transmit()
或HAL_I2C_Mem_Write()
函数向从设备发送数据。需要指定从设备地址、寄存器地址(如果需要的话)和数据。 -
接收数据 :使用
HAL_I2C_Master_Receive()
或HAL_I2C_Mem_Read()
函数从从设备接收数据。同样需要指定从设备地址、寄存器地址(如果需要的话)和数据缓冲区。
- 错误处理
- 在通信过程中,可能会遇到各种错误,如总线忙、应答失败等。使用
HAL_I2C_GetError()
函数检查错误状态,并根据需要进行处理。
示例代码
以下是一个简化的示例,展示了如何在STM32中初始化I2C外设并发送数据:
cpp
#include "stm32f4xx_hal.h"
I2C_HandleTypeDef hi2c1;
void I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000; // 400kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
void I2C_SendData(uint8_t slaveAddr, uint8_t regAddr, uint8_t data) {
HAL_I2C_Mem_Write(&hi2c1, slaveAddr << 1, regAddr, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY);
}
int main(void) {
HAL_Init();
I2C1_Init();
uint8_t slaveAddr = 0x50; // 假设的从设备地址
uint8_t regAddr = 0x00; // 寄存器地址
uint8_t data = 0xAA; // 要发送的数据
I2C_SendData(slaveAddr, regAddr, data);
// 其他代码...
}
注意 :上述代码是一个简化的示例,用于说明如何初始化I2C外设并发送数据。在实际应用中,您可能需要根据具体的硬件和需求进行调整。特别是从设备地址、寄存器地址和数据长度等参数,需要根据您连接的外设来确定。
此外,HAL_I2C_Mem_Write()
函数中的从设备地址需要左移一位(并可选地添加读写位),因为I2C协议中的地址是7位或10位的,但在发送时通常会左移一位以在最低位添加读写位(0为写,1为读)。然而,在大多数情况下,当使用HAL_I2C_Mem_Write()
和HAL_I2C_Mem_Read()
函数时,库函数已经处理了这一位的添加,因此您只需提供7位或10位的从设备地址即可(但通常需要左移一位以确保与库的期望相匹配)。如果库函数要求您提供8位地址,并且您的设备是7位地址,那么您应该手动将7位地址左移一位。如果库函数已经处理了这一点,那么您就不需要再次左移。在上述示例中,我假设了HAL_I2C_Mem_Write()
函数需要8位地址,并且已经通过左移一位来添加了读写位(尽管在这个写操作的上下文中,读写位是0)。但是,请注意,这取决于您使用的具体HAL库版本和您的STM32微控制器型号。