这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【SCD4x传感器测评】4、驱动设计及系统实现输出测试

共1条 1/1 1 跳转至

【SCD4x传感器测评】4、驱动设计及系统实现输出测试

高工
2025-10-05 23:35:35     打赏

        接下来就是进行基本的驱动设计,这里我们使用最常用的STM32作为主要的控制器件,我们在第二章的时候主要使用的是就是arduino进行的快速验证,可是并不知道所以然,会用还要能把它集成到其他系统,其中STM32作为目前使用应用范围最广的MCU,明显是本次驱动验证最好的载体。

        我们通过快速验证以及详细介绍,实际上驱动的设计也是基本水到渠成的,本次我们就以周期性测量来进行基本的驱动设计,主要包括接口适配,命令函数的适配,再到具体测量的实现。

        我们先通过测量实现基本的通信验证,这里我们通过get_serial_number和get_sensor_variant来进行验证,用于证明传感器的身份以及验证接口的准确性。

        首先是接口的适配,主要是发送命令和数据接收,分别对应IIC的发送和接受:
int SCD4x_Send_Commmand(uint16_t command)
{
    uint8_t CommandData[2] = {0};
    int result;
    
    CommandData[0] = command >> 8 & 0xff;
  CommandData[1] = command & 0xff;
    result = HAL_I2C_Master_Transmit(&hi2c1,(SCD41_ADDRESS << 1), CommandData, 2, 1000);
    
    if (result!=HAL_OK)
        return -1; //error
    else
        return 0; //Success
}

int SCD4x_Read_Response(uint8_t ndata,uint8_t *data)
{
    // (2 bytes status + 1 byte CRC)*n
    int result;

    result = HAL_I2C_Master_Receive(&hi2c1, (SCD41_ADDRESS << 1), data, 3*ndata, 1000);
    
    if (result!=HAL_OK)
        return -1; //error
    else
        return 0; //Success
}

        这里我们需要注意,命令是个16位的数据,我们需要拆分一下,接受的数据也是通过16位的,不过不管是命令还是数据都是通过8位的方式传输的,这里只是做了一下接口的适配,如果后面想要通过模拟IIC的方式只要修改这里就好了,接受数据没有在这里进行处理,实际上可以直接在这里进行CRC的判断以及数据合成,不过我没有放到这里,在具体的命令中进行的处理。需要做一下8位的CRC验证:

uint8_t sensirion_common_generate_crc(const uint8_t* data, uint16_t count)
{
    uint8_t crc = CRC8_INIT;
    for (uint16_t i = 0; i < count; ++i) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; ++j) {
            if (crc & 0x80)
                crc = (crc << 1) ^ CRC8_POLYNOMIAL;
            else
                crc = (crc << 1);
        }
    }
    return crc;
}

        接下来就是具体的命令了,这里主要做的是传感器和设备的识别:

void SCD4x_Init(void)
{
    stop_periodic_measurement();
    HAL_Delay(500); 
    get_serial_number();
    get_sensor_variant();
    start_periodic_measurement();

}


int get_serial_number(void)
{
    uint16_t command = GET_SERIAL_NUMBER_CMD;
    uint8_t response[9]; // 3 data words + 3 CRC bytes
    int result;
    
    // Send command
    result = SCD4x_Send_Commmand(command);
    if (result != HAL_OK) {
        return result;
   }
    HAL_Delay(1); 
    // Read response
    result = SCD4x_Read_Response(9,response);
    if (result != HAL_OK) {
            return result;
    }
    
    SCD4x.Number[0] = (response[0] << 8) | response[1];  
    SCD4x.Number[1] = (response[3] << 8) | response[4];  
    SCD4x.Number[2] = (response[6] << 8) | response[7];  
    
    return result;
}

int get_sensor_variant(void)
{
        uint16_t command = GET_SERIAL_VARIANT_CMD;
        uint8_t response[3] = {0}; // 2 bytes status + 1 byte CRC
    int result;
        
    // Send command
    result = SCD4x_Send_Commmand(command);
    if (result != HAL_OK) {
        return result;
    }
        // Wait for sensor to process
    HAL_Delay(1); 
    // Read response
    result = SCD4x_Read_Response(3,response);
    if (result != HAL_OK) {
        return result;
    }
    // Verify CRC
    if (sensirion_common_generate_crc(response, 2) != response[2]) {
        return -1;
    }

    // Extract the 16-bit status
    SCD4x.Variant = (response[0] << 8) | response[1];

        return 0;
}

        结果如下:

image.png

        接下来是周期性测量用到的函数:

int start_periodic_measurement(void)
{
    uint16_t command = START_PERIODIC_MEASUREMENT_CMD;
  int result;

    result = SCD4x_Send_Commmand(command);
    return result;
}

int stop_periodic_measurement(void)
{
  uint16_t command = STOP_PERIODIC_MEASUREMENT_CMD;
  int result;

    result = SCD4x_Send_Commmand(command);
    return result;
}


/* Function to check if measurement data is ready */
int get_data_ready_status(void)
{
        uint16_t command = GET_DATA_READ_STATUS_CMD;
        uint8_t response[3] = {0}; // 2 bytes status + 1 byte CRC
    int result;
        
    // Send command
    result = SCD4x_Send_Commmand(command);
    if (result != HAL_OK) {
        return result;
    }
        // Wait for sensor to process
    HAL_Delay(1); 
    // Read response
    result = SCD4x_Read_Response(3,response);
    if (result != HAL_OK) {
        return result;
    }
    // Verify CRC
    if (sensirion_common_generate_crc(response, 2) != response[2]) {
        return -1;
    }

    // Extract the 16-bit status
    uint16_t word = (response[0] << 8) | response[1];

    // Check if data is ready (status[10:0] != 0)
    if ((word & 0x07FF) == 0) {
        return -1;
    } else {
        return 0;
    }
}


int read_measurement(void)
{
    uint16_t command = READ_MEASUREMENT_CMD;
    uint8_t response[9]; // 3 data words + 3 CRC bytes
    uint16_t word[3]={0};
    int result=0;

    if(get_data_ready_status()==-1)
        return -1;

    // Send command
  result = SCD4x_Send_Commmand(command);
  if (result != HAL_OK) {
      return result;
  }
    
    // Read response
    result = SCD4x_Read_Response(9,response);
    if (result != HAL_OK) {
            return result;
    }

    word[0] = (response[0] << 8) | response[1];  // CO2
    word[1] = (response[3] << 8) | response[4];  // Temperature
    word[2] = (response[6] << 8) | response[7];  // Humidity

    SCD4x.co2    = word[0];
    SCD4x.temp    = -45 + 175*word[1]/ pow(2,16)-1;
    SCD4x.rh     = 100*word[2]/ pow(2,16)-1;

    printf("co2=%f \n",SCD4x.co2);
    printf("temp=%f \n",SCD4x.temp);
    printf("rh = %f\n",SCD4x.rh);
    return 0;

}

        效果如下:image.png

        这个是一开始检测的数据,需要一定的稳定时间,反应还是挺快的,我离开一段时间后,通风的环境下就小了很多:

image.png

        通风状态下有人的CO2测试数据:

image.png

        PS:本次使用的STM32作为本次的主控,keil作为开发环境,不知道为什么这个IIC还是有时候会出现问题,不知道这个和传感器时候有关系,采用的IIC标准速率进行的采集,一旦调整优化等级就会出现问题,只能用O3等级,但凡是调整到O0或者再加点数据通信就会出现暂停的情况(这个是通过keil在线调试定位的点),听说过进入错误中断的或者死循环的,这种情况还是第一次遇到,大家如果有什么好方法或者解决办法可以一起讨论一下,或者IIC只能用IO口模拟才是最稳定的。

        整体的效果显示,通过OLED进行显示:

【EEPW测评-SCD41评估板】 https://www.bilibili.com/video/BV1PmxgzHEyS/?share_source=copy_web&vd_source=2a202874768d99b0acaa1aceb9a9b93e





关键词: SCD4x     传感器     测评     驱动     系统    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]