This commit is contained in:
2026-02-09 16:36:29 +01:00
parent af9e0c11e0
commit 0f50ddbae3
18 changed files with 610 additions and 293 deletions

View File

@@ -1,5 +1,4 @@
#include "scd30.h"
#include "driver/i2c_master.h"
#include <string.h>
#include <stdio.h>
@@ -26,14 +25,29 @@ static uint8_t calculate_crc8(const uint8_t *data, size_t len) {
return crc;
}
void scd30_init(void) {
i2c_master_config_t i2c_config = {
scd30_handle_t *scd30_init(int sda_gpio, int scl_gpio) {
static scd30_handle_t handle;
i2c_master_bus_config_t bus_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_NUM_0,
.scl_io_num = scl_gpio,
.sda_io_num = sda_gpio,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true
};
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &handle.bus_handle));
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = SCD30_I2C_ADDRESS,
.scl_speed_hz = 100000,
.scl_wait_us = 150000 // Clock stretching
};
i2c_master_init(I2C_NUM_0, &i2c_config);
ESP_ERROR_CHECK(i2c_master_bus_add_device(handle.bus_handle, &dev_cfg, &handle.dev_handle));
return &handle;
}
void scd30_start_measurement(void) {
void scd30_start_measurement(scd30_handle_t *handle) {
uint8_t command[5] = {
(SCD30_CMD_START_MEASUREMENT >> 8) & 0xFF,
SCD30_CMD_START_MEASUREMENT & 0xFF,
@@ -41,11 +55,18 @@ void scd30_start_measurement(void) {
0x00 // Placeholder for CRC
};
command[4] = calculate_crc8(&command[2], 2);
i2c_master_write_to_device(I2C_NUM_0, SCD30_I2C_ADDRESS, command, sizeof(command), 1000 / portTICK_PERIOD_MS);
i2c_master_transmit(handle->dev_handle, command, sizeof(command), 1000);
}
int scd30_read_data(scd30_data_t *data) {
// Helper to convert Big Endian IEEE754 bytes to float
static float bytes_to_float(uint8_t mmsb, uint8_t mlsb, uint8_t lmsb, uint8_t llsb) {
uint32_t val = ((uint32_t)mmsb << 24) | ((uint32_t)mlsb << 16) | ((uint32_t)lmsb << 8) | (uint32_t)llsb;
float f;
memcpy(&f, &val, 4);
return f;
}
int scd30_read_data(scd30_handle_t *handle, scd30_data_t *data) {
uint8_t ready_command[2] = {
(SCD30_CMD_READY_STATUS >> 8) & 0xFF,
SCD30_CMD_READY_STATUS & 0xFF
@@ -54,7 +75,7 @@ int scd30_read_data(scd30_data_t *data) {
// Poll until data is ready
do {
i2c_master_write_read_device(I2C_NUM_0, SCD30_I2C_ADDRESS, ready_command, sizeof(ready_command), ready_status, sizeof(ready_status), 1000 / portTICK_PERIOD_MS);
i2c_master_transmit_receive(handle->dev_handle, ready_command, sizeof(ready_command), ready_status, sizeof(ready_status), 1000);
} while (ready_status[1] != 0x01);
uint8_t read_command[2] = {
@@ -64,7 +85,8 @@ int scd30_read_data(scd30_data_t *data) {
uint8_t buffer[18];
// Read 18 bytes of data
i2c_master_write_read_device(I2C_NUM_0, SCD30_I2C_ADDRESS, read_command, sizeof(read_command), buffer, sizeof(buffer), 1000 / portTICK_PERIOD_MS);
// Format: CO2_MSB, CO2_LSB, CRC, CO2_LMSB, CO2_LLSB, CRC, ...
i2c_master_transmit_receive(handle->dev_handle, read_command, sizeof(read_command), buffer, sizeof(buffer), 1000);
// Validate CRC for each pair of data
for (int i = 0; i < 18; i += 3) {
@@ -73,10 +95,13 @@ int scd30_read_data(scd30_data_t *data) {
}
}
// Parse data
data->co2 = (float)((buffer[0] << 8) | buffer[1]);
data->temp = (float)((buffer[3] << 8) | buffer[4]);
data->humidity = (float)((buffer[6] << 8) | buffer[7]);
// Parse IEEE754 floats (Big Endian)
// Structure: [Byte1, Byte2, CRC, Byte3, Byte4, CRC]
// 0 1 2 3 4 5
data->co2 = bytes_to_float(buffer[0], buffer[1], buffer[3], buffer[4]);
data->temp = bytes_to_float(buffer[6], buffer[7], buffer[9], buffer[10]);
data->humidity = bytes_to_float(buffer[12], buffer[13], buffer[15], buffer[16]);
return 0; // Success
}

View File

@@ -2,6 +2,7 @@
#define SCD30_H
#include <stdint.h>
#include "driver/i2c_master.h"
// Data structure to hold SCD30 sensor data
typedef struct {
@@ -10,9 +11,34 @@ typedef struct {
float humidity; // Relative humidity in percentage
} scd30_data_t;
// Function prototypes
void scd30_init(void);
void scd30_start_measurement(void);
int scd30_read_data(scd30_data_t *data);
typedef struct {
i2c_master_bus_handle_t bus_handle;
i2c_master_dev_handle_t dev_handle;
} scd30_handle_t;
/**
* @brief Initialize the SCD30 sensor
*
* @param sda_gpio SDA GPIO number
* @param scl_gpio SCL GPIO number
* @return scd30_handle_t* Pointer to the sensor handle
*/
scd30_handle_t *scd30_init(int sda_gpio, int scl_gpio);
/**
* @brief Start continuous measurement
*
* @param handle Sensor handle
*/
void scd30_start_measurement(scd30_handle_t *handle);
/**
* @brief Read data from the SCD30 sensor
*
* @param handle Sensor handle
* @param data Pointer to store the read data
* @return int 0 on success, -1 on error
*/
int scd30_read_data(scd30_handle_t *handle, scd30_data_t *data);
#endif // SCD30_H