KEYESTUDIO CCS811

144 views
Skip to first unread message

Glen Gilchrist

unread,
Feb 6, 2021, 1:20:30 PM2/6/21
to Annex WiFi RDS
Firstly - thanks for having me --- glad to be here.

I came via the CMM2 forum (https://www.thebackshed.com/)  -- I am a UK based educator using the CMM2 to teach programming and interfacing with the "real world".

I arrived at Annex HQ due to a desire to make an in class environment sensor and notably serve up the data to a web page.  Couple this with the desire to continue in a BASIC-like language and here I am.

So -- forgive the naive Qs ;-)

I can see that most of the sensors I want to use are "native" to Annex, but I am keen to use :KEYESTUDIO CCS811 to monitor in class CO2 (see KS0457 keyestudio CCS811 Carbon Dioxide Air Quality Sensor - Keyestudio Wiki)  as this is an I2C device I am assuming that this will be fine - just not native?

Can someone give me a steer on how I would make this work in Annex?

Cheers
Nim

Electroguard

unread,
Feb 6, 2021, 5:59:44 PM2/6/21
to Annex WiFi RDS
Hi Nim,
Generally speaking, much of the Annex device functionality is based on appropriate converted arduino libraries, and although the arduino code is not relevant to Annex, an understanding of how arduino is using a device can offer clues of how it might be tackled with Annex - but keep in mind that arduino sketches tend to loop around the same main code and branch on variable changes, whereas Annex scripts tend to wait for interrupts to branch on.

CiccioCB has implemented some low-level I2C instructions, so assuming you know the device address and what registers to read/write, hopefully you can find an existing I2C example which you might hack into your shape (remember that gas detectors usually need an initial warm-up and calibration period).

I can't remember details off the top of my head, but someone on the forum has already published a very nice petrol sniffer which might make a good starting point.

cicciocb

unread,
Feb 7, 2021, 3:54:42 AM2/7/21
to Annex WiFi RDS
HI Nim,
as Robin (Electroguard) said, the device can be managed directly using the I2C functions creating a kind of library support in basic.
For sure this requires some expertise into creating the required functions in basic compared to the "native" support where the "Arduino'' driver is implemented directly into the code.

If there is a sufficient interest, the driver can be easily implemented in the code like is the case for other devices.
Obviously for memory reasons (space available in the devices) not all the drivers can be implemented so the choice must be done in the global general interest.

It could be interesting to create a kind of post where people requests for a particular driver and decide which worth to implement.

PeterN

unread,
Feb 7, 2021, 7:18:22 AM2/7/21
to Annex WiFi RDS
From a western Germany submerged in snow, I can only try to justify my personal ranking here:
The native support of the gas-environment-sensor may currently meet with great interest due to the Corona situation in the school and education sector.
CAN bus is technically very interesting but also technically quite demanding and less interesting in the hobby area.

I would order a gas sensor immediately if there was a signal in this direction.

Glen Gilchrist

unread,
Feb 7, 2021, 7:53:46 AM2/7/21
to Annex WiFi RDS
That is exactly my use case -- I'll let you know how i get on.

Nim

PeterN

unread,
Feb 13, 2021, 7:37:31 PM2/13/21
to Annex WiFi RDS
After I received a CCS811, I tried to build a minimal I2C driver for it in ANNEX32. 
With an ESP32, this works quite well now.

eCO2 and TVOC shown at wlog every 2 seconds

This is the wlog-output in "not silent" mode:

---start-I2C-scan---
found a device at I2C-Adr dec 90    , hex 5A
---end-I2C-scan---

-------------CCS811-Sensor_Status:-------------
STATUSBYTE  :    17    = &b10001
 Boot Mode
 valid firmware loaded
 DATA available to read
 no Error
----------------------------------------
 
Change from BOOT-Mode to  App Mode

-------------CCS811-Sensor_Status:-------------
STATUSBYTE  :    152    = &b10011000
 Application Mode
 valid firmware loaded
 DATA available to read
 no Error
----------------------------------------
 
Set MEAS_MODE_REG to &b:10000 = read new Data once per 1 second

-------------CCS811-Sensor_Status:-------------
STATUSBYTE  :    152    = &b10011000
 Application Mode
 valid firmware loaded
 DATA available to read
 no Error
----------------------------------------
 
eCO2 = 0    TVOC = 0
eCO2 = 0    TVOC = 0
eCO2 = 400    TVOC = 0
eCO2 = 403    TVOC = 0
eCO2 = 400    TVOC = 0
eCO2 = 463    TVOC = 9
eCO2 = 441    TVOC = 6
eCO2 = 435    TVOC = 5
eCO2 = 435    TVOC = 5


And this is my code for it:


CODE: xxxx.bas

'#######################################################################
'Show AIR QUALITY with a CCS811 CO2-TVOC-Sensor at I2C-pins of an ESP32
'#######################################################################
' DB9JG 2021/02/13 V1.0
Version$           = "V1.0"

SILENT             = 0    '1 => suppress  all messages   0 => show some status-messages via  wlog

SDA_PIN            = 21   'SDA=21 at ESP32
SCL_PIN            = 22   'SCL=22 at ESP32
CCS811temp         = 0
CCS811_schreiben   = &hb4 '  Die I2C-Adresse von CCS811 zum schreiben hB4 =1011 0100    7 Bit Plus das  Bit 0 für lesen (0)
CCS811_lesen       = &hb5 '  Die I2C-Adresse von CCS811 zum lesen     hB5 = 10110101    7 Bit Plus das  Bit 0 für schreiben (1)
STATUS_REG         = &h00
MEAS_MODE_REG      = &h01
ALG_RESULT_DATA    = &h02
ENV_DATA           = &h05
NTC_REG            = &h06
THRESHOLDS         = &h10
BASELINE           = &h11
HW_ID_REG          = &h20
ERROR_ID_REG       = &hE0
APP_START_REG      = &hF4
SW_RESET           = &hFF
CCS811_I2C_ADR     = &h5A
GPIO_WAKE          = &h5
DRIVE_MODE_IDLE    = &h0
DRIVE_MODE_1SEC    = &h10
DRIVE_MODE_10SEC   = &h20
DRIVE_MODE_60SEC   = &h30
INTERRUPT_DRIVEN   = &h8
THRESHOLDS_ENABLED = &h4
Dim BUFFER(10)  'I2C-Sende- / Empfangspuffer.

if not silent GOSUB I2C_SCANNER  


I2C.SETUP SDA_PIN, SCL_PIN    ' set I2C ports
GOSUB SHOW_CCS811_STATUS

GOSUB CCS811_GO_APP_MODE   'leave BOOT-Mode
GOSUB SHOW_CCS811_STATUS   

GOSUB CCS811_SET_MODE      'CCS811 generates eCO2 and TVOC once per second
GOSUB SHOW_CCS811_STATUS

TIMER0 2000, CCS811_SHOW   'fetch eCO2 and TVOC from CCS811 sensor

WAIT

end '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!



'######################################################################
CCS811_SHOW:
GOSUB CCS811_READ
wlog "eCO2 = ";eCO2,"TVOC = ";TVOC
return

'######################################################################
CCS811_READ:
' Bit 3 = Data Ready 0:no new Data 1:new Data
' Bit 0 Error dedection 0:no Error 1: Error on i2c or Sensor
i2c.writeRegByte CCS811_I2C_ADR, STATUS_REG , 0
i2c.ReqFrom CCS811_I2C_ADR,1
CCS811temp = i2c.read

If CCS811temp and 8 then                               'if Bit3 of status_register =1 then DATA_available
  i2c.writeRegByte CCS811_I2C_ADR, ALG_RESULT_DATA ,0  'selects the Result mailbox
  i2c.ReqFrom CCS811_I2C_ADR, 8
  for i = 1 to 8                                       'The Result mailbox contains  8 Bytes
    BUFFER(i)  = i2c.read
  next
  eCO2 = 256*BUFFER(1) + BUFFER(2)    'eCO2 ppm
  TVOC = 256*BUFFER(3) + BUFFER(4)    'eTVOC
else
  eCO2 = 0
  TVOC = 0
end if

return
'#########################################################################################################################################################




'######################################################################
SHOW_CCS811_STATUS:
'----------------------Status request-------------------------------------
' Bit 7 FW_Mode = 0:Boot Mode 1:Application Mode
' Bit 4 =  Application Firmware loaded 0: no 1:Valid application loaded
' Bit 3 = Data Ready 0:no new Data 1:new Data
' Bit 0 Error dedection 0:no Error 1: Error on i2c or Sensor
if silent return

i2c.writeRegByte CCS811_I2C_ADR, STATUS_REG , 0
i2c.ReqFrom CCS811_I2C_ADR,1
CCS811temp = i2c.read
pause  25
wlog ""
wlog "-------------CCS811-Sensor_Status:-------------"
wlog "STATUSBYTE  :",CCS811temp,"= &b"; bin$(CCS811temp)
If CCS811temp and 128 then
  wlog " Application Mode"
else
  wlog " Boot Mode"
end if
If CCS811temp and 16 then
  wlog " valid firmware loaded"
else
  wlog "  NO valid firmware loaded!"
end if
If CCS811temp and 8 then
  wlog " DATA available to read"
else
  wlog " no DATA available to read"
end if
If CCS811temp and 1 then
  wlog " Error on i2c or sensor!!"
  'Read the ERROR-ID
  i2c.writeRegByte CCS811_I2C_ADR, ERROR_ID_REG , 0
  i2c.ReqFrom CCS811_I2C_ADR,1
  CCS811temp = i2c.read
  wlog " ERROR_ID_REG : dec",CCS811temp,"= &b";bin$(CCS811temp)
else
  wlog " no Error"
end if
wlog "----------------------------------------"
wlog " "
RETURN



'######################################################################
CCS811_GO_APP_MODE:
'----------------------- Change to Application Mode -------------------
if not silent wlog "Change from BOOT-Mode to  App Mode"
'i2c.writeRegByte CCS811_I2C_ADR, APP_START_REG,0
' geht nicht da value geschreiben wird, Register soll aber nur angewählt werden
'Aber DAS funktioniert:
i2c.begin CCS811_I2C_ADR
I2c.write APP_START_REG
' value hier NICHT schreiben!!!
'  i2c.write value
i2c.end
pause 10
return

'######################################################################
CCS811_SET_MODE:
'------------------------Modus einstellen---------------------------
MODUS = &b00010000      'Bit7=0reserved, 6-4=001Mode 1 jede sekunde neue daten, 3=0 Interrupt für neue Daten aus, 2=0 Interrupt Mode Normal,  1-0 =00 Reserved
if not silent wlog "Set MEAS_MODE_REG to &b:"; bin$(MODUS); " = read new Data once per 1 second"
i2c.writeRegByte CCS811_I2C_ADR, MEAS_MODE_REG, MODUS
pause  10
return


'######################################################################
I2C_SCANNER:
'I2C Address Scanner
'print and wlog  the address of the I2C-devices found

I2C.SETUP 21, 22  ' set I2C port on pins 21 and 22
print "---start-I2C-scan---"
wlog  "---start-I2C-scan---"
for i = 0 to 120
  i2c.begin i
  if i2c.end = 0 then
    print "found a device at I2C-Adr dec "; i ,", hex "; hex$(i)
    wlog  "found a device at I2C-Adr dec "; i ,", hex "; hex$(i)
    pause 10
  end if
next i
print "---end-I2C-scan---"
wlog  "---end-I2C-scan---"
return




ciccio cb

unread,
Feb 14, 2021, 3:24:23 AM2/14/21
to Annex WiFi RDS
Very good news Peter,
you did a very good job.

I will buy one and I'll try to integrate the functions directly in the code as it seems very easy to integrate

--
You received this message because you are subscribed to the Google Groups "Annex WiFi RDS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to annex_wifi_rd...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/annex_wifi_rds/779b55fb-a171-4029-9069-ebd22621e9d8o%40googlegroups.com.

PeterN

unread,
Feb 14, 2021, 10:43:19 AM2/14/21
to Annex WiFi RDS
Hi Francesco,
the concept  of using mailbox-registers in the CCS811 was new for me and required a bit more reading in the datasheet:-)
I found a very basic template from mirco99 in BASCOM and used that as a stating point.
As my favorite teacher said along time ago:  "You don't have to know about all but know where to find it."
I am still not shure about this sensor as it seems to detect CO2 not the direct way, but calculates eCO2 from TVOC. I will read more about that asap.

PeterN

unread,
Feb 14, 2021, 12:23:10 PM2/14/21
to Annex WiFi RDS
 More Info about CCS811 Burn-in (48h) and Run-in (20 Min) requirement etc at e.g.

PeterN

unread,
Feb 16, 2021, 10:41:42 AM2/16/21
to Annex WiFi RDS
Hi Francesco and Nim

I have carried out further tests with the CCS811 and have arrived at a CO2 traffic light.

As the CCS811 uses "I2C clock stretching" according to its datasheet, I tried to use that in ANNEX32.
The help says: 
I2C.SETUP sda_pin, scl_pin [,freq [,stretch]]
But I could not find an  explanation/range  for  the parameter stretch (0/1?)  and freq (in kHz?)
Did I oversee anything?


My intermediate status code for the CO2-Traffic-Light:

CODE: xxxx.bas

'#######################################################################
' CO2-TRAFFIC-LIGHT 
'Shows AIR QUALITY with 
' - CCS811 CO2-TVOC-Sensor at I2C-pins of an ESP32
' - 3 LEDs (green, yellow, red to show the range of CO2 ppm

'to do in next version:
' - Webinterface for exact CO2 ppm   and TVOV ppb
' - BEEP if poor qaulity formore than  X seconds
' - eMail if poor quality  
'#######################################################################
' DB9JG 2021/02/13 V1.0
Version$           = "V1.1"

SILENT             = 0    '1 => suppress  all messages   0 => show some status-messages via  wlog

MAX_GREEN          = 500  'upper limmit for the green LED range from 300 to MAX_GREEN
MAX_YELLOW         = 600  'upper limmit for the yellow LED range from (MAX_GREEN + 1)to MAX_YELLOW
LED_RED            = 14
LED_YELLOW         = 13
LED_GREEN          = 12

pin.mode LED_RED,     OUTPUT
pin.mode LED_YELLOW,  OUTPUT
pin.mode LED_GREEN,   OUTPUT

PIN(LED_GREEN)  = 1   'show that the device is working

I2C.SETUP SDA_PIN, SCL_PIN ,100000,1   ' set I2C ports
if not silent GOSUB I2C_SCANNER

GOSUB SHOW_CCS811_STATUS

GOSUB CCS811_GO_APP_MODE   'leave BOOT-Mode
GOSUB SHOW_CCS811_STATUS

GOSUB CCS811_SET_MODE      'CCS811 generates eCO2 and TVOC once per second
GOSUB SHOW_CCS811_STATUS

TIMER0 1050, CCS811_SHOW   'fetch eCO2 and TVOC from CCS811 sensor

WAIT

end '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!



'######################################################################
CCS811_SHOW:
GOSUB CCS811_READ
gosub CO2_TRAFFIC_LIGHT

wlog "eCO2 = ";eCO2,"TVOC = ";TVOC
return

'######################################################################
CCS811_READ:
' Bit 3 = Data Ready 0:no new Data 1:new Data
' Bit 0 Error dedection 0:no Error 1: Error on i2c or Sensor
i2c.writeRegByte CCS811_I2C_ADR, STATUS_REG , 0
i2c.ReqFrom CCS811_I2C_ADR,1
CCS811temp = i2c.read

If CCS811temp and 8 then                               'if Bit3 of status_register =1 then DATA_available
  i2c.writeRegByte CCS811_I2C_ADR, ALG_RESULT_DATA ,0  'selects the Result mailbox
  i2c.ReqFrom CCS811_I2C_ADR, 8
  for i = 1 to 8                                       'The Result mailbox contains  8 Bytes
    BUFFER(i)  = i2c.read
  next
  eCO2 = 256*BUFFER(1) + BUFFER(2)    'eCO2 ppm
  TVOC = 256*BUFFER(3) + BUFFER(4)    'eTVOC
else
  eCO2 = 0
  TVOC = 0
end if

return
'#########################################################################################################################################################


'######################################################################
CO2_TRAFFIC_LIGHT:

'PIN(LED_RED)    = 1 - PIN(LED_RED)
'PIN(LED_YELLOW) = 1 - PIN(LED_YELLOW)
'PIN(LED_GREEN)  = 1 - PIN(LED_GREEN)
'
SELECT CASE eCO2
    
  CASE 300 to 500 :    'GREEN range
    PIN(LED_GREEN)  = 1 - PIN(LED_GREEN)
    PIN(LED_RED)    = 0
    PIN(LED_YELLOW) = 0
    
  CASE 501 to 700  :  'YELLOW range
    PIN(LED_YELLOW)  = 1 - PIN(LED_YELLOW)
    PIN(LED_RED)    = 0
    PIN(LED_GREEN) = 0
    
  CASE 701 to 9999 : 'RED range
    PIN(LED_RED)  = 0
    pause 200
    PIN(LED_RED)  = 1 - PIN(LED_RED)
    PIN(LED_GREEN)  = 0
    PIN(LED_YELLOW) = 0
    
  CASE ELSE:
    PIN(LED_RED)    = 1
    PIN(LED_YELLOW) = 1
    PIN(LED_GREEN)  = 1
    
END SELECT



return
'I2C.SETUP SDA_PIN, SCL_PIN    ' set I2C ports

PeterN

unread,
Feb 16, 2021, 10:47:59 AM2/16/21
to Annex WiFi RDS

cicciocb

unread,
Feb 16, 2021, 11:16:48 AM2/16/21
to Annex WiFi RDS
Hi Peter,
first of all the code stretching option is applicable only to the ESP8266 (there is an error in the doc as this option is not present for the ESP32).
The reason is that the ESP32 supports, by default, the clock stretching because it relies on an H/W I2C modules (the ESP8266 use a SW emulation instead).

I do not understand if you are facing to communication problems with this module ....

PeterN

unread,
Feb 16, 2021, 11:27:34 AM2/16/21
to Annex WiFi RDS
Thanks Francesco!

I had some seldom strange readings from the sensor and had the idea of  trying to optimize the I2C-communication.

Over all IT WORKS GOOD!
Reply all
Reply to author
Forward
0 new messages