'bmp'에 해당되는 글 2건

  1. 2018.11.23 Hardware | MAX30105 파티클 센서 - 1
  2. 2018.07.24 Hardware | SSD1306 에 로고를 세겨보자

Hardware | MAX30105 파티클 센서 - 1

|

1. 파티클 센서


인터넷을 돌아다니다 particle sensor 라는 것을 알게 되었습니다.

이게 단순히 공기중의 입자를 확인하는것 뿐만아니라, 혈중 농도 및 심전도까지 확인할 수 있다고 합니다.


나중에 도플러 효과를 이용한 원격 심전도 확인 시스템을 만들 예정이라,

기초적인 지식을 습득하기 위해 일단 이런 류의 센서 사용법을 익혀 보기로 합니다.






2. 주문


물론 AliExpress 에서 주문했습니다.


* CFsunbird High Accuracy I2C MAX30105 Particle Optical Sensor Photodetectors Board Module 1.8V power supply

https://ko.aliexpress.com/item/CFsunbird-High-Accuracy-I2C-MAX30105-Particle-Optical-Sensor-Photodetectors-Board-Module-1-8V-power-supply/32819571918.html




여타 센서류보다 단일 부품으로는 꽤나 비싼편 입니다.

이는 다양한 기능이 들어가 있으며, 기본 소자 자체가 좀 있어 보입니다.


SparkFun 에서 팔고 있는 제품인데, AliExpress 에서 구입하다 보니, 조금 변형된 중국 제품입니다.

단, 소스는 완벽하게 호환됩니다.


* SparkFun Particle Sensor Breakout - MAX30105

https://learn.sparkfun.com/tutorials/max30105-particle-and-pulse-ox-sensor-hookup-guide


보통 정식 제품보다는 AliExpress 가 싼 편인데, 이 제품은 자비가 없군요.

AliExpress 에서 약 12 USD, SparkFun 제품은 13 USD 정도 합니다.





3. 도착


크게 무리없이 2주만에 도착.



납땜이 되지 않은 상태로 배달이 됩니다. 이제 AliExpress 에서 오는 것은 이게 당연한 거죠?



핵심이 되는 센서 부품을 클로즈 업 해봤습니다.



범상치 않아 보이는군요.





4. 연결


Arduino 와의 연결은 다음과 같습니다.


 MAX30105 | Arduino Nano
-------------------------
    VCC   |     3.3V
    GND   |     GND
    SDL   |     A5
    SDA   |     A4
-------------------------


실제 회로 구성은 다음과 같습니다.

Fritzing 에서 그려 보는데, 아쉽게도 아직 Fritzing 에서는 MAX30105 부품이 리스트에 존재하지 않습니다.

아직 아무도 만들지 않았나 봅니다.



Datasheet 입니다 - MAX30105_3.pdf





5. sketch - Red, IR, Green reading


이후 나오는 소스는 모두 아래 site 를 참고하였습니다.


* SparkFun Particle Sensor Breakout - MAX30105

https://learn.sparkfun.com/tutorials/max30105-particle-and-pulse-ox-sensor-hookup-guide


Library 를 인스톨 하고 가장 간단한 스케치를 로드하여 확인해 봅니다.

소스는 소자의 기본 동작인 빨간색, 적외선, 녹색을 감지하고 수치화 하는 스케치 입니다.


File > Examples > MAX3010x Pulse and Proximity Sensor > Example1_Basic_Readings



실제 소스를 여기에 옮겨 봅니다.


/*
  MAX30105 Breakout: Output all the raw Red/IR/Green readings
  By: Nathan Seidle @ SparkFun Electronics
  Date: October 2nd, 2016
  https://github.com/sparkfun/MAX30105_Breakout

  Outputs all Red/IR/Green values.

  Hardware Connections (Breakoutboard to Arduino):
  -5V = 5V (3.3V is allowed)
  -GND = GND
  -SDA = A4 (or SDA)
  -SCL = A5 (or SCL)
  -INT = Not connected

  The MAX30105 Breakout can handle 5V or 3.3V I2C logic. We recommend powering the board with 5V
  but it will also run at 3.3V.

  This code is released under the [MIT License](http://opensource.org/licenses/MIT).
*/

#include "Wire.h"
#include "MAX30105.h"

MAX30105 particleSensor;

#define debug Serial //Uncomment this line if you're using an Uno or ESP
//#define debug SerialUSB //Uncomment this line if you're using a SAMD21

void setup() {
  debug.begin(9600);
  debug.println("MAX30105 Basic Readings Example");

  // Initialize sensor
  if (particleSensor.begin() == false)
  {
    debug.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }

  particleSensor.setup(); //Configure sensor. Use 6.4mA for LED drive
}

void loop() {
  debug.print(" R[");
  debug.print(particleSensor.getRed());
  debug.print("] IR[");
  debug.print(particleSensor.getIR());
  debug.print("] G[");
  debug.print(particleSensor.getGreen());
  debug.print("]");

  debug.println();
}


우선 구동을 시작하면, 녹색과 빨간색 빛이 빠르게 점멸합니다.



저렇게 빛을 쏜 다음 반사되는 값을 읽는것이겠죠?



손가락을 센서 근처로 가져가면 값의 변동이 일어납니다.


센서의 불빛을 슬로우 모션으로 9초동안 찍어 봤습니다.

그랬더니 51초짜리 동영상이 되었네요.



얼마나 빨리 점멸을 하는지, 슬로모션으로 찍어도 실제로 보는것과 그리 차이나지 않습니다.





6. sketch - 물체 인식


IR 의 delta 값을 이용하여 물체가 일정 이상 안에 들어와 있는지 없는지를 판단합니다.

소스는 아래 path 에서 확인할 수 있습니다.


File > Examples > MAX3010x Pulse and Proximity Sensor > Example2_Presense_Sensing






7. sketch - 온도


SparkFun 사에서 제공되는 library 에서 "readTemperature()" 함수를 그대로 이용한 것 입니다.

그럼 위의 함수는 어떻게 되느냐 하면 아래와 같습니다.


// Die Temperature
// Returns temp in C
float MAX30105::readTemperature() {
  // Step 1: Config die temperature register to take 1 temperature sample
  writeRegister8(_i2caddr, MAX30105_DIETEMPCONFIG, 0x01);

  // Poll for bit to clear, reading is then complete
  // Timeout after 100ms
  unsigned long startTime = millis();
  while (millis() - startTime < 100)
  {
    uint8_t response = readRegister8(_i2caddr, MAX30105_DIETEMPCONFIG);
    if ((response & 0x01) == 0) break; //We're done!
    delay(1); //Let's not over burden the I2C bus
  }
  //TODO How do we want to fail? With what type of error?
  //? if(millis() - startTime >= 100) return(-999.0);

  // Step 2: Read die temperature register (integer)
  int8_t tempInt = readRegister8(_i2caddr, MAX30105_DIETEMPINT);
  uint8_t tempFrac = readRegister8(_i2caddr, MAX30105_DIETEMPFRAC);

  // Step 3: Calculate temperature (datasheet pg. 23)
  return (float)tempInt + ((float)tempFrac * 0.0625);


센서 내부에 register 값을 읽어와서 표현하는 것이군요.

구동 소스는 아래 path 에서 확인할 수 있습니다.


File > Examples > MAX3010x Pulse and Proximity Sensor > Example3_Temperature_Sense







8. sketch - 심전도


손가락을 센서에 대고 있으면 심전도를 그려주는 소스 입니다.


File > Examples > MAX3010x Pulse and Proximity Sensor > Example4_HeartBeat_Plotter


읽어들인 IR 값에 대한 변화를 plottor 을 이용해 그려주는 것이죠.
소스를 보면 setup 과 기준값 등을 정해주는 부분이 있을 뿐, 단순히 IR 값을 불러옵니다.

아래처럼 보려면, Tools > Serial Plotter 를 통해서 확인할 수 있습니다.


저의 심전도 모양입니다. 두근두근...





9. sketch - 심박수


대체로 심전도와 비슷한데, 이걸 1분에 몇분 정도 뛰는지를 확인해 주는 소스 입니다.

보통 병원이나 건강검진시 확인해 보는 심박수 겠죠?


구동 소스는 아래 path 에서 확인할 수 있습니다.


File > Examples > MAX3010x Pulse and Proximity Sensor > Example5_HeartRate







FIN


MAX30105 센서는 주로, 심박수 모니터링에 사용되는게 가장 적절해 보입니다.

인터넷에서 어느 분이, 이와 비슷한 센서를 이용하여 심박수를 OLED 에 표시해주는 것까지 해놓은 글이 아래 입니다.


* Heart beat Sensor and “ECG” Display

http://www.xtronical.com/basics/heart-beat-sensor-ecg-display/


저도 따라해 봤는데,

일단 센서에서 나오는 값 자체가 MAX30105 처럼 큰 값으로 나오지 않을 뿐더러,

값의 변화가 딱 OLED 크기만큼 잘 구현이 되어 있어서 잘 하신것 같은데, 도저히 따라해도 안되는군요.



겨우겨우 우겨 넣어서 OLED 에 보여주는 것 까지는 해 봤습니다.

이것 가지고는 만족스럽지 못하여, 못하는 코딩을 이용하여 한번 도전해 보겠습니다.


병원에서 보는 듯 한 모습으로 될 때까지 만들어서 공유해 볼께요.



And

Hardware | SSD1306 에 로고를 세겨보자

|

1. 이제 때가 되었군


그렇습니다.

OLED 를 사용하다 보면, 커스텀 로고 새기는 방법을 익혀야 하는 경우가 몇번 있었습니다만,

대세에 지장이 없어서 무시하고 왔습니다.


그러나 UV Meter 를 가지로 놀려고 아래 링크를 따라해 보니,

커스텀 로고를 새기는 방법을 익혀야 할 때가 된걸 느꼈습니다.


* Arduino UV Meter using the UV31A Ultraviolet Sensor

http://www.electronics-lab.com/project/arduino-uv-meter-using-uv30a-ultraviolet-sensor/


아래 그림처럼, 처음 시작을 커스텀 로고로 시작되는 것을 볼 수 있습니다.



또한, 예전에 VU Meter 를 만들 때, 제작자가 한번 언급한 경우도 있었습니다.

이때는 그냥 제작자 코드를 따라하기만 하면 되는거였죠.


* Hardware | SSD1306 monochrome OLED 를 가지고 VU meter 를 만들어보자

 - http://chocoball.tistory.com/entry/Hardware-VU-meter-using-SSD1306-monochrome-OLED


자 그럼, 한번 시작해 볼까요?





2. Arduino micro 의 I2C 연결


여기서 잠깐.

평소 사용하는 Arduino Nano 와는 다르게, 요즘 자주 사용하고 있는 Arduino Micro 의 I2C pinout 이 달라 조금 헤매었습니다.



OLED 의 SCL / SDA 연결을 위해서는 D3 / D2 pin 을 이용해야 합니다.


 SSD1306  | Arduino Micro
--------------------------
   VCC    |     3.3V
   GND    |     GND
   SDL    |     D3
   SDA    |     D2
--------------------------


연결은 다음과 같아요.






3. OLED 의 너비와 높이를 구해보자


우선 사용할 OLED 의 가로, 세로 pixel 수를 구해야 합니다.

이는 최종적으로 만들 그림의 크기를 정하기 위한거죠.


연결한 OLED 에 가로, 세로 pixel 수를 알아보기 위해 아래 code 를 사용합니다.


#include "SPI.h"
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
 
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup() {
	display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
	display.clearDisplay();
	display.display();
}

void loop() {
	display.clearDisplay();
	
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.setTextSize(2);
	display.println(display.width());
	display.print(display.height());
	
	display.display();
}


결과는 다음과 같습니다.



SSD1306 이지만 128x64 가 아닌, 128x32 군요.

높이가 일반적인 OLED 보다 반쪽이라서 그림을 신경써야 합니다.





4. 필요한 그림파일 찾기


UV Meter 를 위해서는, 우선 태양 그림이 필요합니다.

Googling 하여 태양 그림을 찾아 봅니다.

키워드는 "sun shining icon image" 로 검색했습니다.


주르륵 뜨는군요. 적당한 것을 하나 골라 봅니다.







5. 흑백 및 적당한 크기로


그림을 생성하기 위해 Paint.net 이라는 어플을 사용합니다.


* paint.net

https://www.getpaint.net/


우선 OLED 의 크기가 128x32 이므로, 그림 크기를 OLED 크기에 맞게 생성해 줍니다.



태양 그림 파일을 불러와서 크기를 줄여줍니다.

OLED 가 32 이므로, 32로 하면 그림이 다 들어가겠지만, 그렇게 되면 너무 작아 보여,

64x64 로 줄여줍니다.



또한 OLED 에 표시하기 위해서는 on/off, 0/1, white/black 으로 표시해야 합니다.

최대한 근접하게 우선 Brightness / Contrast 를 설정해 줍니다.



전체적으로 다음과 같이 꾸며 봅니다.


Contrast 를 최대로 높히면 Bitmap 생성시 완전한 흑백으로 근접하게 만들 수 있습니다.



마지막으로 Windows 에 기본으로 들어 있는,

mspaint ( %windir%\system32\mspaint.exe ) 를 사용하여,

최종적으로 Monochrome BMP 파일로 생성해 줍니다.


Save as Monochrome Bitmap 으로 하면서 완전히 white/black 으로 변경됩니다.






6. LCD Assistant


이제 C 코드용 bitmap 을 만들어주는 어플을 다운로드 받아서 실행합니다.


* LCD Assistant

http://en.radzio.dxp.pl/bitmap_converter/



실행한 후, 위에서 만든 파일을 load 합니다.



이제 "Save output" 으로 최종적으로 text 파일로 export 합니다.



Output 된 text 파일을 열어보면 아래와 같이 생성되어 있습니다.



Monochrome Bitmap 으로만 잘 만들면,

LCD Assistant 를 이용하여 C code map 을 만드는데 쉽게 진행됩니다.





7. OLED 에 커스텀 코드를 올려보자


C code map 을 array 로 올린 다음,

display.drawBitmap 을 이용하여 표현할 수 있는 준비가 되었습니다.


최종 코드는 다음과 같습니다.


#include "SPI.h"
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
 
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

static const unsigned char PROGMEM UVMeter[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x18, 0x03, 0x18, 0x01, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x18, 0x03, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x07, 0xC0, 0x07, 0x00, 0x00, 0x1C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x0F, 0xC0, 0x0E, 0x00, 0x00, 0x1C, 0x03, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x3E, 0x00, 0x00, 0x1C, 0x03, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0x0F, 0xF0, 0x7E, 0x00, 0x00, 0x1C, 0x03, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x0F, 0xF8, 0xFE, 0x00, 0x00, 0x1C, 0x03, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xDF, 0xFD, 0xFE, 0x00, 0x00, 0x1C, 0x03, 0x07, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1C, 0x03, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1C, 0x03, 0x03, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1C, 0x03, 0x03, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xE0, 0x03, 0xFF, 0x00, 0x00, 0x1C, 0x07, 0x01, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0x03, 0xE0, 0x7F, 0x00, 0x00, 0x0C, 0x06, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x3F, 0xFE, 0x1F, 0x3F, 0xF0, 0x0E, 0x0E, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x06, 0x0F, 0xF8, 0xFF, 0xFF, 0x8F, 0xFF, 0xC0, 0x07, 0xFC, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x07, 0xFF, 0xF1, 0xFF, 0xFF, 0xC7, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xE7, 0xFF, 0xFF, 0xF3, 0xFF, 0x00, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xCF, 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x70, 0x38, 0x00, 0x20, 0x00, 0x00,
0x01, 0xFF, 0x9F, 0xFF, 0x7F, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x70, 0x38, 0x00, 0x20, 0x00, 0x00,
0x00, 0xFF, 0x9F, 0xF0, 0x07, 0xFC, 0xFE, 0x00, 0x00, 0x00, 0x58, 0x28, 0x38, 0x78, 0x38, 0x48,
0x00, 0x7F, 0x3F, 0xC0, 0x01, 0xFE, 0x7E, 0x00, 0x00, 0x00, 0x58, 0x68, 0x6E, 0x78, 0xCC, 0x7C,
0x00, 0x3E, 0x7F, 0x80, 0x00, 0xFF, 0x3E, 0x00, 0x00, 0x00, 0x48, 0x48, 0xC6, 0x20, 0x84, 0x60,
0x00, 0x1E, 0x7F, 0x00, 0x00, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0x4C, 0xC8, 0xC2, 0x21, 0x86, 0x40,
0x00, 0x1E, 0x7E, 0x00, 0x00, 0x3F, 0x3C, 0x00, 0x00, 0x00, 0x4C, 0x88, 0xFE, 0x21, 0xFE, 0x40,
0x00, 0x3C, 0xFE, 0x00, 0x00, 0x3F, 0x9F, 0x00, 0x00, 0x00, 0x46, 0x88, 0x80, 0x21, 0x80, 0x40,
0x00, 0x7C, 0xFC, 0x00, 0x00, 0x1F, 0x9F, 0xF0, 0x00, 0x00, 0x47, 0x88, 0xC0, 0x21, 0x80, 0x40,
0x00, 0xFC, 0xFC, 0x00, 0x00, 0x1F, 0x9F, 0xFC, 0x00, 0x00, 0x43, 0x08, 0x42, 0x30, 0xC0, 0x40,
0x03, 0xFC, 0xFC, 0x00, 0x00, 0x1F, 0x9F, 0xFE, 0x00, 0x00, 0x43, 0x08, 0x7E, 0x1C, 0x7C, 0x40,
0x07, 0xFC, 0xFC, 0x00, 0x00, 0x1F, 0x9F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};


void setup() {
	display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
	display.clearDisplay();
	display.display();
}

void loop() {
	display.clearDisplay();
	
	display.drawBitmap(0, 0, UVMeter, 128, 32, WHITE);

	display.display();
}


짜잔~!!!

잘 나오는군요.






FIN


사실 이렇게까지 만드는데 거진 8시간정도 걸렸습니다.

Arduino micro 의 I2C pinout 이나, 순수한 Monochrome Bitmap 을 만드는 방법을 찾는데 많이 걸렸네요.

본 포스트가 다른 분들에게 많이 도움이 되었으면 합니다.


And
prev | 1 | next