如果你有使用 Arduino MAX30100 程式庫撰寫 Arduino 程式, 可能會遇到一個小問題, 若是沒有快速的讀取資料, 就可能會導致後續不再能夠讀取新的資料。以下以程式庫內的 MAX30100_RawData為例, 原本的 loop() 如下:
void loop()
{
uint16_t ir, red;
sensor.update();
while (sensor.getRawValues(&ir, &red)) {
Serial.print(ir);
Serial.print('\t');
Serial.println(red);
}
}
因為是不間斷的讀取資料, 所以可以正常運作, 不斷顯示讀到的原始資料:
Initializing MAX30100..SUCCESS
2105 1025
2114 1031
2128 1040
2142 1062
2171 1067
...
但是如果因為進行其他事務導致耽擱了時間, 我們以加入 delay(500) 為例:
void loop()
{
uint16_t ir, red;
sensor.update();
while (sensor.getRawValues(&ir, &red)) {
Serial.print(ir);
Serial.print('\t');
Serial.println(red);
}
Serial.println("=======");
delay(500);
}
你看到的輸出結果就可能會是這樣:
Initializing MAX30100..SUCCESS
35 36
=======
=======
=======
=======
=======
=======
...
你會看到 loop 裡面的 while 後來都沒有發生作用, 只看到印出分隔每次 loop() 的 "======="。這表示已經沒有讀取到新的資料了, 最主要的原因是程式庫從 MAX30100 模組讀取資料的 MAX30100::readFifoData() 是這樣寫的:
void MAX30100::readFifoData()
{
uint8_t buffer[MAX30100_FIFO_DEPTH * 4];
uint8_t toRead;
toRead = (readRegister(MAX30100_REG_FIFO_WRITE_POINTER) - readRegister(MAX30100_REG_FIFO_READ_POINTER)) & (MAX30100_FIFO_DEPTH - 1);
if (toRead)
{
burstRead(MAX30100_REG_FIFO_DATA, buffer, 4 * toRead);
for (uint8_t i = 0; i < toRead; ++i)
{
// Warning: the values are always left-aligned
readoutsBuffer.push({.ir = (uint16_t)((buffer[i * 4] << 8) | buffer[i * 4 + 1]),
.red = (uint16_t)((buffer[i * 4 + 2] << 8) | buffer[i * 4 + 3])});
}
}
}
其中 toRead 是用來計算模組上還有多少筆資料待讀取。MAX30100 使用一個總共 16 筆資料的環狀佇列, 並透過 FIFO_WR_PTR 暫存器紀錄下一筆資料要寫入的位置編號, 編號為 0~15;FIFO_RD_PTR 暫存器則是第一筆待讀取資料的位置編號。當兩個暫存器指向同一個位置時, 就表示佇列滿了, 這時若有新的資料就會被丟棄, 並且在 OVF_COUNTER (Overflow counter) 暫存器記錄被丟棄的資料筆數, 最多為 15。在上面的函式中, 透過這一列程式計算待讀取資料的筆數:
toRead = (readRegister(MAX30100_REG_FIFO_WRITE_POINTER) - readRegister(MAX30100_REG_FIFO_READ_POINTER)) & (MAX30100_FIFO_DEPTH - 1);
也就是寫入位置與待讀取位置的差距, 但是並沒有考慮到佇列已滿, 也就是差距為 0 的狀況。如果讀取資料的速度不夠快, 佇列滿了, 這列程式就會得到待讀取資料為 0 筆的結論, 使得後面真正讀取資料的 if 內的程式根本不會執行。為了解決這個問題, 我們將程式小改一下, 只要 OVF_COUNTER 不為 0, 就表示佇列已滿, 將 toRead 設為 16 即可:
if(readRegister(MAX30100_REG_FIFO_OVERFLOW_COUNTER) == 0)
toRead = (readRegister(MAX30100_REG_FIFO_WRITE_POINTER) - readRegister(MAX30100_REG_FIFO_READ_POINTER)) & (MAX30100_FIFO_DEPTH-1);
else
toRead = 16;
修改過後, 同樣的程式就可以得到正確的結果了:
Initializing MAX30100..SUCCESS
=======
8649 2722
8646 2725
8639 2731
8615 2718
8601 2716
8582 2702
8570 2703
8570 2698
8579 2701
8591 2709
8594 2707
8602 2712
8585 2716
8568 2714
8526 2711
8491 2700
=======
8437 2672
8422 2664
8426 2667
8431 2667
.....
Top comments (0)