赞
踩
byte ledBrightness = 60; //Options: 0=Off to 255=50mA
byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; //Options: 69, 118, 215, 411
int adcRange = 4096; //Options: 2048, 4096, 8192, 16384
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
这里开始设置MAX3010X的各种参数,对其进行初始化。直接看函数原型吧
在H文件中的定义如下
void setup(byte powerLevel = 0x1F, byte sampleAverage = 4, byte ledMode = 3, int sampleRate = 400, int pulseWidth = 411, int adcRange = 4096);
也都是可选参数
CPP文件中的实现如下
void MAX30105::setup(byte powerLevel, byte sampleAverage, byte ledMode, int sampleRate, int pulseWidth, int adcRange) { softReset(); //Reset all configuration, threshold, and data registers to POR values //FIFO Configuration //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //The chip will average multiple samples of same type together if you wish if (sampleAverage == 1) setFIFOAverage(MAX30105_SAMPLEAVG_1); //No averaging per FIFO record else if (sampleAverage == 2) setFIFOAverage(MAX30105_SAMPLEAVG_2); else if (sampleAverage == 4) setFIFOAverage(MAX30105_SAMPLEAVG_4); else if (sampleAverage == 8) setFIFOAverage(MAX30105_SAMPLEAVG_8); else if (sampleAverage == 16) setFIFOAverage(MAX30105_SAMPLEAVG_16); else if (sampleAverage == 32) setFIFOAverage(MAX30105_SAMPLEAVG_32); else setFIFOAverage(MAX30105_SAMPLEAVG_4); //setFIFOAlmostFull(2); //Set to 30 samples to trigger an 'Almost Full' interrupt enableFIFORollover(); //Allow FIFO to wrap/roll over //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Mode Configuration //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- if (ledMode == 3) setLEDMode(MAX30105_MODE_MULTILED); //Watch all three LED channels else if (ledMode == 2) setLEDMode(MAX30105_MODE_REDIRONLY); //Red and IR else setLEDMode(MAX30105_MODE_REDONLY); //Red only activeLEDs = ledMode; //Used to control how many bytes to read from FIFO buffer //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Particle Sensing Configuration //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- if(adcRange < 4096) setADCRange(MAX30105_ADCRANGE_2048); //7.81pA per LSB else if(adcRange < 8192) setADCRange(MAX30105_ADCRANGE_4096); //15.63pA per LSB else if(adcRange < 16384) setADCRange(MAX30105_ADCRANGE_8192); //31.25pA per LSB else if(adcRange == 16384) setADCRange(MAX30105_ADCRANGE_16384); //62.5pA per LSB else setADCRange(MAX30105_ADCRANGE_2048); if (sampleRate < 100) setSampleRate(MAX30105_SAMPLERATE_50); //Take 50 samples per second else if (sampleRate < 200) setSampleRate(MAX30105_SAMPLERATE_100); else if (sampleRate < 400) setSampleRate(MAX30105_SAMPLERATE_200); else if (sampleRate < 800) setSampleRate(MAX30105_SAMPLERATE_400); else if (sampleRate < 1000) setSampleRate(MAX30105_SAMPLERATE_800); else if (sampleRate < 1600) setSampleRate(MAX30105_SAMPLERATE_1000); else if (sampleRate < 3200) setSampleRate(MAX30105_SAMPLERATE_1600); else if (sampleRate == 3200) setSampleRate(MAX30105_SAMPLERATE_3200); else setSampleRate(MAX30105_SAMPLERATE_50); //The longer the pulse width the longer range of detection you'll have //At 69us and 0.4mA it's about 2 inches //At 411us and 0.4mA it's about 6 inches if (pulseWidth < 118) setPulseWidth(MAX30105_PULSEWIDTH_69); //Page 26, Gets us 15 bit resolution else if (pulseWidth < 215) setPulseWidth(MAX30105_PULSEWIDTH_118); //16 bit resolution else if (pulseWidth < 411) setPulseWidth(MAX30105_PULSEWIDTH_215); //17 bit resolution else if (pulseWidth == 411) setPulseWidth(MAX30105_PULSEWIDTH_411); //18 bit resolution else setPulseWidth(MAX30105_PULSEWIDTH_69); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //LED Pulse Amplitude Configuration //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Default is 0x1F which gets us 6.4mA //powerLevel = 0x02, 0.4mA - Presence detection of ~4 inch //powerLevel = 0x1F, 6.4mA - Presence detection of ~8 inch //powerLevel = 0x7F, 25.4mA - Presence detection of ~8 inch //powerLevel = 0xFF, 50.0mA - Presence detection of ~12 inch setPulseAmplitudeRed(powerLevel); setPulseAmplitudeIR(powerLevel); setPulseAmplitudeGreen(powerLevel); setPulseAmplitudeProximity(powerLevel); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Multi-LED Mode Configuration, Enable the reading of the three LEDs //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- enableSlot(1, SLOT_RED_LED); if (ledMode > 1) enableSlot(2, SLOT_IR_LED); if (ledMode > 2) enableSlot(3, SLOT_GREEN_LED); //enableSlot(1, SLOT_RED_PILOT); //enableSlot(2, SLOT_IR_PILOT); //enableSlot(3, SLOT_GREEN_PILOT); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- clearFIFO(); //Reset the FIFO before we begin checking the sensor }
看起来挺长的,但是都是类似与枚举的if-else,不是很复杂。
softReset(); //Reset all configuration, threshold, and data registers to POR values
函数代码如下
void MAX30105::softReset(void) {
bitMask(MAX30105_MODECONFIG, MAX30105_RESET_MASK, MAX30105_RESET);
// Poll for bit to clear, reset is then complete
// Timeout after 100ms
unsigned long startTime = millis();
while (millis() - startTime < 100)
{
uint8_t response = readRegister8(_i2caddr, MAX30105_MODECONFIG);
if ((response & MAX30105_RESET) == 0) break; //We're done!
delay(1); //Let's not over burden the I2C bus
}
}
这个bitMask
函数还是挺有意思的,之前做这类操作的时候没有想过用这种方法。
后面的部分就是读取了esp32启动以来的毫秒数,然后做循环,判断这个位是不是设置成功了。
就是等待100毫秒,看复位成功了没有。
话说这个操作方式确实比较精准,误差不会太大。
这个函数是一个位操作的函数,控制一位或者几位的bit的赋值。
代码如下:
void MAX30105::bitMask(uint8_t reg, uint8_t mask, uint8_t thing)
{
// Grab current register context
uint8_t originalContents = readRegister8(_i2caddr, reg);
// Zero-out the portions of the register we're interested in
originalContents = originalContents & mask;
// Change contents
writeRegister8(_i2caddr, reg, originalContents | thing);
}
操作流程如下:
这个操作一开始看,感觉有点傻,为啥不直接传输thing,然后在里面进行取反操作,何必多次一举,看了其他调用这个函数的代码,我大概搞清楚了。
这个操作不是单纯的对一位bit进行操作,而是对多位进行操作,打个比方
现在有第0位到第2位的bit是代表一个模式设置,这个模式有101,110,111三种。那么就可以传输一个二进制是1111 1000
的mask,那与读取出来的值进行与操作之后,就把第0位到第2位的数据清零了,这时thing再传递三种模式的其中一种。这样就可以做到任意位数的赋值,这种方式还挺巧妙的。
但是也能感觉到作者在写mark的数据定义的时候挺烦的,一会2进制赋值,一会16进制赋值。
FIFO就可以想象成一个队列,先进先出,用于缓存数据的。
代码如下
if (sampleAverage == 1) setFIFOAverage(MAX30105_SAMPLEAVG_1); //No averaging per FIFO record
else if (sampleAverage == 2) setFIFOAverage(MAX30105_SAMPLEAVG_2);
else if (sampleAverage == 4) setFIFOAverage(MAX30105_SAMPLEAVG_4);
else if (sampleAverage == 8) setFIFOAverage(MAX30105_SAMPLEAVG_8);
else if (sampleAverage == 16) setFIFOAverage(MAX30105_SAMPLEAVG_16);
else if (sampleAverage == 32) setFIFOAverage(MAX30105_SAMPLEAVG_32);
else setFIFOAverage(MAX30105_SAMPLEAVG_4);
setFIFOAverage
函数中只有bitMask(MAX30105_FIFOCONFIG, MAX30105_SAMPLEAVG_MASK, numberOfSamples);
这一段代码
定义的代码如下
static const uint8_t MAX30105_FIFOCONFIG = 0x08;
static const uint8_t MAX30105_SAMPLEAVG_MASK = (byte)~0b11100000;
static const uint8_t MAX30105_SAMPLEAVG_1 = 0x00;
static const uint8_t MAX30105_SAMPLEAVG_2 = 0x20;
static const uint8_t MAX30105_SAMPLEAVG_4 = 0x40;
static const uint8_t MAX30105_SAMPLEAVG_8 = 0x60;
static const uint8_t MAX30105_SAMPLEAVG_16 = 0x80;
static const uint8_t MAX30105_SAMPLEAVG_32 = 0xA0;
具体表达了什么意思可以看前言里我写的文章里的FIFO配置
章节,我在这里也做了部分引用
地址 功能 B7 B6 B5 B4 B3 B2 B1 B0 R/W 0x08 FIFO配置 SMP_AVE[2] SMP_AVE[1] SMP_AVE[0] FIFO_ROL LOVER_EN FIFO_A_FULL[3] FIFO_A_FULL[2] FIFO_A_FULL[1] FIFO_A_FULL[0] RW SMP_AVE:平均值,为了减少数据吞吐量,通过设置这个寄存器,相邻的样本(在每个单独的通道中)可以在芯片上进行平均和抽取。
SMP_AVE 平均量 000 1(不平均) 001 2 010 4 011 8 100 16 101 32 110 32 111 32 FIFO_ROL LOVER_EN:FIFO被填满之后的控制。如果是0,在你读取之前都不会更新,如果是1,会更新覆盖之前的数据
这其实也是FIFO的设置,当设置为1时如果FIFO中的数据满了,那么就会覆盖老的数据,设置为0则不会覆盖。
enableFIFORollover(); //Allow FIFO to wrap/roll over
内部也就是调用了bitMask,代码如下
void MAX30105::enableFIFORollover(void) {
bitMask(MAX30105_FIFOCONFIG, MAX30105_ROLLOVER_MASK, MAX30105_ROLLOVER_ENABLE);
}
同上,可以看前言里的MAX30102分析。
可以看出来,设置的过程是按照功能划分的,更新使能和FIFO配置都是一个寄存器里的内容,却分成了两个部分来写。可读性比较好,但是执行效率就不怎么高了。
设置红光和红外光,三种模式,同上,可以看前言里的MAX30102分析。
if (ledMode == 3) setLEDMode(MAX30105_MODE_MULTILED); //Watch all three LED channels
else if (ledMode == 2) setLEDMode(MAX30105_MODE_REDIRONLY); //Red and IR
else setLEDMode(MAX30105_MODE_REDONLY); //Red only
activeLEDs = ledMode; //Used to control how many bytes to read from FIFO buffer
设置ADC的采样范围,具体参数,可以看前言里的MAX30102分析。
if(adcRange < 4096) setADCRange(MAX30105_ADCRANGE_2048); //7.81pA per LSB
else if(adcRange < 8192) setADCRange(MAX30105_ADCRANGE_4096); //15.63pA per LSB
else if(adcRange < 16384) setADCRange(MAX30105_ADCRANGE_8192); //31.25pA per LSB
else if(adcRange == 16384) setADCRange(MAX30105_ADCRANGE_16384); //62.5pA per LSB
else setADCRange(MAX30105_ADCRANGE_2048);
采样率和脉冲宽度是相关的,因为采样率设置了脉冲宽度时间的上限。如果用户选择的采样率对于所选LED_PW设置来说太高,则将尽可能高的采样率编程到寄存器中。具体参数,可以看前言里的MAX30102分析。
if (sampleRate < 100) setSampleRate(MAX30105_SAMPLERATE_50); //Take 50 samples per second
else if (sampleRate < 200) setSampleRate(MAX30105_SAMPLERATE_100);
else if (sampleRate < 400) setSampleRate(MAX30105_SAMPLERATE_200);
else if (sampleRate < 800) setSampleRate(MAX30105_SAMPLERATE_400);
else if (sampleRate < 1000) setSampleRate(MAX30105_SAMPLERATE_800);
else if (sampleRate < 1600) setSampleRate(MAX30105_SAMPLERATE_1000);
else if (sampleRate < 3200) setSampleRate(MAX30105_SAMPLERATE_1600);
else if (sampleRate == 3200) setSampleRate(MAX30105_SAMPLERATE_3200);
else setSampleRate(MAX30105_SAMPLERATE_50);
这些位设置LED脉冲宽度(IR和Red具有相同的脉冲宽度),因此间接设置每个样本中ADC的积分时间。ADC分辨率与积分时间直接相关。具体参数,可以看前言里的MAX30102分析。
if (pulseWidth < 118) setPulseWidth(MAX30105_PULSEWIDTH_69); //Page 26, Gets us 15 bit resolution
else if (pulseWidth < 215) setPulseWidth(MAX30105_PULSEWIDTH_118); //16 bit resolution
else if (pulseWidth < 411) setPulseWidth(MAX30105_PULSEWIDTH_215); //17 bit resolution
else if (pulseWidth == 411) setPulseWidth(MAX30105_PULSEWIDTH_411); //18 bit resolution
else setPulseWidth(MAX30105_PULSEWIDTH_69);
设置脉冲宽度,具体参数,可以看前言里的MAX30102分析。
setPulseAmplitudeRed(powerLevel);
setPulseAmplitudeIR(powerLevel);
这两个设置在MAX30102中是无效的,因为数据手册中这个地址的寄存器并没有分配功能,但是因为MAX30105是向下兼容的,所以MAX30102使用也不会出问题。
setPulseAmplitudeGreen(powerLevel);
setPulseAmplitudeProximity(powerLevel);
enableSlot(1, SLOT_RED_LED);
if (ledMode > 1) enableSlot(2, SLOT_IR_LED);
if (ledMode > 2) enableSlot(3, SLOT_GREEN_LED);
void MAX30105::enableSlot(uint8_t slotNumber, uint8_t device) { uint8_t originalContents; switch (slotNumber) { case (1): bitMask(MAX30105_MULTILEDCONFIG1, MAX30105_SLOT1_MASK, device); break; case (2): bitMask(MAX30105_MULTILEDCONFIG1, MAX30105_SLOT2_MASK, device << 4); break; case (3): bitMask(MAX30105_MULTILEDCONFIG2, MAX30105_SLOT3_MASK, device); break; case (4): bitMask(MAX30105_MULTILEDCONFIG2, MAX30105_SLOT4_MASK, device << 4); break; default: //Shouldn't be here! break; } }
如果是MAX30102最大只可以设置到2。
具体参数,可以看前言里的MAX30102分析。
clearFIFO(); //Reset the FIFO before we begin checking the sensor
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。