Wemos mini 보드 사용중 일정주기로 함수가 실행되도록 하는 방법을 찾다가 발견한 "Ticker"에 대해 정리해봅니다.

millis() 함수를 사용하는 BlinkWithoutDelay 예제를 수정하여 사용할 수도 있지만 "Ticker"가 좀더 간단한 것 같습니다.

esp8266 관련 라이브러리를 설치하면 아두이노 기본예제에서도 찾을 수 있습니다.

 

 

사용법은 쉽습니다.

1초마다 blink하는 예제는

 

#include <Ticker.h> //Ticker Library

 

Ticker blinker;

 

#define LED 2 //On board LED

 

//=======================================================================

void changeState()

{

digitalWrite(LED, !(digitalRead(LED))); //Invert Current State of LED

}

//=======================================================================

// Setup

//=======================================================================

void setup()

{

Serial.begin(115200);

Serial.println("");

 

pinMode(LED,OUTPUT);

 

//Initialize Ticker every 1s

blinker.attach(1, changeState); //Use <strong>attach_ms</strong> if you need time in ms

}

//=======================================================================

// MAIN LOOP

//=======================================================================

void loop()

{

}

 

<참조글>

https://circuits4you.com/2018/01/02/esp8266-timer-ticker-example/

 

ESP8266 Timer and Ticker Example | Circuits4you.com

There are two timers in ESP8266 Timer0 and Timer1, one timer is used by its WiFi functions. We get only one timer to work. To avoid crash issues use ticker.

circuits4you.com

 

https://blog.naver.com/alfee0/220891064336

 

WeMos 사용기 #8 Timer !

Wemos 의 타이머 인터럽트에 대한 이야기 두번째 입니다. 몇 번인가 적었지만, 제일 좋은 것은 데이터 시...

blog.naver.com

 

ESP8266에 Deep_Sleep 모드가 있는 것처럼 아두이노 보드에 있는 Sleep Mode를 사용해봅니다.

<참고글>

https://cafe.naver.com/dgarduino/4028

 

아두이노 잠재우기와 깨우기 - Don...

대한민국 모임의 시작, 네이버 카페

cafe.naver.com

 

https://playground.arduino.cc/Learning/ArduinoSleepCode/

 

Arduino Playground - ArduinoSleepCode

attachInterrupt(0, pin2_isr, LOW); /* 0, 1, or many lines of code here */ set_sleep_mode(SLEEP_MODE_PWR_DOWN); cli(); sleep_enable(); sleep_bod_disable(); sei(); sleep_cpu(); /* wake up here */ sleep_disable();

playground.arduino.cc

 

https://www.element14.com/community/thread/40538/l/arduino-sleep-pin-interrupt?displayFullThread=true

불러오는 중입니다...

 

다섯가지 방법중 첫번째인 외부인터럽트를 이용한 방법으로 LED Blink를 10회 실행하며, Blink 횟수를 카운트하여 시리얼모니터로 출력하고  "Good Night.."출력 후 Sleep모드로 진입합니다.

버튼을 누르면 다시 깨어나 Blink를 시작합니다.

#include <avr/sleep.h>

int wakePin = 2; // pin used for waking up

int led=13;

void wakeUpNow() {

// execute code here after wake-up before returning to the loop() function

// timers and code using timers (serial.print and more...) will not work here.

// we don't really need to execute any special functions here, since we

// just want the thing to wake up

}

void setup() {

Serial.begin(115200);

pinMode(wakePin, INPUT_PULLUP);

pinMode(led, OUTPUT);

attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function wakeUpNow when pin 2 gets LOW

}

void sleepNow() {

set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here

sleep_enable(); // enables the sleep bit in the mcucr register

attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function

sleep_mode(); // here the device is actually put to sleep!!

// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

sleep_disable(); // first thing after waking from sleep: disable sleep...

detachInterrupt(0); // disables interrupt 0 on pin 2 so the wakeUpNow code will not be executed during normal running time.

}

void loop() {

Serial.println("Blink Start...");

for(int i=0; i<10; i++){

digitalWrite(led, HIGH);

delay(1000);

digitalWrite(led, LOW);

delay(1000);

Serial.println(i);

}

Serial.println("Good Night..");

delay(1);

sleepNow(); // sleep function called here

//Serial.println("Hello!");

}

 

 

버튼을 누른 후 깨어나 Blink Start...를 출력할때 제대로 출력되지 않는 현상이 보입니다.

미니 파워서플라이인 B3603을 이용하여 소모전류를 측정한 결과

Blink동작중 41mA

 

슬립모드 진입후 29mA로 확인되었습니다.

 

슬립모드 진입후에도 29mA의 소모전류가 흐르는 것은 LED, Regulator, usb시리얼용 IC(Atmega16u2)등이 계속 동작하기 때문일 것입니다.

전원이 공급되면 항상 켜지는 전원 표시용 LED를 제거한 후 소모전류를 확인해본 결과

<제거전>

 

<제거후>

 

Blink동작시 41mA -> 37mA로 4mA 감소

 

슬립모드 진입시 29mA -> 23mA로 6mA 감소되는 것이 보입니다.

아두이노 보드끼리 uart핀을 서로 연결하여 시리얼 데이타를 주고 받을 수 있습니다.

이때 보내는 쪽 보드(TX)의 TX와 받는쪽 보드(RX)의 RX와 연결해주고, 보내는보드의 RX핀과 받는보드의 TX와 연결해주어야 시리얼통신이 됩니다.

보내는 보드는 아두이노 나노, 받는 보드는 우노보드를 사용하였습니다. 

 

보내는 측(TX, 나노보드)의 소스코드는

void setup() {

// initialize serial communication at 9600 bits per second:

Serial.begin(115200);

}

 

// the loop routine runs over and over again forever:

void loop() {

// read the input on analog pin 0:

char msg[] = "Hello World";

// print out the value you read:

Serial.write(msg);

Serial.println();

delay(2); // delay in between reads for stability

}

나노보드의 하드웨어 시리얼핀을 통하여 "Hello World" String을

보내는데 delay(2)를 사용하여 2ms 쉬었다가 한번씩 보내도록 했습니다.

하드웨어 시리얼이므로 baudRate를 115200으로 할 수 있습니다.

배열 char msg[]을 사용하고, Serial.write()함수로 보냈습니다.

char msg[] = "Hello World";

Serial.write(msg);

 

이번에는 수신보드(RX)인 우노보드에 업로드한 코드입니다.

아두이노 ide에 있는 serialEvent()예제코드에서 loop()문에 

Serial.println("OK!");를 추가하였습니다.

이렇게 하면 "OK!"를 시리얼모니터로 출력하면서 동시에 serialEvent()함수로 TX로부터 받은 시리얼값(여기서는 "Hello World")을 출력하게 됩니다.

 

String inputString = ""; // a String to hold incoming data

bool stringComplete = false; // whether the string is complete

 

void setup() {

// initialize serial:

Serial.begin(115200);

// reserve 200 bytes for the inputString:

inputString.reserve(200);

}

 

void loop() {

// print the string when a newline arrives:

Serial.println("OK!");

if (stringComplete) {

Serial.println(inputString);

// clear the string:

inputString = "";

stringComplete = false;

}

}

 

/*

SerialEvent occurs whenever a new data comes in the hardware serial RX. This

routine is run between each time loop() runs, so using delay inside loop can

delay response. Multiple bytes of data may be available.

*/

void serialEvent() {

while (Serial.available()) {

// get the new byte:

char inChar = (char)Serial.read();

// add it to the inputString:

inputString += inChar;

// if the incoming character is a newline, set a flag so the main loop can

// do something about it:

if (inChar == '\n') {

stringComplete = true;

}

}

}

<출력결과>

TX측(나노보드)

RX측(우노보드)

 

RX보드의 loop()문에 있던 "OK!"데이타가 2개 출력될때, TX보드로 부터 받은 "Hello World"데이타가 1개 출력되므로

출력빈도를 1대 1로 맞추려면 TX보드의 출력빈도를 늘려주면 됩니다.

TX보드의 소스코드중 delay타임을 delay(1)로 한 경우 RX보드의 출력데이타가 다음과 같이 깨짐현상이 발생하고,

Hello World 데이타 갯수가 많아 1.5ms로 변경하여 봅니다.

delay(1.5);는 없으므로 delayMicroseconds(1500);으로 변경 후 확인 결과

1개씩 출력하며 1대1로 맞았습니다.

 

void setup() {

// initialize serial communication at 9600 bits per second:

Serial.begin(115200);

}

 

// the loop routine runs over and over again forever:

void loop() {

// read the input on analog pin 0:

char msg[] = "Hello World";

// print out the value you read:

Serial.write(msg);

Serial.println();

delayMicroseconds(1500); // delay in between reads for stability

}

 

마지막으로 TX측 소스코드를 바꾸어 테스트해보면

<소스코드>

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(115200);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0: 
  String msg = "Hello World";   
  // print out the value you read:
  //Serial.write(msg);
  Serial.println(msg);
  delayMicroseconds(1500);        // delay in between reads for stability   
}

배열함수대신 String 변수 msg를 정의하였고, Serial.write(msg)대신 Serial.println(msg) 함수를 사용하였습니다.

 

결과는 동일하나 OK! 데이타가 간혹 2개씩 출력되는 결과가 보입니다.

코드를 수정하며 TX쪽에서 보내지는 시리얼데이타 전송속도가 달라진다는 것을 짐작할 수 있습니다.

 

주변밝기를 조도센서를 이용하여 읽고, 읽은 값으로 LED의 밝기를 조절하도록 하려면...

조도센서를 읽는 것은 analogRead(pin) 함수를 사용하고, LED에 표시하는 것은 pwm을 사용하여 analogWrite(pin, value) 함수를 사용하면 됩니다.

앞서 조도센서를 전압 5V쪽에 연결하면 밝을때 analogRead()값이 커진다고 하였으므로, 밝으면 LED도 밝게 표시하도록

조도센서를 5V쪽에 연결하고, GND쪽으로 1KΩ 저항을 연결하였습니다.

 

#define led 5

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(115200);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
  analogWrite(led, sensorValue);
  delay(100);
}

analogRead()를 통해 읽은 sensorValue값을 그대로 analogWrite()의 pwm값으로 사용하였습니다.

밝은 조건일때

※ 사실 sensorValue = 688은 pwm출력으로 사용하면 문제가 됩니다. pwm출력범위는 0~255입니다

 

어두운 조건을 만들기 위해 조도센서를 덮었습니다. sensorValue값이 50이하로 떨어졌습니다.

사진상으로는 잘 나오지 않았지만, 밝기가 감소합니다.

 

좀 더 밝기를 구분해 줄수 있는 방법을 찾아봅니다.

첫번째는 아날로그 입력인 sensorValue 값은 0~1023사이의 범위를 가지는 반면에 pwm출력은 0~255의 범위를 가지기 때문에, sensorValue/4를 하여 pwm출력으로 사용하는 방법입니다.

analogWrite(led, sensorValue/4);

Serial.println(sensorValue/4);

시리얼 모니터 출력도 sensorVlaue/4를 하여 pwm출력값으로 변경하였습니다.

적용결과는

 

이번에는 조도센서를 가린 경우

앞서의 경우보다 값이 1/4만큼 줄었기 때문에 어두운조건에서 LED 밝기가 약해졌음을 확인할 수 있습니다.

다른 방법으로 map()함수를 사용하여 봅니다.

https://www.arduino.cc/reference/en/language/functions/math/map/

 

Arduino Reference

Description Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow, a value of fromHigh to toHigh, values in-between to values in-between, etc. Does not constrain values to within the range, because out-of-range v

www.arduino.cc

 

https://blog.naver.com/msyang59/220973634210

 

Map.html

참조 -> 언어 -> 함수 -> 수학 -> map() 함수 관련 설명을 번역하여 첨부에 올렸습니다: 첨부:

blog.naver.com

 

현재 조건에서 조도센서 값이 변하는 범위를 확인합니다.

#define led 5


// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(115200);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  Serial.print(sensorValue);
  // print out the value you read:
  sensorValue = map(sensorValue, 30,700,0,255);  
  analogWrite(led, sensorValue);
  Serial.println("\t"+String(sensorValue));
  delay(100);
}

sensorValue의 범위는 최소 30 ~ 최대 700으로 하였습니다.

pwm출력의 범위는 그대로 0~255로 하였습니다.

map함수는 30 -> 0, 700->255의 범위를 가지도록 매핑시키는 함수입니다.

앞의 값은 조도센서의 sensorValue값이고 뒤의 값은 map()함수를 실행 후의 sensorValue값을 출력합니다.

이런....어두울때의 sensorValue값이 최소범위 30이하로 내려가 마이너스값이 되었습니다.

이때 LED밝기는 전혀 어둡지 않습니다. 밝을때와 차이가 없습니다.

 

 

최소값의 범위를 다시 20으로 조정하여

sensorValue = map(sensorValue, 20,700,0,255); 

이번에는 최대값이 700을 넘었...

map()함수의 결과도 pwm출력범위 255를 넘어버렸습니다.

밝은조건에서 LED가 어둡네요.

 

 

 

다시 조정합니다.

sensorValue = map(sensorValue, 20,800,0,255); 

 

이번에는 정상적으로 LED의 밝기 구분이 좀 더 확실해졌습니다.

만약 입력값의 최대,최소범위를 좀 더 확실하게 알 수 있다면 출력값의 범위도 좀 더 세밀하게 조정이 가능합니다.

https://blog.naver.com/mkhee77/220824616628

 

풀업저항과 풀다운저항에 대하여, 조도센서 배치에 따른 입력값

Arduino로 놀기

blog.naver.com

 

https://blog.naver.com/mkhee77/221419995243

 

전압 분배 회로의 저항값의 설정(2)

https://ko.wikipedia.org/wiki/%EC%A0%84%EC%95%95_%EB%B6%84%EB%B0%B0_%EB%B2%95%EC%B...

blog.naver.com

 

조도센서(CDS)는 빛의 밝기에 따라 저항값이 변하는 일종의 가변저항으로 이해하면 편할것 같습니다.

저항의 한 종류이므로 저항의 전압분배의 법칙을 적용할 수 있습니다.

조도센서는 빛을 받으면 저항값이 작아지고, 어두운 조건에서 빛을 적게받으면 저항값이 커집니다.

위의 그림과 같이 밝기 조건에 대하여 조도센서의 위치에 따라 analogRead의 값이 달라지고, 서로 반대방향으로 움직입니다.

왼쪽 그림과 같이 조도센서가 전원쪽(up side)에 있게되면, 어두운 조건에서 저항값이 커지고, analogRead값은 작아지게 되며, 이것은 전압분배식에서 분모에 위치한 CDS(Ω) 값이 커지면 전체값이 작아지는 것으로 설명됩니다.

반대로, 오른쪽 그림과 같이 조도센서가 GND(down side)쪽에 있게되면, 어두운 조건에서 저항값이 커지고, analogRead값은 커지개 되며, 이것은 역시 오른쪽의 전압분배식에서 CDS(Ω) 값이 커지면서 분자와 분모에 모두 값이 커지지만 분자에 더 영향을 미쳐 전체값이 커지는 것으로 설명됩니다.

      

아두이노 기본예제인 ReadAnalogVoltage를 활용하여 정확한 전압을 읽는 예제입니다.

/*
  ReadAnalogVoltage

  Reads an analog input on pin 0, converts it to voltage, and prints the result to the Serial Monitor.
  Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu).
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/ReadAnalogVoltage
*/

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(115200);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.print(sensorValue);
  Serial.print("\t");
  Serial.println(voltage);
  delay(100);
}

변경내용은 sensorValue값을 출력하고, delay(100)을 주었습니다.

5V핀을 A0핀에 직접 연결한 후의 시리얼모니터 출력결과는

float voltage = sensorValue * (5.0 / 1023.0) = 1023 * (5.0 / 1023.0) = 5.0

5V 핀의 실제 전압을 멀티테스터로 확인결과 4.86V로 확인되었습니다.

소스코드중 float voltage = sensorValue * (5.0 / 1023.0); 을

float voltage = sensorValue * (4.86 / 1023.0); 으로 바꾸면

아날로그 입력핀 A0에서 읽은 값은 1023으로 동일하지만 5.0에서 4.86으로 실제 전압을 적용하면

voltage값도 그에 맞추어 변경됩니다.

아두이노 기본예제인 ReadAnalogVoltage를 이용하여 아날로그 입력핀으로 정확한 전압값을 읽기위해서는

float voltage = sensorValue * (4.86 / 1023.0); 부분에서 4.86값을 아두이노 보드의 5V핀의 실제전압을

적용해주어야 합니다.

아두이노 기본 예제중 ReadAnalogVoltage 예제입니다.

아두이노관련 영어어휘를 익히고자 일부러 영문으로 설정하여 사용하여 지금은 한글보다 더 익숙하게 되었습니다.

ide설정을 일부러 영문으로 시작해보는 것도 좋은 방법인 것 같습니다.

/*
  ReadAnalogVoltage

  Reads an analog input on pin 0, converts it to voltage, and prints the result to the Serial Monitor.
  Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu).
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/ReadAnalogVoltage
*/

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
}

아두이노 우노나 나노의 경우 아날로그 입력핀을 10비트로 읽습니다.

2의 10승 = 1024, 하여 0부터 1023까지 1024단계로 읽습니다.

위의 예문 중간부

// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V): 

는 전압 0-5V까지 0-1023의 값으로 읽는다는 의미입니다.

즉 0V -> 0이고, 5V -> 1023에 대응된다면, 5V를 1023등분하면

5V / 1023 = 0.00488 약 0.0049V = 4.9mV

아날로그 입력핀으로 읽는 값은 4.9mV 단위로 구분되어 읽을수 있게 됩니다(해상력이 4.9mV라고 할수 있음)

예를 들어 읽은 값이 value = 758 이라고 했을때 몇 V인지 계산한다면

758 x 0.0049 = 3.7142V 이고

비례식 5V : 1023 = x : 758

x = 758 x 5V/1023 = 3.7047V (0.00488과 0.0049에 의한 오차) 

위의 예제 코드중 float voltage = sensorValue * (5.0 / 1023.0); 은

x 를 구하는 전압 float voltage, 758 을 아날로그 입력값 sensorValue로 바꾸면 동일한 식입니다.

 

 

 


티스토리에 새로 블로그를 시작합니다.

아두이노와 라즈베리파이를 공부하며 기록하는 내용들이 후에 좋은 자료로 남길 바라며...







+ Recent posts