Skip to content

Instantly share code, notes, and snippets.

@tomtor
Last active June 2, 2017 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomtor/d63fb0eef60ed15d5c67d220e524acdc to your computer and use it in GitHub Desktop.
Save tomtor/d63fb0eef60ed15d5c67d220e524acdc to your computer and use it in GitHub Desktop.
CCS811 low power Arduino sketch
/***************************************************
This is an example for the CCS811 digital TVOC/eCO2 Sensor by CCMOSS/AMS
http://www.ccmoss.com/gas-sensors#CCS811
Updated: March 28, 2017
The sensor uses I2C protocol to communicate, and requires 2 pins - SDA and SCL
Another GPIO is also required to assert the WAKE pin for communication. this
pin is passed by an argument in the begin function.
A breakout board is available: https://github.com/AKstudios/CCS811-Breakout
The ADDR pin on the sensor can be connected to VCC to set the address as 0x5A.
The ADDR pin on the sensor can be connected to GND to set the address as 0x5B.
Written by Akram Ali from AKstudios (www.akstudios.com)
GitHub: https://github.com/AKstudios/
STM32 Sleep and low power code by Tom Vijlbrief
****************************************************/
#include <CCS811.h>
#define ADDR 0x5A
//#define ADDR 0x5B
#define WAKE_PIN PB12
// Defined for power and sleep functions pwr.h and scb.h
#include <libmaple/pwr.h>
#include <libmaple/scb.h>
#include <RTClock.h>
RTClock rt(RTCSEL_LSI, 39); // 1 milli second alarm
void sleepMode(bool deepSleepFlag)
{
// Clear PDDS and LPDS bits
PWR_BASE->CR &= PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF;
// Set PDDS and LPDS bits for standby mode, and set Clear WUF flag (required per datasheet):
PWR_BASE->CR |= PWR_CR_CWUF;
// Enable wakeup pin bit.
PWR_BASE->CR |= PWR_CSR_EWUP;
SCB_BASE->SCR |= SCB_SCR_SLEEPDEEP;
// System Control Register Bits. See...
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Cihhjgdh.html
if (deepSleepFlag) {
// Set Power down deepsleep bit.
PWR_BASE->CR |= PWR_CR_PDDS;
// Unset Low-power deepsleep.
PWR_BASE->CR &= ~PWR_CR_LPDS;
} else {
adc_disable(ADC1);
adc_disable(ADC2);
#if STM32_HAVE_DAC
dac_disable_channel(DAC, 1);
dac_disable_channel(DAC, 2);
#endif
// Unset Power down deepsleep bit.
PWR_BASE->CR &= ~PWR_CR_PDDS;
// set Low-power deepsleep.
PWR_BASE->CR |= PWR_CR_LPDS;
}
// Now go into stop mode, wake up on interrupt
asm(" wfi");
// Clear SLEEPDEEP bit so we can use SLEEP mode
SCB_BASE->SCR &= ~SCB_SCR_SLEEPDEEP;
}
void setSpeed()
{
#if F_CPU == 8000000UL
// nothing to do, using about 8 mA
#elif F_CPU == 16000000UL
rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_2);
#elif F_CPU == 48000000UL
rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_6);
#elif F_CPU == 72000000UL
rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_9);
#else
#error "Unknown F_CPU!?"
#endif
}
int sleepTime;
void AlarmFunction () {
// We always wake up with the 8Mhz HSI clock!
// So adjust the clock if needed...
setSpeed();
extern volatile uint32 systick_uptime_millis;
systick_uptime_millis += sleepTime;
}
void mdelay(int n, bool mode = false)
{
sleepTime = n;
const int interval = 10000;
while (n > 0) {
//iwdg_feed();
time_t nextAlarm = rt.getTime() + (n > interval ? interval : n); // Calculate from time now.
rt.createAlarm(&AlarmFunction, nextAlarm);
sleepMode(mode);
n -= interval;
}
}
void msleep(uint32_t ms)
{
uint32_t start = rt.getTime();
while (rt.getTime() - start < ms) {
asm(" wfi");
}
}
void allInput()
{
adc_disable(ADC1);
adc_disable(ADC2);
pinMode(PA0, INPUT_ANALOG);
pinMode(PA1, INPUT_ANALOG);
pinMode(PA2, INPUT_ANALOG);
pinMode(PA3, INPUT_ANALOG);
pinMode(PA4, INPUT_ANALOG);
pinMode(PA5, INPUT_ANALOG);
pinMode(PA6, INPUT_ANALOG);
pinMode(PA7, INPUT_ANALOG);
pinMode(PA8, INPUT_ANALOG);
pinMode(PA9, INPUT_ANALOG);
pinMode(PA10, INPUT_ANALOG);
pinMode(PA11, INPUT_ANALOG);
pinMode(PA12, INPUT_ANALOG);
pinMode(PA13, INPUT_ANALOG);
pinMode(PA14, INPUT_ANALOG);
pinMode(PA15, INPUT_ANALOG);
pinMode(PB0, INPUT_ANALOG);
pinMode(PB1, INPUT_ANALOG);
pinMode(PB2, INPUT_ANALOG);
pinMode(PB3, INPUT_ANALOG);
pinMode(PB4, INPUT_ANALOG);
pinMode(PB5, INPUT_ANALOG);
pinMode(PB6, INPUT_ANALOG);
pinMode(PB7, INPUT_ANALOG);
pinMode(PB8, INPUT_ANALOG);
pinMode(PB9, INPUT_ANALOG);
pinMode(PB10, INPUT_ANALOG);
pinMode(PB11, INPUT_ANALOG);
pinMode(PB12, INPUT_ANALOG);
pinMode(PB13, INPUT_ANALOG);
pinMode(PB14, INPUT_ANALOG);
pinMode(PB15, INPUT_ANALOG);
}
void blinkN(int n, int d = 400, int t = 800)
{
pinMode(LED_BUILTIN, OUTPUT);
for (int i = 0; i < n; i++) {
digitalWrite(LED_BUILTIN, 0);
mdelay(5);
digitalWrite(LED_BUILTIN, 1);
mdelay(d);
}
pinMode(LED_BUILTIN, INPUT_ANALOG);
mdelay(t);
}
CCS811 sensor;
void setup()
{
allInput();
Serial.begin(115200);
delay(1000);
Serial.println("CCS811 test");
if (!sensor.begin(uint8_t(ADDR), uint8_t(WAKE_PIN))) {
Serial.println("Initialization failed.");
while (1)
;
}
}
void loop()
{
static int loop;
static int co2;
static int tvoc;
//pinMode(LED_BUILTIN, OUTPUT);
//digitalWrite(LED_BUILTIN, 0);
byte status = sensor.readStatus();
//Serial.println(status, HEX);
if (status == 0x98) {
sensor.compensate(22, 50.73); // replace with t and rh values from sensor
sensor.getData();
Serial.println();
co2= sensor.readCO2();
tvoc= sensor.readTVOC();
Serial.print("CO2 concentration : "); Serial.print(co2); Serial.println(" ppm");
Serial.print("TVOC concentration : "); Serial.print(tvoc); Serial.println(" ppb");
}
Serial.print(++loop); Serial.print(' ');
Serial.flush();
//digitalWrite(LED_BUILTIN, 1);
blinkN(co2 ? (co2+50) / 100 : 2);
blinkN((tvoc + 5) / 10);
mdelay(10000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment