MicroMod Environmental Function Board Hookup Guide

Pages
Contributors: bboyho, Elias The Sparkiest
Favorited Favorite 0

Introduction

The SparkFun MicroMod Environmental Function Board adds additional sensing options to the MicroMod Processor Boards. This function board includes three sensors to monitor air quality (SGP40), humidity & temperature (SHTC3), and CO2 concentrations (STC31) in your indoor environment. To make it even easier to use, all communication is over the MicroMod's I2C bus! In this tutorial, we will go over how to connect the board and read the sensors.

SparkFun MicroMod Environmental Function Board

SparkFun MicroMod Environmental Function Board

SEN-18632
$149.95 $112.46
1

Required Materials

To follow along with this tutorial, you will need the following materials at a minimum. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Reversible USB A to C Cable - 2m

Reversible USB A to C Cable - 2m

CAB-15424
$8.95
1
microSD Card - 1GB (Class 4)

microSD Card - 1GB (Class 4)

COM-15107
$5.50
SparkFun MicroMod Artemis Processor

SparkFun MicroMod Artemis Processor

DEV-16401
$14.95
1
SparkFun MicroMod Environmental Function Board

SparkFun MicroMod Environmental Function Board

SEN-18632
$149.95 $112.46
1
Pocket Screwdriver Set

Pocket Screwdriver Set

TOL-12891
$4.50
5

SparkFun MicroMod Main Board - Single

DEV-18575
Retired

MicroMod Main Board

To hold the processor and function boards, you will need one Main board. Depending on your application, you may choose to have either one or two function boards.

SparkFun MicroMod Main Board - Single

DEV-18575
Retired

SparkFun MicroMod Main Board - Double

DEV-18576
Retired

MicroMod Function Board

To add additional functionality to your Processor Board, you'll want to include one or two function boards when connecting them to the Main Board. Besides the MicroMod Environmental Function Board which this tutorial is focused on, you may descide to add the WiFi Function Board to the mix. Make sure to adjust the cart and include the MicroMod Main Board - Double as opposed to the Single when using two Function Boards. Check out the SparkFun catalog for other function boards.

SparkFun MicroMod Environmental Function Board

SparkFun MicroMod Environmental Function Board

SEN-18632
$149.95 $112.46
1
SparkFun MicroMod WiFi Function Board - ESP32

SparkFun MicroMod WiFi Function Board - ESP32

WRL-18430
$14.95 $8.97

Tools

You will need a screw driver to secure the Processor and Function boards.

SparkFun Mini Screwdriver

SparkFun Mini Screwdriver

TOL-09146
$1.05
3

Suggested Reading

If you aren't familiar with the MicroMod ecosystem, we recommend reading here for an overview.

MicroMod Logo
MicroMod Ecosystem

If you aren’t familiar with the following concepts, we also recommend checking out a few of these tutorials before continuing. Make sure to check the respective hookup guides for your processor board and function board to ensure that you are installing the correct USB-to-serial converter. You may also need to follow additional instructions that are not outlined in this tutorial to install the appropriate software.

What is an Arduino?

What is this 'Arduino' thing anyway? This tutorials dives into what an Arduino is and along with Arduino projects and widgets.

Installing Arduino IDE

A step-by-step guide to installing and testing the Arduino software on Windows, Mac, and Linux.

How to Install CH340 Drivers

How to install CH340 drivers (if you need them) on Windows, Mac OS X, and Linux.

SparkFun Humidity Sensor Breakout - SHTC3 (Qwiic) Hookup Guide

A Hookup Guide to get started using the SHTC3 breakout.

Getting Started with MicroMod

Dive into the world of MicroMod - a compact interface to connect a microcontroller to various peripherals via the M.2 Connector!

Air Quality Sensor - SGP40 (Qwiic) Hookup Guide

Get started measuring indoor air quality with the SparkFun Air Quality Sensor - SGP40 (Qwiic) Hookup Guide.

Hardware Overview

This section goes over the important features on the MicroMod Environmental Function Board. Of course, we recommend checking out the Resources and Going Further for more information on each sensor.

Power

To power the board, you will need to apply power to a SparkFun Main Board. Power applied will connect to the Function Board's VIN pin, which will be regulated down for the rest of the board with the AP2112 3.3V/600mA voltage regulator.

Voltage Regulator

SGP40

The board includes the Sensirion SGP40 sensor IC which measures air quality. The reserved I2C address for the SGP40 is 0x59. For easy reference, the default address for the SGP40 is labeled on the board.

SGP40

SHTC3

The board includes the Sensirion SHTC3 sensor IC which measures humidity and temperature. The reserved I2C address for the SHTC3 is 0x70. For easy reference, the default address for the SHTC3 is labeled on the board.

SHTC3

STC31

The board includes the Sensirion STC31 sensor IC which measures CO2 concentrations in N2 and CO2 in air. The reserved I2C address for the STC31 is 0x29. For easy reference, the default address for the STC31 is labeled on the board.

STC31

EEPROM

The board includes an I2C EEPROM. Unfortunately, this is not available for the user and was meant to hold board specific information.

EEPROM

LED

There is one LED to indicate when there is power available. You can disable the LED with the PWR jumper

LED

Jumpers

The following jumpers are included to configure the board.

  • PWR - By default, the jumper with the label PWR is closed. This jumper connects the 3.3V line and LED. Cutting this jumper will disable the LED.
  • I2C Pull-up Resistors - By default, this three way jumper labeled I2C is closed and connects two pull-up resistors to the I2C data lines. If you have many devices on your I2C data lines, then you may consider cutting these two jumpers.
  • STC31 Address Selection - There are three jumpers available on the board to adjust the STC31's address. By default, the jumpers are open. The alternative addresses for the sensor are 0x2A, 0x2B, and 0x2C. To select the address, you will need to close the jumper by adding a solder blob to one of the solder jumpers.


alt text

MicroMod Function Board Pinout

Depending on your window size, you may need to use the horizontal scroll bar at the bottom of the table to view the additional pin functions. Note that the M.2 connector pins on opposing sides are offset from each other as indicated by the bottom pins where it says (Not Connected)*. There is no connection to pins that have a "-" under the primary function.

AUDIO UART GPIO/BUS I2C SDIO SPI0 Dedicated
Function Bottom
Pin
   Top   
Pin
Function
(Not Connected) 75 GND
3.3V 74 73 G5 / BUS5
RTC_3V_BATT 72 71 G6 / BUS6
SPI_CS1# SDIO_DATA3 (I/O) 70 69 G7 / BUS7
SDIO_DATA2 (I/O) 68 67 G8
SDIO_DATA1 (I/O) 66 65 G9 ADC_D- CAM_HSYNC
SPI_CIPO1 SDIO_DATA0 (I/O) 64 63 G10 ADC_D+ CAM_VSYNC
SPI COPI1 SDIO_CMD (I/O) 62 61 SPI_CIPO (I)
SPI SCK1 SDIO_SCK (O) 60 59 SPI_COPI (O) LED_DAT
AUD_MCLK (O) 58 57 SPI_SCK (O) LED_CLK
CAM_MCLK PCM_OUT I2S_OUT AUD_OUT 56 55 SPI_CS#
CAM_PCLK PCM_IN I2S_IN AUD_IN 54 53 I2C_SCL1 (I/O)
PDM_DATA PCM_SYNC I2S_WS AUD_LRCLK 52 51 I2C_SDA1 (I/O)
PDM_CLK PCM_CLK I2S_SCK AUD_BCLK 50 49 BATT_VIN / 3 (I - ADC) (0 to 3.3V)
G4 / BUS4 48 47 PWM1
G3 / BUS3 46 45 GND
G2 / BUS2 44 43 CAN_TX
G1 / BUS1 42 41 CAN_RX
G0 / BUS0 40 39 GND
A1 38 37 USBHOST_D-
GND 36 35 USBHOST_D+
A0 34 33 GND
PWM0 32 31 Module Key
Module Key 30 29 Module Key
Module Key 28 27 Module Key
Module Key 26 25 Module Key
Module Key 24 23 SWDIO
UART_TX2 (O) 22 21 SWDCK
UART_RX2 (I) 20 19 UART_RX1 (I)
CAM_TRIG D1 18 17 UART_TX1 (0)
I2C_INT# 16 15 UART_CTS1 (I)
I2C_SCL (I/0) 14 13 UART_RTS1 (O)
I2C_SDA (I/0) 12 11 BOOT (I - Open Drain)
D0 10 9 USB_VIN
SWO G11 8 7 GND
RESET# (I - Open Drain) 6 5 USB_D-
3.3V_EN 4 3 USB_D+
3.3V 2 1 GND
Alternative Function Primary Function Bottom
Pin
   Top   
Pin
Primary Function Alternative Function
(Not Connected) 75 GND
VIN 74 73 3.3V
VIN 72 71 Power EN
- 70 69 -
- 66 65 -
- 64 63 -
- 62 61 -
- 60 59 -
- 58 57 -
- 56 55 -
- 54 53 -
- 52 51 -
- 50 49 -
- 48 47 -
- 46 45 GND
- 44 43 -
- 42 41 -
- 40 39 GND
- 38 37 -
EEPROM_A0 36 35 -
EEPROM_A1 34 33 GND
EEPROM_A2 32 31 Module Key
Module Key 30 29 Module Key
Module Key 28 27 Module Key
Module Key 26 25 Module Key
Module Key 24 23 -
- 22 21 I2C_SCL
- 20 19 I2C_SDA
- 18 17 -
- 16 15 -
- 14 13 -
- 12 11 -
- 10 9 -
- 8 7 -
- 6 5 -
- 4 3 -
- 2 1 GND
Signal Group Signal I/O Description Voltage
Power 3.3V I 3.3V Source 3.3V
GND Return current path 0V
USB_VIN I USB VIN compliant to USB 2.0 specification. Connect to pins on processor board that require 5V for USB functionality 4.8-5.2V
RTC_3V_BATT I 3V provided by external coin cell or mini battery. Max draw=100μA. Connect to pins maintaining an RTC during power loss. Can be left NC. 3V
3.3V_EN O Controls the carrier board's main voltage regulator. Voltage above 1V will enable 3.3V power path. 3.3V
BATT_VIN/3 I Carrier board raw voltage over 3. 1/3 resistor divider is implemented on carrier board. Amplify the analog signal as needed for full 0-3.3V range 3.3V
Reset Reset I Input to processor. Open drain with pullup on processor board. Pulling low resets processor. 3.3V
Boot I Input to processor. Open drain with pullup on processor board. Pulling low puts processor into special boot mode. Can be left NC. 3.3V
USB USB_D± I/O USB Data ±. Differential serial data interface compliant to USB 2.0 specification. If UART is required for programming, USB± must be routed to a USB-to-serial conversion IC on the processor board.
USB Host USBHOST_D± I/O For processors that support USB Host Mode. USB Data±. Differential serial data interface compliant to USB 2.0 specification. Can be left NC.
CAN CAN_RX I CAN Bus receive data. 3.3V
CAN_TX O CAN Bus transmit data. 3.3V
UART UART_RX1 I UART receive data. 3.3V
UART_TX1 O UART transmit data. 3.3V
UART_RTS1 O UART ready to send. 3.3V
UART_CTS1 I UART clear to send. 3.3V
UART_RX2 I 2nd UART receive data. 3.3V
UART_TX2 O 2nd UART transmit data. 3.3V
I2C I2C_SCL I/O I2C clock. Open drain with pullup on carrier board. 3.3V
I2C_SDA I/O I2C data. Open drain with pullup on carrier board 3.3V
I2C_INT# I Interrupt notification from carrier board to processor. Open drain with pullup on carrier board. Active LOW 3.3V
I2C_SCL1 I/O 2nd I2C clock. Open drain with pullup on carrier board. 3.3V
I2C_SDA1 I/O 2nd I2C data. Open drain with pullup on carrier board. 3.3V
SPI SPI_COPI O SPI Controller Output/Peripheral Input. 3.3V
SPI_CIPO I SPI Controller Input/Peripheral Output. 3.3V
SPI_SCK O SPI Clock. 3.3V
SPI_CS# O SPI Chip Select. Active LOW. Can be routed to GPIO if hardware CS is unused. 3.3V
SPI/SDIO SPI_SCK1/SDIO_CLK O 2nd SPI Clock. Secondary use is SDIO Clock. 3.3V
SPI_COPI1/SDIO_CMD I/O 2nd SPI Controller Output/Peripheral Input. Secondary use is SDIO command interface. 3.3V
SPI_CIPO1/SDIO_DATA0 I/O 2nd SPI Peripheral Input/Controller Output. Secondary use is SDIO data exchange bit 0. 3.3V
SDIO_DATA1 I/O SDIO data exchange bit 1. 3.3V
SDIO_DATA2 I/O SDIO data exchange bit 2. 3.3V
SPI_CS1/SDIO_DATA3 I/O 2nd SPI Chip Select. Secondary use is SDIO data exchange bit 3. 3.3V
Audio AUD_MCLK O Audio master clock. 3.3V
AUD_OUT/PCM_OUT/I2S_OUT/CAM_MCLK O Audio data output. PCM synchronous data output. I2S serial data out. Camera master clock. 3.3V
AUD_IN/PCM_IN/I2S_IN/CAM_PCLK I Audio data input. PCM syncrhonous data input. I2S serial data in. Camera periphperal clock. 3.3V
AUD_LRCLK/PCM_SYNC/I2S_WS/PDM_DATA I/O Audio left/right clock. PCM syncrhonous data SYNC. I2S word select. PDM data. 3.3V
AUD_BCLK/PCM_CLK/I2S_CLK/PDM_CLK O Audio bit clock. PCM clock. I2S continuous serial clock. PDM clock. 3.3V
SWD SWDIO I/O Serial Wire Debug I/O. Connect if processor board supports SWD. Can be left NC. 3.3V
SWDCK I Serial Wire Debug clock. Connect if processor board supports SWD. Can be left NC. 3.3V
ADC A0 I Analog to digital converter 0. Amplify the analog signal as needed to enable full 0-3.3V range. 3.3V
A1 I Analog to digital converter 1. Amplify the analog signal as needed to enable full 0-3.3V range. 3.3V
PWM PWM0 O Pulse width modulated output 0. 3.3V
PWM1 O Pulse width modulated output 1. 3.3V
Digital D0 I/O General digital input/output pin. 3.3V
D1/CAM_TRIG I/O General digital input/output pin. Camera trigger. 3.3V
General/Bus G0/BUS0 I/O General purpose pins. Any unused processor pins should be assigned to Gx with ADC + PWM capable pins given priority (0, 1, 2, etc.) positions. The intent is to guarantee PWM, ADC and Digital Pin functionality on respective ADC/PWM/Digital pins. Gx pins do not guarantee ADC/PWM function. Alternative use is pins can support a fast read/write 8-bit or 4-bit wide bus. 3.3V
G1/BUS1 I/O 3.3V
G2/BUS2 I/O 3.3V
G3/BUS3 I/O 3.3V
G4/BUS4 I/O 3.3V
G5/BUS5 I/O 3.3V
G6/BUS6 I/O 3.3V
G7/BUS7 I/O 3.3V
G8 I/O General purpose pin 3.3V
G9/ADC_D-/CAM_HSYNC I/O Differential ADC input if available. Camera horizontal sync. 3.3V
G10/ADC_D+/CAM_VSYNC I/O Differential ADC input if available. Camera vertical sync. 3.3V
G11/SWO I/O General purpose pin. Serial Wire Output 3.3V

Board Dimensions

The board uses the standard MicroMod Function Board size which measures about 1.50"x2.56".

Board Dimensions

Hardware Hookup

If you have not already, make sure to check out the Getting Started with MicroMod: Hardware Hookup for information on inserting your Processor and Function Boards to the Main Board.

Getting Started with MicroMod

October 21, 2020

Dive into the world of MicroMod - a compact interface to connect a microcontroller to various peripherals via the M.2 Connector!

After securing the Processor and Function Board to the Main Board, your setup should look like the image below. Connect a USB Type C Cable to begin programming your Processor Board. In this case, we used the MicroMod Main Board - Single, MicroMod Artemis Processor, and MicroMod Environmental Function Board.

Main Board, Processor, and Function Boards

Software Installation

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review the following tutorials.

Arduino Board Definitions and Driver

We'll assume that you installed the necessary board files and drivers for your Processor Board. In this case, we used the MicroMod Artemis Processor Board which uses the CH340 USB-to-serial converter. If you are using a Processor Board, make sure to check out its hookup guide for your Processor Board.

Installing Board Definitions in the Arduino IDE

September 9, 2020

How do I install a custom Arduino board/core? It's easy! This tutorial will go over how to install an Arduino board definition using the Arduino Board Manager. We will also go over manually installing third-party cores, such as the board definitions required for many of the SparkFun development boards.

MicroMod Artemis Processor Board Hookup Guide

October 21, 2020

Get started with the Artemis MicroMod Processor Board in this tutorial!

How to Install CH340 Drivers

August 6, 2019

How to install CH340 drivers (if you need them) on Windows, Mac OS X, and Linux.

Arduino Library

The SparkFun SGP40, SHTC3, and STC3X Arduino libraries can be downloaded with the Arduino library manager by searching 'SparkFun SGP40,' 'SHTC3,' and 'STC3X'. Or you can grab the zip here from each respective GitHub repository (SGP40, SHTC3, STC3X) to manually install:

Arduino Examples

Example 1: Reading SHTC3, STC31, and SGP40

Below is the combined example to read SHTC3, STC31, and SGP40. If you have not already, select your Board (in this case the MicroMod Artemis), and associated COM port. Copy and paste the code below in your Arduino IDE. Hit the upload button and set the serial monitor to 115200 baud.

language:c
/******************************************************************************

  WRITTEN BY: Ho Yun "Bobby" Chan
  @ SparkFun Electronics
  DATE: 10/19/2021
  GITHUB REPO: https://github.com/sparkfun/MicroMod_Environmental_Sensor_Function_Board
  DEVELOPMENT ENVIRONMENT SPECIFICS:
    Firmware developed using Arduino IDE v1.8.12

  ========== DESCRIPTION==========
  This example code combines example codes from the SHTC3, STC31, and SGP40 libraries.
  Most of the steps to obtain the measurements are the same as the example code.
  Generic object names were renamed (e.g. mySensor => mySGP40 and mySTC3x).

     Example 1: Basic Relative Humidity and Temperature Readings  w/ SHTC3; Written by Owen Lyke
     Example 2: PHT (SHTC3) Compensated CO2 Readings w/ STC31; Written by Paul Clark and based on earlier code by Nathan Seidle
     Example 1: Basic VOC Index w/ SGP40; Written by Paul Clark

  Open a Serial Monitor at 115200 baud to view the readings!

  Note: You may need to wait about ~5 minutes after starting up the code before VOC index
  has any values.

  ========== HARDWARE CONNECTIONS ==========
  MicroMod Artemis Processor Board => MicroMod Main Board => MicroMod Environmental Function Board (with SHTC3, STC31, and SGP40)

  Feel like supporting open source hardware?
  Buy a board from SparkFun!
       MicroMod MicroMod Artemis Processor   | https://www.sparkfun.com/products/16401
       MicroMod Main Board - Single          | https://www.sparkfun.com/products/18575
       MicroMod Environmental Function Board | https://www.sparkfun.com/products/18632

  You can also get the sensors individually.

       Qwiic SHTC3 | https://www.sparkfun.com/products/16467
       Qwiic STC31 | https://www.sparkfun.com/products/18385
       Qwiic SGP40 | https://www.sparkfun.com/products/17729

  LICENSE: This code is released under the MIT License (http://opensource.org/licenses/MIT)

******************************************************************************/



#include <Wire.h>

#include "SparkFun_SHTC3.h" //Click here to get the library: http://librarymanager/All#SparkFun_SHTC3
SHTC3 mySHTC3; // Create an object of the SHTC3 class

#include "SparkFun_STC3x_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_STC3x
STC3x mySTC3x; // Create an object of the mySTC3x class

#include "SparkFun_SGP40_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_SGP40
SGP40 mySGP40; //Create an object of the SGP40 class

float RH = 0.00; // Variable to keep track of SHTC3 temperature compensation for the STC31
float temperature = 0.00; // Variable to keep track of SHTC3 relative humidity compensation for the STC31






void setup() {

  Serial.begin(115200);
  //while (!Serial) ; // Wait for Serial Monitor/Plotter to open for Processors with Native USB (i.e. SAMD51)
  Serial.println(F("Initializing Combined Example w/ SGP40, SHTC3, and STC31."));
  Wire.begin();

  //mySTC3x.enableDebugging(); // Uncomment this line to get helpful debug messages on Serial
  //mySGP40.enableDebugging(); // Uncomment this line to print useful debug messages to Serial



  if (mySHTC3.begin() != SHTC3_Status_Nominal)
  {
    Serial.println(F("SHTC3 not detected. Please check wiring. Freezing..."));
    while (1)
      ; // Do nothing more
  }

  if (mySTC3x.begin() == false)
  {
    Serial.println(F("STC3x not detected. Please check wiring. Freezing..."));
    while (1)
      ; // Do nothing more
  }

  if (mySGP40.begin() == false)
  {
    Serial.println(F("SGP40 not detected. Check connections. Freezing..."));
    while (1)
      ; // Do nothing more
  }



  //We need to tell the STC3x what binary gas and full range we are using
  //Possible values are:
  //  STC3X_BINARY_GAS_CO2_N2_100   : Set binary gas to CO2 in N2.  Range: 0 to 100 vol%
  //  STC3X_BINARY_GAS_CO2_AIR_100  : Set binary gas to CO2 in Air. Range: 0 to 100 vol%
  //  STC3X_BINARY_GAS_CO2_N2_25    : Set binary gas to CO2 in N2.  Range: 0 to 25 vol%
  //  STC3X_BINARY_GAS_CO2_AIR_25   : Set binary gas to CO2 in Air. Range: 0 to 25 vol%
  if (mySTC3x.setBinaryGas(STC3X_BINARY_GAS_CO2_AIR_25) == false)
  {
    Serial.println(F("Could not set the binary gas! Freezing..."));
    while (1)
      ; // Do nothing more
  }



  //We can compensate for temperature and relative humidity using the readings from the SHTC3

  if (mySHTC3.update() != SHTC3_Status_Nominal) // Request a measurement
  {
    Serial.println(F("Could not read the RH and T from the SHTC3! Freezing..."));
    while (1)
      ; // Do nothing more
  }

  //In case the ‘Set temperature command’ has been used prior to the measurement command,
  //the temperature value given out by the STC31 will be that one of the ‘Set temperature command’.
  //When the ‘Set temperature command’ has not been used, the internal temperature value can be read out.
  temperature = mySHTC3.toDegC(); // "toDegC" returns the temperature as a floating point number in deg C
  Serial.print(F("Setting STC3x temperature to "));
  Serial.print(temperature, 2);
  Serial.print(F("C was "));
  if (mySTC3x.setTemperature(temperature) == false)
    Serial.print(F("not "));
  Serial.println(F("successful"));

  RH = mySHTC3.toPercent(); // "toPercent" returns the percent humidity as a floating point number
  Serial.print(F("Setting STC3x RH to "));
  Serial.print(RH, 2);
  Serial.print(F("% was "));
  if (mySTC3x.setRelativeHumidity(RH) == false)
    Serial.print(F("not "));
  Serial.println(F("successful"));

  //If we have a pressure sensor available, we can compensate for ambient pressure too.
  //As an example, let's set the pressure to 840 mbar (== SF Headquarters)
  uint16_t pressure = 840;
  Serial.print(F("Setting STC3x pressure to "));
  Serial.print(pressure);
  Serial.print(F("mbar was "));
  if (mySTC3x.setPressure(pressure) == false)
    Serial.print(F("not "));
  Serial.println(F("successful"));

  Serial.println(F("Note: Relative humidity and temperature compensation for the STC31 will be updated frequently in the main loop() function."));

} //end setup()






void loop() {

  //==============================
  //==========READ SHTC3==========
  //==============================
  //minimum update rate = ~100Hz

  SHTC3_Status_TypeDef result = mySHTC3.update();           // Call "update()" to command a measurement, wait for measurement to complete, and update the RH and T members of the object

  RH = mySHTC3.toPercent();                                 // "toPercent" returns the percent humidity as a floating point number
  Serial.print(F("RH = "));
  Serial.print(RH);

  Serial.print(F("%, T = "));
  Serial.print(mySHTC3.toDegF());                           // "toDegF" return the temperature as a flaoting point number in deg F
  Serial.print(F(" deg F, "));

  temperature = mySHTC3.toDegC();                           // "toDegC" returns the temperature as a floating point number in deg C
  Serial.print(temperature);
  Serial.print(F(" deg C"));

  if (mySHTC3.lastStatus == SHTC3_Status_Nominal)           // You can also assess the status of the last command by checking the ".lastStatus" member of the object
  {
    Serial.println("");                                         //Sample data good, no need to output a message
  }
  else {
    Serial.print(F(",     Update failed, error: "));        //notify user if there is an error
    errorDecoder(mySHTC3.lastStatus);
    Serial.println("");
  }



  //==============================
  //==========READ STC31==========
  //==============================
  //minimum update rate = 1Hz


  if (mySTC3x.setRelativeHumidity(RH) == false)
    Serial.print(F("Unable to set STC31 Relative Humidity with SHTC3."));

  if (mySTC3x.setTemperature(temperature) == false)
    Serial.println(F("Unable to set STC31 Temperature with SHTC3."));


  Serial.print(F("CO2(%): "));

  if (mySTC3x.measureGasConcentration())                   // measureGasConcentration will return true when fresh data is available
  {
    Serial.println(mySTC3x.getCO2(), 2);
  }
  else
  {
    Serial.print(mySTC3x.getCO2(), 2);
    Serial.println(F(",     (old STC3 sample reading, STC31 was not able to get fresh data yet)"));  //output this note to indicate  when we are not able to obtain a new measurement
  }



  //==============================
  //==========READ SGP40==========
  //==============================
  //minimum update rate = 1Hz

  Serial.print(F("VOC Index is: "));
  Serial.println(mySGP40.getVOCindex()); //Get the VOC Index using the default RH (50%) and T (25C)



  //================================
  //=========SPACE & DELAY==========
  //================================
  //Serial.println("");// Uncomment this line to add some space between readings for the Serial Monitor
  delay(1000); //Wait 1 second - the Sensirion VOC and CO2 algorithms expects a sample rate of 1Hz

}//end loop()





void errorDecoder(SHTC3_Status_TypeDef message)                             // The errorDecoder function prints "SHTC3_Status_TypeDef" results in a human-friendly way
{
  switch (message)
  {
    case SHTC3_Status_Nominal : Serial.print("Nominal"); break;
    case SHTC3_Status_Error : Serial.print("Error"); break;
    case SHTC3_Status_CRC_Fail : Serial.print("CRC Fail"); break;
    default : Serial.print("Unknown return code"); break;
  }
}

Example 2: Reading SHTC3, STC31, and SGP40 in CSV

Below is the same combined code but formatted for CSV. If you have not already, select your Board (in this case the MicroMod Artemis), and associated COM port. Copy and paste the code below in your Arduino IDE. Hit the upload button and set the serial monitor to 115200 baud.

language:c
/******************************************************************************

  WRITTEN BY: Ho Yun "Bobby" Chan
  @ SparkFun Electronics
  DATE: 10/19/2021
  GITHUB REPO: https://github.com/sparkfun/MicroMod_Environmental_Sensor_Function_Board
  DEVELOPMENT ENVIRONMENT SPECIFICS:
    Firmware developed using Arduino IDE v1.8.12

  ========== DESCRIPTION==========
  This example code combines example codes from the SHTC3, STC31, and SGP40 libraries.
  Most of the steps to obtain the measurements are the same as the example code.
  Generic object names were renamed (e.g. mySensor => mySGP40 and mySTC3x).

     Example 1: Basic Relative Humidity and Temperature Readings  w/ SHTC3; Written by Owen Lyke
     Example 2: PHT (SHTC3) Compensated CO2 Readings w/ STC31; Written by Paul Clark and based on earlier code by Nathan Seidle
     Example 1: Basic VOC Index w/ SGP40; Written by Paul Clark

  Open a Serial Monitor/Plotter at 115200 baud to view the readings!

  Note: You may need to wait about ~5 minutes after starting up the code before VOC index
  has any values.

  ========== HARDWARE CONNECTIONS ==========
  MicroMod Artemis Processor Board => MicroMod Main Board => MicroMod Environmental Function Board (with SHTC3, STC31, and SGP40)

  Feel like supporting open source hardware?
  Buy a board from SparkFun!
       MicroMod MicroMod Artemis Processor   | https://www.sparkfun.com/products/16401
       MicroMod Main Board - Single          | https://www.sparkfun.com/products/18575
       MicroMod Environmental Function Board | https://www.sparkfun.com/products/18632

  You can also get the sensors individually.
       SHTC3 | https://www.sparkfun.com/products/16467
       STC31 | https://www.sparkfun.com/products/18385
       SGP40 | https://www.sparkfun.com/products/17729

  LICENSE: This code is released under the MIT License (http://opensource.org/licenses/MIT)

******************************************************************************/



#include <Wire.h>

#include "SparkFun_SHTC3.h" //Click here to get the library: http://librarymanager/All#SparkFun_SHTC3
SHTC3 mySHTC3; // Create an object of the SHTC3 class

#include "SparkFun_STC3x_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_STC3x
STC3x mySTC3x; // Create an object of the STC3x class

#include "SparkFun_SGP40_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_SGP40
SGP40 mySGP40; //Create an object of the SGP40 class

float RH = 0.00; // Variable to keep track of SHTC3 temperature compensation for the STC31
float temperature = 0.00; // Variable to keep track of SHTC3 relative humidity compensation for the STC31

//Debug mode, comment one of these lines out using a syntax
//for a single line comment ("//"):
#define DEBUG 0     //0 = Output for Serial Plotter, CSV
//#define DEBUG 1     //1 = Output for Serial Monitor





void setup() {

  Serial.begin(115200);
  //while (!Serial) ; // Wait for Serial Monitor/Plotter to open for Processors with Native USB (i.e. SAMD51)


#if DEBUG
  Serial.println(F("Initializing Combined Example w/ SGP40, SHTC3, and STC31."));
#else
  Serial.println(F("RH,degF,degC,SHTC3_Valid,RH_Compensate_Valid,degC_Compensate_Valid,CO2%,STC31_Valid,VOC_Index"));
#endif

  Wire.begin();

  //mySTC3x.enableDebugging(); // Uncomment this line to get helpful debug messages on Serial
  //mySGP40.enableDebugging(); // Uncomment this line to print useful debug messages to Serial



  if (mySHTC3.begin() != SHTC3_Status_Nominal)
  {
#if DEBUG
    Serial.println(F("SHTC3 not detected. Please check wiring. Freezing..."));
#endif
    while (1)
      ; // Do nothing more
  }

  if (mySTC3x.begin() == false)
  {
#if DEBUG
    Serial.println(F("STC3x not detected. Please check wiring. Freezing..."));
#endif
    while (1)
      ; // Do nothing more
  }

  if (mySGP40.begin() == false)
  {
#if DEBUG
    Serial.println(F("SGP40 not detected. Check connections. Freezing..."));
#endif
    while (1)
      ; // Do nothing more
  }



  //We need to tell the STC3x what binary gas and full range we are using
  //Possible values are:
  //  STC3X_BINARY_GAS_CO2_N2_100   : Set binary gas to CO2 in N2.  Range: 0 to 100 vol%
  //  STC3X_BINARY_GAS_CO2_AIR_100  : Set binary gas to CO2 in Air. Range: 0 to 100 vol%
  //  STC3X_BINARY_GAS_CO2_N2_25    : Set binary gas to CO2 in N2.  Range: 0 to 25 vol%
  //  STC3X_BINARY_GAS_CO2_AIR_25   : Set binary gas to CO2 in Air. Range: 0 to 25 vol%
  if (mySTC3x.setBinaryGas(STC3X_BINARY_GAS_CO2_AIR_25) == false)
  {
#if DEBUG
    Serial.println(F("Could not set the binary gas! Freezing..."));
#endif
    while (1)
      ; // Do nothing more
  }



  //We can compensate for temperature and relative humidity using the readings from the SHTC3

  if (mySHTC3.update() != SHTC3_Status_Nominal) // Request a measurement
  {
#if DEBUG
    Serial.println(F("Could not read the RH and T from the SHTC3! Freezing..."));
#endif
    while (1)
      ; // Do nothing more
  }

  //In case the ‘Set temperature command’ has been used prior to the measurement command,
  //the temperature value given out by the STC31 will be that one of the ‘Set temperature command’.
  //When the ‘Set temperature command’ has not been used, the internal temperature value can be read out.
  temperature = mySHTC3.toDegC(); // "toDegC" returns the temperature as a floating point number in deg C
#if DEBUG
  Serial.print(F("Setting STC3x temperature to "));
  Serial.print(temperature, 2);
  Serial.print(",");
  Serial.print(F("C was "));
#endif

  if (mySTC3x.setTemperature(temperature) == false) {
#if DEBUG
    Serial.print(F("not "));
#endif
  }
#if DEBUG
  Serial.println(F("successful"));
#endif

  RH = mySHTC3.toPercent(); // "toPercent" returns the percent humidity as a floating point number

#if DEBUG
  Serial.print(F("Setting STC3x RH to "));
  Serial.print(RH, 2);
  Serial.print(",");
  Serial.print(F("% was "));
#endif

  if (mySTC3x.setRelativeHumidity(RH) == false) {
#if DEBUG
    Serial.print(F("not "));
#endif
  }
#if DEBUG
  Serial.println(F("successful"));
#endif



  //If we have a pressure sensor available, we can compensate for ambient pressure too.
  //As an example, let's set the pressure to 840 mbar (== SF Headquarters)
  uint16_t pressure = 840;

#if DEBUG
  Serial.print(F("Setting STC3x pressure to "));
  Serial.print(pressure);
  Serial.print(F("mbar was "));
#endif

  if (mySTC3x.setPressure(pressure) == false) {
#if DEBUG
    Serial.print(F("not "));
#endif
  }
#if DEBUG
  Serial.println(F("successful"));

  Serial.println(F("Note: Relative humidity and temperature compensation for the STC31 will be updated frequently in the main loop() function."));
#endif

} //end setup()





void loop() {


  //==============================
  //======DEBUG TURNED ON=========
  //==============================
#if DEBUG
  //==============================
  //==========READ SHTC3==========
  //==============================
  //minimum update rate = ~100Hz

  SHTC3_Status_TypeDef result = mySHTC3.update();           // Call "update()" to command a measurement, wait for measurement to complete, and update the RH and T members of the object

  RH = mySHTC3.toPercent();                                 // "toPercent" returns the percent humidity as a floating point number
  Serial.print(F("RH = "));
  Serial.print(RH);

  Serial.print(F("%, T = "));
  Serial.print(mySHTC3.toDegF());                           // "toDegF" return the temperature as a flaoting point number in deg F
  Serial.print(F(" deg F, "));

  temperature = mySHTC3.toDegC();                           // "toDegC" returns the temperature as a floating point number in deg C
  Serial.print(temperature);
  Serial.print(F(" deg C"));

  if (mySHTC3.lastStatus == SHTC3_Status_Nominal)           // You can also assess the status of the last command by checking the ".lastStatus" member of the object
  {
    Serial.println("");                                         //Sample data good, no need to output a message
  }
  else {
    Serial.print(F(",     Update failed, error: "));        //notify user if there is an error
    errorDecoder(mySHTC3.lastStatus);
    Serial.println("");
  }



  //==============================
  //==========READ STC31==========
  //==============================
  //minimum update rate = 1Hz


  if (mySTC3x.setRelativeHumidity(RH) == false)
    Serial.print(F("Unable to set STC31 Relative Humidity with SHTC3."));

  if (mySTC3x.setTemperature(temperature) == false)
    Serial.println(F("Unable to set STC31 Temperature with SHTC3."));


  Serial.print(F("CO2(%): "));

  if (mySTC3x.measureGasConcentration())                   // measureGasConcentration will return true when fresh data is available
  {
    Serial.println(mySTC3x.getCO2(), 2);
  }
  else
  {
    Serial.print(mySTC3x.getCO2(), 2);
    Serial.println(F(",     (old STC3 sample reading, STC31 was not able to get fresh data yet)"));  //output this note to indicate  when we are not able to obtain a new measurement
  }



  //==============================
  //==========READ SGP40==========
  //==============================
  //minimum update rate = 1Hz

  Serial.print(F("VOC Index is: "));
  Serial.println(mySGP40.getVOCindex()); //Get the VOC Index using the default RH (50%) and T (25C)





  //==============================
  //=====DEBUG TURNED OFF=========
  //==============================
#else
  //==============================
  //==========READ SHTC3==========
  //==============================
  //minimum update rate = ~100Hz

  SHTC3_Status_TypeDef result = mySHTC3.update();           // Call "update()" to command a measurement, wait for measurement to complete, and update the RH and T members of the object

  RH = mySHTC3.toPercent();
  Serial.print(RH);
  Serial.print(",");
  Serial.print(mySHTC3.toDegF());
  Serial.print(",");
  temperature = mySHTC3.toDegC();                           // "toDegC" returns the temperature as a floating point number in deg C
  Serial.print(temperature);
  Serial.print(",");

  if (mySHTC3.lastStatus == SHTC3_Status_Nominal)           // You can also assess the status of the last command by checking the ".lastStatus" member of the object
  {
    Serial.print("1");                                         //Sample data good, no need to output a message
    Serial.print(",");
  }
  else
  {
    Serial.print("0");                                         //Sample data bad, no need to output a message
    Serial.print(",");
  }



  //==============================
  //==========READ STC31==========
  //==============================
  //minimum update rate = 1Hz


  if (mySTC3x.setRelativeHumidity(RH) == false)
  {
    //Serial.print(F("Unable to set STC31 Relative Humidity with SHTC3."));
    Serial.print("0");
    Serial.print(",");
  }
  else
  {
    Serial.print("1");
    Serial.print(",");
  }

  if (mySTC3x.setTemperature(temperature) == false)
  {
    //Serial.println(F("Unable to set STC31 Temperature with SHTC3."));
    Serial.print("0");
    Serial.print(",");
  }
  else
  {
    Serial.print("1");
    Serial.print(",");
  }

  if (mySTC3x.measureGasConcentration())                   // measureGasConcentration will return true when fresh data is available
  {
    Serial.print(mySTC3x.getCO2(), 2);
    Serial.print(",");
    Serial.print("1");                                     //Fresh Data
    Serial.print(",");
  }
  else
  {
    Serial.print(mySTC3x.getCO2(), 2);
    Serial.print(",");
    Serial.print("0");                                     //Data not fresh
    Serial.print(",");
  }



  //==============================
  //==========READ SGP40==========
  //==============================
  //minimum update rate = 1Hz

  Serial.println(mySGP40.getVOCindex()); //Get the VOC Index using the default RH (50%) and T (25C)

#endif



  //================================
  //=========SPACE & DELAY==========
  //================================
  //Serial.println("");// Uncomment this line to add some space between readings for the Serial Monitor
  delay(1000); //Wait 1 second - the Sensirion VOC algorithm expects a sample rate of 1Hz

}//end loop()





void errorDecoder(SHTC3_Status_TypeDef message)                             // The errorDecoder function prints "SHTC3_Status_TypeDef" resultsin a human-friendly way
{
  switch (message)
  {
    case SHTC3_Status_Nominal : Serial.print("Nominal"); break;
    case SHTC3_Status_Error : Serial.print("Error"); break;
    case SHTC3_Status_CRC_Fail : Serial.print("CRC Fail"); break;
    default : Serial.print("Unknown return code"); break;
  }
}

Troubleshooting

Resources and Going Further

Now that you've successfully got your MicroMod Environmental Function Board up and running, it's time to incorporate it into your own project! For more information, check out the resources below:

Need some inspiration for your next project? Check out some of these related tutorials with MicroMod:

Getting Started with MicroMod

Dive into the world of MicroMod - a compact interface to connect a microcontroller to various peripherals via the M.2 Connector!

MicroMod Machine Learning Carrier Board Hookup Guide

Get hacking with this tutorial on our Machine Learning Carrier Board!

MicroMod Main Board Hookup Guide

The MicroMod Main Board - Single and Double are specialized carrier boards that allow you to interface a Processor Board with a Function Board(s). The modular system allows you to add an additional feature(s) to a Processor Board with the help of a Function Board(s). In this tutorial, we will focus on the basic functionality of the Main Board - Single and Main Board - Double.

Or check out this related blog post.