【英飞凌XENSIV™ PAS CO2传感器】传感器驱动设计
[复制链接]
一、准备工作
硬件方面是在进行N32G430测评时做的EVA板上直接预留了,正好用N32作为主控进行通信。
接下来就要进行软件驱动的设计,了解测量的基本结构。
二、软件结构
1、XENSIVTM PAS CO2开始测量的基本操作
检查初始化是否正确,可以通过检查传感器状态寄存器来完成。
在开始测量之前,建议检查和设置压力补偿,可以通过外部的压力传感器数据进行写入补偿,寄存器的默认压力设置是1015hpa。
使用连续测量模式时,可以预先在两个测量周期配置寄存器中定义测量周期,注意配置完测量模式后,都会触发测量序列。
通过读取测量状态寄存器,可以检查测量序列是否完成,从而在二氧化碳浓度结果寄存器中是否有新的二氧化碳浓度值可用。
2、了解具体的寄存器参数
1)PROD_ID
地址:0x00
默认值:0x4F
注释:该寄存器显示设备的产品和版本ID,对该寄存器的写访问被忽略,由于修订版本的不同,该数据有可能不同,所以慎用。
2)SENS_STS
地址:0x01
默认值:0xC0
注释:这个寄存器显示和控制传感器的状态,对该寄存器只读位的写访问被忽略。
Field
|
Bits
|
Description
|
SEN_RDY
|
7
|
Sensor ready bit 该位表示上电复位后传感器的初始化是否已正确执行。 0:传感器未正确初始化。 1b:传感器已正确初始化。
|
PWM_DIS_ST
|
6
|
PWM_DIS pin status 该位表示在引脚PWM_DIS上读取的级别。 0:在引脚PWM_DIS读取低电平。 1:在引脚PWM_DIS读取高电平。 注意:这个位在引脚PWM_DIS的每次转换时都会更新。
|
ORTMP
|
5
|
Out-of-range temperature error bit (sticky bit) 该位表示是否检测到温度超出指定有效范围的情况。 0:没有发生错误。 1:出现错误。 通过设置SENS_STS.ORTMP_CLR清除此位。
|
ORVS
|
4
|
Out-of-range VDD12V error bit (sticky bit) 该位表示是否检测到VDD12V超出指定有效范围的条件。 0:没有发生错误。 1:出现错误。 通过设置位SENS_STS.ORVS_CLR清除此位。
|
ICCER
|
3
|
Communication error notification bit (sticky bit) 该位表示串行通信接口是否收到了无效的命令。 0:没有收到无效的命令。 1:收到无效的命令。 通过设置SENS_STS.ICCER_CLR清除此位。
|
ORTMP_CLR
|
2
|
Out-of-range temperature error clear bit 写入1清除SENS_STS.ORTMP。 这个位被读回为0
|
ORVS_CLR
|
1
|
Out-of-range VDD12V error clear bit 写入1清除SENS_STS.ORVS。 这个位被读回为0
|
ICCER_CLR
|
0
|
Communication error clear bit 写入1清除SENS_STS.ICCER。 这个位被读回为0
|
可以说这个状态寄存器是最重要的,在开机时就需要进行读取和设计。
3)MEAS_RATE_H与MEAS_RATE_L
寄存器MEAS_RATE_H和MEAS_RATE_L定义连续模式中使用的测量周期(1位= 1 s)。
例如:0FFFH以上的值被视为等于FFFH (4095 s), 0005H以下的值被视为等于0005 h (5 s),将一个无效的值写入此字段将产生一个通信错误(SENS_STS.ICCER)。
注意:当写入到MEAS_RATE_H和MEAS_RATE_L时,设备不会立即考虑新值。它在下一次从空闲模式到连续模式的转换时被内部锁存。
寄存器名称:MEAS_RATE_H
地址:0x02
默认值:0x00
注释:这个寄存器显示和控制传感器的状态,对该寄存器只读位的写访问被忽略。
Field
|
Bits
|
Description
|
0
|
7:4
|
这个位域应该用0H来写
|
VAL
|
3:0
|
连续模式下测量周期的MSB 该值与位域MEAS_RATE_L的拼接定义了连续模式下的测量周期。
|
注意:0x0f以上的值保留,将一个无效的值写入此字段将产生一个通信错误(SENS_STS.ICCER),并将位域设置为0x0f。
寄存器名称:MEAS_RATE_L
地址:0x03
默认值:0x3C
注释:连续模式下测量周期的LSB。
备注:0x00 ~ 0x04为保留值,将一个无效的值写入此字段将产生一个通信错误(SENS_STS.ICCER),并将位域设置为0x05。
4)MEAS_CFG
地址:0x04
默认值:0x24
注释:测量模式配置寄存器,定义了设备的操作设置。
Field
|
Bits
|
Description
|
Res
|
7:6
|
这个位域应该写入00b。
|
PWM_OUTEN
|
5
|
PWM output software enable bit 0:软件关闭PWM输出。 1:软件开启PWM输出。 注1:引脚PWM的实际状态取决于两者 MEAS_CFG.PWM_OUTEN和引脚PWM_DIS。 注2:该位自动设置在PWM_DIS引脚的高到低。
|
PWM_MODE
|
4
|
PWM mode configuration 0: PWM单脉冲模式。 1: PWM连续脉冲模式。
|
BOC_CFG
|
3:2
|
Baseline offset compensation configuration 00b:禁用自动基线偏移补偿(ABOC)。没有抵消补偿发生。 01b: ABOC启用。偏移量在每次BOC计算时定期更新。 注意:在单发模式下,ABOC校正因子被应用,但ABOC方案未激活且未更新。 10b:强制补偿。 注意:强制补偿完成后,设备自动将自身重新配置为ABOC (MEAS_CFG.BOC_CFG = 01b)。 11b:保留。
|
OP_MODE
|
1:0
|
传感器操作模式 00b:空闲模式。 01b:启用单发模式。将01b写入此字段会触发单个测量序列。该字段由固件自动重置。 10b:开启连续模式。 11b:保留(作为00b)。
|
5)CO2PPM_H与CO2PPM_L
寄存器CO2PPM_H和CO2PPM_L用于显示最后一次CO2浓度测量的结果(1 bit = 1 ppm)。
读取寄存器CO2PPM_L清除位MEAS_STS.DRDY。
在读取CO2浓度值时,用户应先读取CO2PPM_H寄存器,然后读取CO2PPM_L寄存器。
寄存器名称:CO2PPM_H
地址:0x05
默认值:0x00
注释:CO2浓度值的MSB。
寄存器名称:CO2PPM_L
地址:0x06
默认值:0x00
注释:CO2浓度值的LSB。
6)MEAS_STS
地址:0x07
默认值:0x00
注释:这个寄存器显示传感器的状态信息。对该寄存器只读位的写访问被忽略。
Field
|
Bits
|
Description
|
0
|
7:6
|
这个位域被读取为00b。
|
Res
|
5
|
保留
|
DRDY
|
4
|
Data ready bit (sticky bit) 该位表示寄存器中是否有新数据可用(CO2PPM_H和CO2PPM_L) 0:没有新的数据。 1:表示存在未读数据。这个位设置在每个测量序列的末尾。 通过读取CO2PPM_L清除该位。
|
INT_STS
|
3
|
INT pin status bit 这个位指示引脚INT是否已锁存到活动状态(在报警或数据准备好的情况下)。 0:引脚INT没有锁存到活动状态。 1:引脚INT已锁存到活动状态。该位设置在每个测量序列的末尾,以防出现锁存条件。 通过设置位MEAS_STS.INT_STS_CLR清除此位。
|
ALARM
|
2
|
Alarm notification (sticky bit) 这个位表示是否发生了阈值违反。 0:没有违规发生。 1:违反发生。该位设置在每个测量序列的末尾,以防违反。 通过设置位MEAS_STS.ALARM_CLR清除该位。
|
INT_STS_CLR
|
1
|
INT pin status clear bit 用1写入这个位可以清除位MEAS_STS.INT_STS和强制引脚INT到非活动级别。 这个位被读回为0b。
|
ALARM_CLR
|
0
|
Alarm notification clear bit 用1写入这个位可以清除位MEAS_STS.ALARM。 这个位被读回为0b。
|
7)INT_CFG
地址:0x08
默认值:0x11
注释:这个寄存器定义了引脚INT的配置。
Field
|
Bits
|
Description
|
0
|
7:5
|
这个位域应该用00b写。
|
INT_TYP
|
4
|
Pin INT electrical configuration 0b:引脚INT配置为推挽和非活动状态。 1b:引脚INT配置为推挽和活动状态。 注意: 写入此位域将使引脚INT处于非活动状态。
|
INT_FUNC
|
3:1
|
Pin INT function configuration 000b:引脚INT未激活。 001b:配置引脚INT为告警阈值违规通知引脚。 010b:引脚INT配置为数据就绪通知引脚。 011b:引脚INT配置为传感器繁忙通知引脚。 100b:引脚INT配置为早期测量开始通知引脚(此功能仅在连续模式下可用 MEAS_CFG.OP_MODE = 10b,否则引脚不活动)。 101 b:保留 ... 111 b:保留
|
ALARM_TYP
|
0
|
Alarm type configuration bit 该位域定义在违反较低或较高阈值的情况下是否发出警报。 0b:向下交叉——将寄存器ALARM_TH_H和ALARM_TH_L的连接值定义为低阈值寄存器。 1b:向上交叉——将寄存器ALARM_TH_H和ALARM_TH_L的连接值定义为较高阈值寄存器。
|
8)ALARM_TH_H与ALARM_TH_L
地址:0x09~0x0A
默认值:0x00
注释:寄存器ALARM_TH_H和ALARM_TH_L定义用于告警违规阈值的值(1位= 1 ppm)。
9)PRES_REF_H与PRES_REF_L
地址:0x0B/0x0C
默认值:0x03/0xF7
注释:寄存器PRES_REF_L和PRES_REF_H用于捕获要补偿的大气压力(1位= 1 hPa),用户必须先写入PRES_REF_H,然后写入PRES_REF_L,如果不更新默认值,压力补偿实际上是无效的,为了正确操作,用户应确保所编程的压力值在设备规定的压力工作范围内,有效的工作范围是750 hPa到1150 hPa。低于750 hPa的值将被视为750 hPa,1150 hPa以上的值将被处理为1150 hPa,如果写入此范围以外的值,则位SENS_STS.ICCER被置位。
10)CALIB_REF_H与CALIB_REF_L
地址:0x0D/0x0E
默认值:0x01/0x90
注释:自动基线偏移补偿参考,寄存器CALIB_REF_H和CALIB_REF_L定义了用于ABOC和力校准的参考值(1bit = 1 ppm),数值必须包含在350ppm和900ppm之间。低于350 ppm的数值将被视为350 ppm,900ppm以上的值将被处理为900ppm。如果写入超出此范围的值,则位SENS_STS.ICCER被置位。
11)SCRATCH_PAD
地址:0x0F
默认值:0x00
注释:该寄存器为运行时的数据完整性测试提供了可读可写的地址空间。该寄存器与特定的硬件功能无关。
12)SENS_RST
地址:0x10
默认值:0x00
注释:该寄存器用于触发软复位。如果接收到无效的命令,位SENS_STS.ICCER被置位。
Field
|
Bits
|
Description
|
SRTRG
|
7:0
|
Soft reset trigger 向该字段写入A3H会触发软复位事件。 将BCH写入此字段将重置ABOC上下文。 将CFH写入此字段将立即将压力校准偏移量保存在内部非易失性存储器中。 将DFH写入此字段禁用IIR滤波器。 将FCH写入此字段将重置强制校准校正因子。 将FEH写入此字段启用IIR滤波器(默认启用)。 此位被读取为00H。
|
3、测试基本配置
初始配置为连续采集,周期20s,不产生中断。
出现过读取的数据是65535的情况,读取数据是通过定时2s扫描MEAS_STS寄存器的Data ready bit ,如果为1则读取CO2浓度结果。目前还不太清楚为什么会出现读取结果为0xffff的情况。初步怀疑是连续测量以固定时间进行测量序列,开始进行测量序列时1s内应该是最好不要有任何操作,包括读写,有可能异常,循环扫描有可能与这块存在重叠导致异常。
由于口罩原因,目前还无法获取标气,头一天晚上在家测得的CO2浓度为1900ppm左右,可能是电脑房密闭的原因,且长时间在这个房间里,空气相对浑浊。无人一晚后,早上的水平在800ppm左右,不过我进来后水平基本就在1600ppm左右,这个传感器放置的位置还是有一定讲究的。
4、驱动代码
通过对上述寄存器的解读基本可以确定,读写寄存器基本围绕一个寄存器或者相邻两个寄存器组成的16位。
/************************************宏定义************************************/
#define PasCO2_SlaveAddress 0x28
#define PasCO2_RegAddr_ID 0x00
#define PasCO2_RegAddr_SENS_STS 0x01//状态寄存器
#define PasCO2_RegAddr_RATE_H 0x02//测量周期寄存器_高
#define PasCO2_RegAddr_RATE_L 0x03//测量周期寄存器_低
#define PasCO2_RegAddr_MEASCFG 0x04//测量配置寄存器
#define PasCO2_RegAddr_PPM_H 0x05//测量结果寄存器_高
#define PasCO2_RegAddr_PPM_L 0x06//测量结果寄存器_低
#define PasCO2_RegAddr_MEAS_STS 0x07//传感器状态寄存器
#define PasCO2_RegAddr_INTCFG 0x08//中断配置寄存器
#define PasCO2_RegAddr_ALARM_H 0x09//报警阈值寄存器_高
#define PasCO2_RegAddr_ALARM_L 0x0A//报警阈值寄存器_低
#define PasCO2_RegAddr_PRES_H 0x0B//压力补偿寄存器_高
#define PasCO2_RegAddr_PRES_L 0x0C//压力补偿寄存器_低
#define PasCO2_RegAddr_CALIB_H 0x0D//基线偏移寄存器_高
#define PasCO2_RegAddr_CALIB_L 0x0E//基线偏移寄存器_低
#define PasCO2_RegAddr_SCRATCH_PAD 0x0F//传感器状态寄存器
#define PasCO2_RegAddr_SENS_RST 0x10//复位寄存器
#define REG_SENS_STS_ICCER_CLR_POS (0U)
#define REG_SENS_STS_ICCER_CLR_MSK (0x01U << REG_SENS_STS_ICCER_CLR_POS)
#define REG_SENS_STS_ORVS_CLR_POS (1U)
#define REG_SENS_STS_ORVS_CLR_MSK (0x01U << REG_SENS_STS_ORVS_CLR_POS)
#define REG_SENS_STS_ORTMP_CLR_POS (2U)
#define REG_SENS_STS_ORTMP_CLR_MSK (0x01U << REG_SENS_STS_ORTMP_CLR_POS)
#define REG_SENS_STS_ICCER_POS (3U)
#define REG_SENS_STS_ICCER_MSK (0x01U << REG_SENS_STS_ICCER_POS)
#define REG_SENS_STS_ORVS_POS (4U)
#define REG_SENS_STS_ORVS_MSK (0x01U << REG_SENS_STS_ORVS_POS)
#define REG_SENS_STS_ORTMP_POS (5U)
#define REG_SENS_STS_ORTMP_MSK (0x01U << REG_SENS_STS_ORTMP_POS)
#define REG_SENS_STS_PWM_DIS_ST_POS (6U)
#define REG_SENS_STS_PWM_DIS_ST_MSK (0x01U << REG_SENS_STS_PWM_DIS_ST_POS)
#define REG_SENS_STS_SEN_RDY_POS (7U)
#define REG_SENS_STS_SEN_RDY_MSK (0x01U << REG_SENS_STS_SEN_RDY_POS)
/*******************************全局变量********************************/
typedef enum
{
ERROR_NONE = 0x00, // no error
ERROR_COM = 0x01, // IIC通信异常
ERROR_ICC = 0x02, // 无效指令
ERROR_ORVS = 0x03, // 12V电压超限
ERROR_ORTMP = 0x04, // 温度超限
ERROR_NOT_READY = 0x05, // 未正确初始化
} Error_PasCO2;
Error_PasCO2 error_PasCO2;
typedef struct
{
uint8_t Mode;//测量模式
uint16_t MeasRate;//测量周期
uint16_t AlarmTh;//报警阈值
uint16_t PresRef;//压力补偿
uint16_t CalibRef;//偏移补偿
}PasCO2_Config;
PasCO2_Config PasCO2Config;
typedef struct
{
uint8_t Error; //错误码
uint8_t ID;
uint16_t PPM;
}PasCO2States;//传感器状态
PasCO2States PasCO2,PasCO2Show;
/*******************************函数********************************/
void PasCO2_Init(void);
void PasCO2_GetPPM(void);
static Error_PasCO2 PasCO2_CheckCom(void);
static uint8_t PasCO2_GetOneWord(uint8_t reg);
static void PasCO2_SetOneWord(uint8_t reg,uint8_t data);
static uint16_t PasCO2_GetTwoWord(uint8_t reg);
static void PasCO2_SetTwoWord(uint8_t reg,uint16_t data);
//******************************************************************************
//* 函数名称 : void PasCO2_Init(void)
//* 函数描述 :
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
void PasCO2_Init(void)
{
uint8_t SysData;
if(PasCO2_CheckCom() == ERROR_NONE)
{
PasCO2.ID = PasCO2_GetOneWord(PasCO2_RegAddr_ID);
SysData = PasCO2_GetOneWord(PasCO2_RegAddr_SENS_STS);
if ((SysData & REG_SENS_STS_ICCER_MSK) != 0U)
PasCO2.Error = ERROR_ICC;
else if ((SysData & REG_SENS_STS_ORVS_MSK) != 0U)
PasCO2.Error = ERROR_ORVS;
else if ((SysData & REG_SENS_STS_ORTMP_MSK) != 0U)
PasCO2.Error = ERROR_ORTMP;
else if ((SysData & REG_SENS_STS_SEN_RDY_MSK) == 0U)
PasCO2.Error = ERROR_NOT_READY;
else
PasCO2.Error = ERROR_NONE;
}
else
{
PasCO2.Error = ERROR_COM;
}
if(PasCO2.Error == ERROR_NONE)
{
PasCO2_SetOneWord(PasCO2_RegAddr_MEASCFG,0x04);//切换到空闲模式
PasCO2_SetTwoWord(PasCO2_RegAddr_RATE_H,0x0006);//测量周期20s
PasCO2_SetTwoWord(PasCO2_RegAddr_PRES_H,0x03f6);//设置压力
PasCO2_SetOneWord(PasCO2_RegAddr_INTCFG,0x01);//关闭外部中断
PasCO2Config.MeasRate = PasCO2_GetTwoWord(PasCO2_RegAddr_RATE_H);
PasCO2Config.PresRef = PasCO2_GetTwoWord(PasCO2_RegAddr_PRES_H);
PasCO2Config.CalibRef = PasCO2_GetTwoWord(PasCO2_RegAddr_CALIB_H);
PasCO2_SetOneWord(PasCO2_RegAddr_MEASCFG,0x06);//切换到连续采集模式
}
}
//******************************************************************************
//* 函数名称 : PasCO2_GetPPM(void)
//* 函数描述 : 获取CO2浓度值
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
void PasCO2_GetPPM(void)
{
uint8_t MEAS_STS = 0;
MEAS_STS = PasCO2_GetOneWord(PasCO2_RegAddr_MEAS_STS);
if((MEAS_STS&0x10) == 0x10)
{
delay_ms(30);
PasCO2.PPM = PasCO2_GetTwoWord(PasCO2_RegAddr_PPM_H);
MEAS_STS = 0;
}
}
//******************************************************************************
//* 函数名称 : PasCO2_CheckCom(void)
//* 函数描述 :
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
static Error_PasCO2 PasCO2_CheckCom(void)
{
uint8_t CheckData = 0;
PasCO2_SetOneWord(PasCO2_RegAddr_SCRATCH_PAD,0xA5);
CheckData = PasCO2_GetOneWord(PasCO2_RegAddr_SCRATCH_PAD);
return (CheckData == 0xA5) ? ERROR_NONE : ERROR_COM;
}
//******************************************************************************
//* 函数名称 : PasCO2_GetOneWord
//* 函数描述 : 获取一个8位数
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
static uint8_t PasCO2_GetOneWord(uint8_t reg)
{
uint8_t getData = 0;
IIC2_MasterUS_RecvBytes(1,&getData,PasCO2_SlaveAddress,reg);
return getData;
}
//******************************************************************************
//* 函数名称 : PasCO2_GetOneWord
//* 函数描述 : 设置一个8位数
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
static void PasCO2_SetOneWord(uint8_t reg,uint8_t data)
{
IIC2_MasterUS_SendBytes(1,&data,PasCO2_SlaveAddress,reg);
}
//******************************************************************************
//* 函数名称 : PasCO2_GetTwoWord(uint8_t rate)
//* 函数描述 : 获取16位数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
static uint16_t PasCO2_GetTwoWord(uint8_t reg)
{
uint8_t Data[2]={0};
uint16_t data = 0;
IIC2_MasterUS_RecvBytes(2,Data,PasCO2_SlaveAddress,reg);
data = Data[0];
data = data << 8;
data |= Data[1];
return data;
}
//******************************************************************************
//* 函数名称 : PasCO2_SetTwoWord
//* 函数描述 : 设置16位数据
//* 输入参数 : rate:5~4095s
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 :
//******************************************************************************
static void PasCO2_SetTwoWord(uint8_t reg,uint16_t data)
{
uint8_t Data[2];
Data[0] = (uint8_t)(data>>8);
Data[1] = (uint8_t)data;
IIC2_MasterUS_SendBytes(2,Data,PasCO2_SlaveAddress,reg);
}
5、效果视频
CO2测试界面显示
|