目录app
1、硬件链接oop
2、模拟IIC测试
头文件ui
C文件spa
3、CCS811过程.net
VCC - 3.3V
SCL和SDA接IIC
WAK接地(也能够由单片机引脚控制)
#ifndef __MYIIC_H #define __MYIIC_H #include "main.h" void IIC_Init(void); void IIC_Start(void); void IIC_Stop(void); void IIC_Send_Byte(uint8_t txd); uint8_t IIC_Read_Byte(unsigned char ack); uint8_t IIC_Wait_Ack(void); void IIC_Ack(void); void IIC_NAck(void); #endif
#include "my_iic.h" #include "delay.h" #define HT_SDA GPIO_PIN_7 //B7 #define HT_SCK GPIO_PIN_6 //B6 static void SDA_IN(){ GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pins : PAPin PAPin */ GPIO_InitStruct.Pin = HT_SDA; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } static void SDA_OUT(){ GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = HT_SDA; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void SDA_HIGH(){ HAL_GPIO_WritePin(GPIOB, HT_SDA, GPIO_PIN_SET); } void SDA_LOW(){ HAL_GPIO_WritePin(GPIOB, HT_SDA, GPIO_PIN_RESET); } void SCL_HIGH(){ HAL_GPIO_WritePin(GPIOB, HT_SCK, GPIO_PIN_SET); } void SCL_LOW(){ HAL_GPIO_WritePin(GPIOB, HT_SCK, GPIO_PIN_RESET); } GPIO_PinState read_sdaval(){ return HAL_GPIO_ReadPin(GPIOB,HT_SDA); } void IIC_Start(void) { SDA_OUT(); SDA_HIGH(); SCL_HIGH(); delay_us(5); SDA_LOW();//START:when CLK is high,DATA change form high to low delay_us(5); SCL_LOW(); delay_us(5); } void IIC_Stop(void) { SDA_OUT(); SCL_LOW(); SDA_LOW();//STOP:when CLK is high DATA change form low to high delay_us(5); SCL_HIGH(); SDA_HIGH(); delay_us(5); } uint8_t IIC_Wait_Ack(void) { uint8_t ucErrTime=0; SDA_IN(); // SDA_HIGH();delay_us(1); SCL_HIGH();delay_us(1); while(read_sdaval()) { ucErrTime++; delay_us(1); if(ucErrTime>250) { IIC_Stop(); return 1; } } SCL_LOW(); return 0; } void IIC_Ack(void) { SCL_LOW(); SDA_OUT(); SDA_LOW(); delay_us(20); SCL_HIGH(); delay_us(5); SCL_LOW(); } void IIC_NAck(void) { SCL_LOW(); SDA_OUT(); SDA_HIGH(); delay_us(5); SCL_HIGH(); delay_us(5); SCL_LOW(); } void IIC_Send_Byte(uint8_t txd) { uint8_t t; SDA_OUT(); SCL_LOW(); for(t=0;t<8;t++) { if((txd&0x80)>>7) SDA_HIGH(); else SDA_LOW(); txd<<=1; delay_us(50); SCL_HIGH(); delay_us(50); SCL_LOW(); delay_us(50); } } uint8_t IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN(); for(i=0;i<8;i++ ) { SCL_LOW(); delay_us(50); SCL_HIGH(); receive<<=1; delay_us(25); if(read_sdaval()) { receive++; } delay_us(25); } if (!ack) IIC_NAck();//nACK else IIC_Ack(); //ACK return receive; }
判断是否是0x81 (129),若是不是则IIC逻辑问题或者电平问题(供电电压在1.8V-3.6V,以及对应匹配电阻)。
若是APP_VALID值不为1,则内部MCU的程序不对,须要烧录(通常不会出现这个问题,也有人遇到过,见
CCS811二氧化碳传感器基于Arduino的升级固件(刷机)教程)
从boot模式切换到APP模式才能够进行测量。只需在地址0xF4寄存器内写1Byte操做。
经过读取状态值,判断切换到APP模式是否成功。状态位为FW_MODE
在MEAS_MODE写入参数,例如1秒测一次写0x10。注意不一样周期切换时间可能须要数十秒的时间。
从地址0x02读取8Byte数据,其中测量结果对应Byte位见下表
#ifndef CCS811_h #define CCS811_h #include "delay.h" #include "my_iic.h" #define boolean uint8_t #define byte uint8_t typedef struct { uint16_t eco2; uint16_t tvoc; uint8_t status; uint8_t error_id; uint8_t hw_id; uint16_t raw_data; } ccs811_measurement_t; #define CCSADDR 0x5A<<1 // when I2C_ADDR pin is LOW // #define CCSADDR 0x5B<<1 when I2C_ADDR pin is HIGH #define READ 0xB5 #define WRIT 0xB4 // Registers for CCS811 #define STATUS 0x00 #define MEAS_MODE 0x01 #define ALG_RESULT_DATA 0x02 #define RAW_DATA 0x03 #define ENV_DATA 0x05 #define NTC 0x06 #define THRESHOLDS 0x10 #define BASELINE 0x11 #define HW_ID 0x20 #define HW_Version 0x21 #define FW_Boot_Version 0x23 #define FW_App_Version 0x24 #define ERROR_ID 0xE0 #define SW_RESET 0xFF #define MODE0 0x00 #define MODE1 0x10 #define MODE2 0x20 #define MODE3 0x30 #define MODE4 0x40 extern ccs811_measurement_t CCS; void readStatus(void); void readHW_ID(void); void readErrorID(void); void readALG_RESULT_DATA(uint8_t *data); void app_Start(void); int readTVOC(void); int readCO2(void); void getData(void); void compensate(float t, float rh); void setMode(uint8_t mode); void reset(void); void sleep(void); #endif
C文件
#include "CCS811.h" ccs811_measurement_t CCS; #define nWAKE_HIGN() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_5) #define nWAKE_LOW() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_5) #define nINT_LOW() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_4) #define nINT_HIGN() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_4) //查看是否有新数据 返回值 1:有 // 0:没有 uint8_t CheckData_Ready(void) { readStatus(); if((CCS.status&8)==1) return 1; else return 0; } //读取一个bit数据 uint8_t CCS811_ReadOneByte(uint8_t ReadAddr) { uint8_t temp=0; nWAKE_LOW(); delay_us(50);//必须等待50us IIC_Start(); //addr接地,7位地址为0x5A,读地址为AB,写地址AA IIC_Send_Byte(WRIT); //发送写命令 if(IIC_Wait_Ack()){IIC_Stop(); return 255;} //else nINT=0; IIC_Send_Byte(ReadAddr); if(IIC_Wait_Ack()){IIC_Stop(); return 255;} //if(!IIC_Wait_Ack()){nINT=1;delay_ms(200);nINT=0;delay_ms(200);} delay_ms(1); IIC_Start(); IIC_Send_Byte(READ); if(IIC_Wait_Ack()){IIC_Stop(); return 255;} temp=IIC_Read_Byte(0); IIC_Stop(); nWAKE_HIGN(); delay_us(50); return temp; } void CCS811_WriteOneByte(uint8_t RegAddr,uint8_t DataToWrite) { nWAKE_LOW(); delay_us(50); IIC_Start(); IIC_Send_Byte(WRIT); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(RegAddr); IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); IIC_Wait_Ack(); IIC_Stop(); nWAKE_HIGN(); } //测量数据前必须开启 void app_Start(void) { nWAKE_LOW(); delay_us(50); IIC_Start(); IIC_Send_Byte(WRIT); //发送写命令 if(IIC_Wait_Ack()) { IIC_Stop();return; } IIC_Send_Byte(0xF4); delay_us(180); //必须等待180us以上才可以收到应答 if(IIC_Wait_Ack()){IIC_Stop();return;} IIC_Stop(); nWAKE_HIGN(); } void readStatus(void) { CCS.status=CCS811_ReadOneByte(STATUS); } void readHW_ID(void) { CCS.hw_id=CCS811_ReadOneByte(HW_ID); } void readErrorID(void) { CCS.error_id=CCS811_ReadOneByte(ERROR_ID); } void setMode(uint8_t mode) { // nWAKE=0; // delay_us(50); CCS811_WriteOneByte(MEAS_MODE,mode); // nWAKE=1; } //一次读8bit数据,前2bit为eco2数据,接着2bit为tvoc数据 //当status第五位为1时有新数据。 void getData(void) { uint8_t i,buffer[8]; nWAKE_LOW(); delay_us(50); IIC_Start(); IIC_Send_Byte(WRIT); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(ALG_RESULT_DATA); IIC_Wait_Ack(); IIC_Stop(); delay_us(50); IIC_Start(); IIC_Send_Byte(READ); //发送写命令 IIC_Wait_Ack(); for(i=0;i<8-1;i++) buffer[i]=IIC_Read_Byte(1); buffer[i]=IIC_Read_Byte(0); IIC_Stop(); nWAKE_HIGN(); CCS.eco2 = ((uint16_t)buffer[0] << 8) + buffer[1]; CCS.tvoc = ((uint16_t)buffer[2] << 8) + buffer[3]; CCS.status=buffer[4]; } //睡眠模式 void sleep(void) { CCS811_WriteOneByte(MEAS_MODE,0x00000000); } //软重置,回到boot模式 void reset(void) { uint8_t ResetData[4]={0X11,0XE5,0X72,0X8A}; nWAKE_LOW(); delay_us(50); IIC_Start(); IIC_Send_Byte(WRIT); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(SW_RESET); IIC_Wait_Ack(); IIC_Send_Byte(0X11); IIC_Wait_Ack(); IIC_Send_Byte(0XE5); IIC_Wait_Ack(); IIC_Send_Byte(0X72); IIC_Wait_Ack(); IIC_Send_Byte(0X8A); IIC_Wait_Ack(); IIC_Stop(); nWAKE_HIGN(); }
main.c
/** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(1000); readHW_ID(); printf("id:%d\r\n",CCS.hw_id); readStatus(); printf("sta0:%d\r\n",CCS.status); app_Start(); readStatus(); printf("sta1:%d\r\n",CCS.status); setMode(0x10); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_Delay(998); getData(); printf("eco2:%d",CCS.eco2); printf("tvoc:%d\r\n",CCS.tvoc); readStatus(); printf("sta:%d\r\n",CCS.status); } /* USER CODE END 3 */ }