'piezo buzzer'에 해당되는 글 2건

  1. 2019.04.14 Hardware | touch sensor 를 이용하여 놀아보기
  2. 2018.12.02 Hardware | MAX30105 파티클 센서 - 2

Hardware | touch sensor 를 이용하여 놀아보기

|

오늘은 머리도 식힐 겸, touch sensor 를 가지고 놀아 봤습니다.




1. 구입


터치 센서로는 몇가지가 있지만, RobotDyn 사에서 만든 센서를 선택했습니다.

RobotDyn 사의 기판색이 블렉이고 마무리가 깔끔해서 좋습니다.


* Digital capacitive touch switch sensor. Double side touch area. Module.

https://www.aliexpress.com/item/Digital-capacitive-touch-sensor/32570170116.html






2. 도착


워낙 저렴하고 간단한 부품이라 잊어버리고 있으니 도착해 있더랬습니다.



이 부품은 특이하게 "Capacitive" 라는 단어가 들어가네요.

유도체적인 성질을 가지는 것인가? 라는 생각을 잠시 해봅니다.



외형은 요렇습니다.

Touch Sensor 라고 표시된 밑부분에서 감지를 하도록 되어 있습니다.

Digital Out 이라고 표기해 놔서 arduino 의 digital pin 에 연결하면 된다는 것을 알 수 있네요.



신기하게도 뒷면의 동일한 부분도 터치인식을 합니다.






3. layout


Pin 연결은 digital pin 과 연결하면 됩니다.

전압은 3.3V 줬습니다.


 Touch Sensor | Arduino Nano
-----------------------------
      Out     |     D4
      GND     |     GND
      VCC     |     RX
-----------------------------


회로도는 다음과 같습니다.

그냥 터치센서만 연결하면 어떻게 인식되는지 알 수가 없으니, LED 와 Piezo Buzzer 를 추가했습니다.

Piezo buzzer 사용하는 법은 아래를 참고해 보세요.


* Hardware | Arduino 로 buzzer 소리내기

https://chocoball.tistory.com/entry/HardwareArduinoBuzzer


LED는 220 ohm 저항을 달아주는 것을 잊지 마시구요.



실제 사진은 다음과 같습니다.






4. Sketch


소스는 다음과 같습니다.

각 digital pin 을 정의하고, touch sensor 에 입력이 들어오면 LED 와 buzzer 를 on 하는 구조 입니다.


입력이 없어지면, LED 및 buzzer 오 off 를 꼭 만들어 줘야 합니다.


int T_IN = 4;
int LED = 3;
int PIEZO = 2;

void setup()
{
	pinMode(T_IN, INPUT);
	pinMode(LED, OUTPUT);
}

void loop()
{
	if(digitalRead(T_IN)) {
		digitalWrite(LED, HIGH);
		tone(PIEZO, 600);
	}
	digitalWrite(LED, LOW);
	noTone(2);
}





5. 결과


너무 단순한 내용이라 틀리고 자시고 할 것이 없습니다.

동영상 갑니다.



신기한 것은 손가락이 직접 닿지 않더라도 가까이 대기만 해도 인식합니다. 한 1.5mm 정도?






FIN


요즘 항공무선통신 자격증을 준비하면서, 예전 실기 과목으로는 모르스 부호도 했었다는 것을 알게 되었습니다.

항공무선통신 자격증 시험 준비에 대해서는 다른 포스트에 있습니다.


* Life | 항공무선통신사 도전기 - 1

https://chocoball.tistory.com/entry/Life-airnav-comm-cert-1


나중에 시간 되면, 이번에 했던것을 조금 발전시켜 morse code + arduino 도 한번 도전해 보겠습니다.





* Morse code

https://en.wikipedia.org/wiki/Morse_code


Morse code is usually heard at the receiver as a medium-pitched on/off audio tone (600–1000 Hz), so transmissions are easier to copy than voice through the noise on congested frequencies, and it can be used in very high noise / low signal environments.


And

Hardware | MAX30105 파티클 센서 - 2

|

이 글은 이전 MAX30105 파티클 센서를 활용하여 OLED 에 심전도를 그려보는 도전기 입니다.

이전 글은 아래 link 를 참고하세요.


* Hardware | MAX30105 파티클 센서 - 1

http://chocoball.tistory.com/entry/Hardware-MAX30105-particle-sensor-1





1. min, max 와 scalar


일단 MAX30105 에서 입력받는 값은 5만에서 많게는 10만도 넘어갑니다.

이를 32 pixel 너비를 갖는 OLED 에 표현하려면 그 값에 맞도록 축소시켜야 합니다.



이에 더하여, 값들의 기준이 아래 그림처럼 널을 뛰므로 기준값을 잡기가 여간 쉽지 않습니다.



기준값을 잡기 위해 min, max 값을 한 사이클당 판별하여 scale in 치환값을 잡아줘야 합니다.


이를 위해 일단, 이전 사이클에서 얻은 제일 작은 min 값을 이용하여,

입력받는 값에서 빼면 그래프가 아래 그림처럼 내려갑니다.



OLED 폭이 128 pixel 이므로, 이 폭을 한 사이클로 잡습니다.

EXCEL 을 통하여 위의 방식을 검증해 본 결과 문제 없이 표현되는 것을 확인할 수 있었습니다.



OLED 의 y 값에 해당하는 값을 EXCEL 에서 32 pixel 기준으로 변환된 값을 array 에 입력하고

순서대로 출력해서 OLED 에 맞는지 최종 확인해 봅니다.



요리조리 검증해 본 결과 아래 식을 통해서 min, max 값과 한 사이클을 OLED 폭인 128 에 표현하고

다시 0 부터 시작하는 - 화면이 바뀌는 방법을 확인하였습니다.


	irValue = particleSensor.getIR();
	
	if( x > 127) { //refresh OLED screen
		display.clearDisplay();
		lastx=0;
		x=1;
		
		scaler = (max_irValue - min_irValue) / 32;
		pre_min_irValue = min_irValue;
		
		// reset min, max value
		max_irValue = irValue;
		min_irValue = irValue - 1;
	}





2. y값 reverse


OLED 에 표현시, x/y 값은 우리가 일반적으로 배운 왼쪽 아래에서 시작되는 것이 아니라,

왼쪽 위로부터 값의 증가를 표현합니다.



즉, sensor 로부터 값을 입력 받으면, 상하 전치를 시켜줘야 합니다.

제가 쓰고 있는 것은 상하 32 pixel 이므로, 아래 한 pixel 을 빼면 31 이므로,

31 에서 입력받은 값을 빼주면 표현하고자 하는 위치로 바꿀 수 있습니다. 



	// invert y values to fit OLED display
	if ( pre_min_irValue > irValue) {
		y = 31;
	} else {
		y = 31 - ((irValue - pre_min_irValue) / scaler);
	}

값이 너무 적어지면, 값이 역전하여 아래 그림같이 튀어버립니다.

그래서 전 사이클에서 확인 되었던 min value 보다 적어지면 강제적으로 최저값을 할당합니다.

여기서 "y = 31" 은 OLED 상에서는 제일 밑에 표시되는, 일상의 0 값과 같습니다.






3. BPM 과 piezo buzzer


심전도의 값이 가장 높아지면 buzzer 를 울리게 하는 소스 입니다.

또한 BPM 값도 표현해 줍니다.


BPM 값은 심전도의 한 사이클 평균을 내어 1분동안 얼마나 맥박이 뛰는지를 수치화 한 값입니다.



소스는 다음과 같고, 아래 blog 를 전면 참고하였습니다.


* Heart beat Sensor and “ECG” Display

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


	ThisTime=millis();
	if( y < UpperThreshold ) {
		if(BeatComplete) {
			BPM=ThisTime-LastTime;
			BPM=int(60/(float(BPM)/1000));
			BPMTiming=false;
			BeatComplete=false;
			tone(2,1000,250);
		}
		if(BPMTiming==false) {
			LastTime=millis();
			BPMTiming=true;
		}
	}
	if((y > LowerThreshold) && (BPMTiming))
		BeatComplete=true;






4. source


지금까지의 작업을 모두 합하여 하나의 소스로 만들었습니다.


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

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"

// Hardware SPI
#define OLED_DC     6
#define OLED_CS     7
#define OLED_RESET  8
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);

MAX30105 particleSensor;

unsigned int irValue;
unsigned int max_irValue;
unsigned int min_irValue;
unsigned int x = 0;
unsigned int y;
unsigned int lastx = 0;
unsigned int lasty = 0;
unsigned int scaler;
unsigned int pre_min_irValue;
int BPM;
int LastTime = 0;
int ThisTime;
bool BPMTiming=false;
bool BeatComplete=false;
#define UpperThreshold 10
#define LowerThreshold 25

void setup() {
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  
  // initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { //Use default I2C port, 400kHz speed
    display.println("MAX30105 was not found. Please check wiring/power.");
    while (1);
  }
  
  //Setup to sense a nice looking saw tooth on the plotter
  byte ledBrightness = 0x1F; //Options: 0=Off to 255=50mA
  byte sampleAverage = 8; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode = 3; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  int sampleRate = 1000; //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
  
  // initiate min, max values
  irValue = particleSensor.getIR();
  max_irValue = irValue;
  min_irValue = max_irValue - 1; 
  for (int ini ; ini < 100 ; ini++) {
	  irValue = particleSensor.getIR();
	  
	  if (max_irValue < irValue) {max_irValue = irValue;}
	  if (min_irValue > irValue) {min_irValue = irValue;}
  }
  
  display.display();
}

void loop() {
	irValue = particleSensor.getIR();
	
	if( x > 127) { //refresh OLED screen
		display.clearDisplay();
		lastx=0;
		x=1;
		
		scaler = (max_irValue - min_irValue) / 32;
		pre_min_irValue = min_irValue;
		
		// reset min, max value
		max_irValue = irValue;
		min_irValue = irValue - 1;
	}
	
	display.setTextColor(WHITE);
	ThisTime=millis();

	// invert y values to fit OLED display
	if ( pre_min_irValue > irValue) {
		y = 31;
	} else {
		y = 31 - ((irValue - pre_min_irValue) / scaler);
	}
	
	// draw heartbeat lins
	display.drawLine(lastx, lasty, x, y, WHITE);
	lasty = y;
	lastx = x;
	
	// update min, max values
	if (max_irValue < irValue) {max_irValue = irValue;}
	if (min_irValue > irValue) {min_irValue = irValue;}
	
	ThisTime=millis();
	if( y < UpperThreshold ) {
		if(BeatComplete) {
			BPM=ThisTime-LastTime;
			BPM=int(60/(float(BPM)/1000));
			BPMTiming=false;
			BeatComplete=false;
			tone(2,1000,250);
		}
		if(BPMTiming==false) {
			LastTime=millis();
			BPMTiming=true;
		}
	}
	if((y > LowerThreshold) && (BPMTiming))
		BeatComplete=true;
	
	// display BMP
	display.fillRect(0,24,64,32,BLACK);
	display.setCursor(0,24);
	display.print("      BPM");
	display.setCursor(0,24);
	display.print(BPM);
	
	// check finger is on the sensor
	if (irValue < 10000) { display.setCursor(1,1); display.print("NO Finger?"); }
	
	// display all data to OLED
	display.display();
	x++;
}


결과 동영상을 올려 봅니다.







FIN


이걸 구현해 보려고 3주간 주말 = 토, 일 이틀간 x 3 = 6일 동안 삽질의 연속이었습니다.

이 문제는 소스에서 scalar 를 구하기 위한 나누기를 해야 하는데, % 연산자를 사용했기 때문이었습니다.


* Modulo

https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/modulo/


% 연산자는 몫을 구하는 것이 아니라, 나머지를 구하는 연산자지요!!!

반대로 알고 있었던 것. 이걸 알아 차리는데 6일이나 걸렸습니다!!!



변수의 갯수도 줄여 보기도 하고, 각 값을 먼저 scale in 해서 결과를 내보기도 하고, 하여간 별짓 다 했습니다.

처음에 디버깅만 잘 했어도 이렇게 오래 걸리지는 않았을 듯 하네요.

디버깅 작업이 얼마나 중요한지 새삼 깨닳았습니다.



이렇게 하면 Serial Monitor 에도 이렇게 나오니 환장할 노릇이었습니다.


이 덕에 Hardware SPI 활용과 OLED refresh rate 등등을 공부하게 되었네요.

아이고야... 좀 쉬자.


SpO2 농도 값이나, 그래프를 좀더 안정적으로 보여줄 수 있도록 소스를 더 다듬고 싶었지만,

에너지를 너무 많이 써서 이번 작업은 여기까지 하겠습니다.


나중에 다시 생각나면, 소스코드를 다시 잡아 볼께요.


And
prev | 1 | next