[아두이노] 온도센서를 이용한 경보 온도계 다른 접근

IOT/아두이노|2019. 6. 3. 09:00

[아두이노] 온도센서를 이용한 경보 온도계 다른 접근 




[주제 ]

  • 일반스위치버턴을 인터럽트스위치버턴으로 변경
  • 50도 이상 증가 한 후 50이하로 떨어진 순간에 현재 온도가 출력되게 변경

지난시간에 간단히 경보 온도계를 만들었는데 그냥 넘어가기가 그래서 코딩적 접근 방법을 다르게 시도해보는 시간을 갖도록 하겠습니다. 하드웨어 부분은 동일하지만 어떻게 코딩을 하냐에 따라서 다양한 결과를 만들어 낼 수 있습니다.

1. 경보 온도계 회로도



경보 온도계는 지난 시간과 동일합니다. 참고에 지난시간의 post를 보고 사전학습을 미리 해주세요.


2. 코딩


[ 기본 소스 ]

#include <LiquidCrystal.h>

//LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(3, 4, 8, 9, 10, 11);

const int switchPin = 2;
const int piezoPin = 12;
unsigned long timeVal=0;
float V=0;
float C=0;
float F=0;

void setup() {
  pinMode(switchPin, INPUT_PULLUP);

  lcd.begin(16,2);
  lcd.setCursor(0, 0);
  lcd.print("Hello World");
  delay(1000);
  lcd.clear();
}

void loop() { 
  V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산
  //float V = analogRead(A0)*5.0/1023;

  C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
  F = C*9.0/5.0+32; //화씨 F = C*1.8+32;
    
  if(digitalRead(switchPin)== LOW){
    output();
    timeVal=millis();
    delay(500);
  }
  if(millis()-timeVal>=2000){
    output();  
    timeVal=millis();
  }
  if(C>50){
    output();
    tone(piezoPin,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);
    timeVal=millis();
  }
}  
 void output(){
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("C : ");
   lcd.setCursor(6, 0);
   lcd.print(C);  
   lcd.setCursor(0, 1);
   lcd.print("F : ");
   lcd.setCursor(6, 1);
   lcd.print(F);  
  }

float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}

지난시간의 실험한 기본 소스입니다. 이 소스에 대한 설명은 생략하겠습니다. 모르는분들은 지난시간의 post를 보고 오시기 바랍니다. 기본소스에 어떤 부분이 수정되고 추가 되었는지를 비교하면서 보시기 바랍니다.

1) 스위치 버턴을 인터럽트 스위치버턴으로 변경


const int interruptPin = 2;//인터럽트핀

void setup() { 
  pinMode(interruptPin, INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING);
}

void switchFn(){
   인터럽트 발생 시 처리 명령문;
}

아두이노우노는 2,3번이 인터럽트 핀입니다. 다른 핀을 사용 할 경우는 반응하지 않습니다. 다른 아두이노보드 일 경우는 해당 보드의 인터럽트 핀 넘버가 다를 수 있음으로 해당 보드의 인터럽트 핀 정보를 찾아보시기 바랍니다.

attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING);
FALLING : HIGH -> LOW로 변할때

이렇게 setup()함수 안에다 인터럽트 함수를 선언해 놓으면 해당 interruptPin에 전류가 HIGH->LOW로 변할 때 switchFn()함수를 호출하게 됩니다. 해당 인터럽트 2번핀은 풀업모드의 스위치버턴입니다. 처음 상태가 HIGH이고 스위치를 누르면 LOW이기 때문에 스위치를 누를대 HIGH->LOW로 변하게 됩니다. 그러면, switchFn()함수가 호출이 됩니다. 어떤 원리인지 아시겠지요.

[기존소스]

const int switchPin = 2;
void setup() {
  pinMode(switchPin, INPUT_PULLUP);
}
void loop(){
  if(digitalRead(switchPin)== LOW){
    output();
    timeVal=millis();
    delay(500);
  }
}   

변경 후,

boolean switchState=false; //스위치 상태값

void setup() { 
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING);
}
void loop(){
  if(switchState==true){
    output();    
    timeVal=millis();    
    switchState=false;
  }
}   
void switchFn(){
  switchState=true;
}

같은 동작의 같은 느낌의 코딩입니다. 하지만 어떤 차이가 있을까요. 변경 전 스위치 버턴은 loop()함수에서 무한 반복할때 순서대로 명령문을 처리할 때 스위치가 눌러졌는지 확인하는 원리이고 변경 후 스위치 버턴은 loop()함수에서 무한 반복하는 명령문들의 순서랑 상관없이 스위치버턴 이벤트가 발생합니다. 즉, loop()함수와는 별개로 독립적으로 스위치버턴 동작을 수행합니다.

loop()함수의 지배권에 있느냐 독립적으로 있느냐에 차이인 것이죠. 사용목적에 따라서 사용하시면 됩니다.

2) 경보 해제 후 온도 출력


[기존소스]

void loop(){
  if(C>50){ 
    output();
    tone(piezoPin,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);    
    timeVal=millis();    
    tmpState=true;    
  }  
}

지난시간에 숙제로 남겨 둔 50이상일 때 경보음과 현재 온도를 출력하게 코딩을 했었습니다. 그렇다면 50도 이상이 되었다가 50도 이하가 되는 순간 온도는 수정되어야 하지만 지난 소스에서는 바로 수정되는게 아니라 정해진 시간이 될 때까지는 온도값이 출력되지 않습니다. 그 부분을 해결하라고 숙제를 내줬는데 해결책은 알아 볼까요.

어떤 상태가 되면 그 상태가 되었을 때 그 상태에 대한 상태값을 변수로 저장하면 됩니다. 50이상이 된다면 이상이 되었을 때의 상태값을 가지고 있을 때 그 상태값을 기준으로 50이하가 된 순가 현재 온도를 출력시키면 해결 됩니다. 설명이 어렵게 되었는데 코딩을 살펴볼까요.

if(C>50){
 tmpState=true;
}
if(tmpState==true){
  if(C<50){
    tmpState=false;
  }
}

C의 온도가 50도 이상이면 tmpState은 true로 50이상인 상태가 되었다는 것을 상태변수에 저장해 놓습니다. 그러기 다음 if문을 통해서 50이상인 상태가 되었다면 다시 if문으로 C가 50이하로 떨어졌는지 체크하게 되고 50이하로 떨어졌다면 다시 tmpState의 상태값은 원상태로 돌아가서 50이상이 될때까지는 false가 됩니다. 이 원리는 자주 사용하는 원리이니깐 이참에 꼭 알아두시기 바랍니다.

if문은 어떤 A조건의 상태가 되면 그 A상태를 기억 할 수 있고 그 A상태를 기준으로 B조건에 들어 갈 수 있고 B라 상태를 만들 수 있습니다. 서로 다른 조건에 대해서 상태에 따라서 개입을 하고 싶을 때 if문을 활용 한다는 점을 꼭 기억해 두세요.

변경 후,

boolean tmpState = false; //온도 상태값

void loop(){
  if(C>50){ 
    output();
    tone(piezoPin,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);    
    timeVal=millis();    
    tmpState=true;    
  }  
  
  if(tmpState==true){
    if(C<50){ 
      timeVal=millis();    
      tmpState=false;    
      output();
    }    
  }
}

3. 종합 소스


2초 단위로 LCD16x2에 온도와 습도가 출력됩니다. 여기서 스위치버턴을 누르면 인터럽트함수가 호출되고 switchState 값을 true로 변경하여 스위치가 눌러졌음을 나타냅니다 그리고 나서 if문에서 switchState가 true면 현재 온도와 습도를 출력하게 되게 코딩이 되어 있습니다. 스위치를 눌렀을 때 현재 온도와 습도를 출력하게 만든 것이죠. 다음으로, 온도가 50이상일 때 경보음과 현재 온도가 출력되는데 tmpState 변수에 true로 50이상인 상태를 나타냅니다. 그 다음 if문으로 온도가 50이하가 될때 현재 온도가 출력되게 함으로써 실시간으로 50이상으로 올라갔다가 50이하로 떨어졌을 때 현재 온도가 출력되게 함으로써 지난 시간의 코딩에 비해 경보 온도계를 매끄럽게 표현이 되었네요.

#include <LiquidCrystal.h>

//LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(3, 4, 8, 9, 10, 11);


//const int switchPin = 2;
const int interruptPin = 2;//인터럽트핀
boolean switchState=false; //스위치 상태값
boolean tmpState = false; //온도 상태값

const int piezoPin = 12;
unsigned long timeVal=0;
float V=0;
float C=0;
float F=0;


void setup() { 
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), switchFn, FALLING);
  
  lcd.begin(16,2);
  lcd.setCursor(0, 0);
  lcd.print("Hello World");
  delay(1000);
  lcd.clear();

}

void loop() {
 
  V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산
  
  //float V = analogRead(A0)*5.0/1023;

  C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
  F = C*9.0/5.0+32; //화씨 F = C*1.8+32;
  
  
  if(switchState==true){
    output();    
    timeVal=millis();    
    switchState=false;
  }
  if(millis()-timeVal>=2000){
    output();  
    timeVal=millis();
  }
  
  if(C>50){ 
    output();
    tone(piezoPin,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);    
    timeVal=millis();    
    tmpState=true;    
  }  
  
  if(tmpState==true){
    if(C<50){ 
      timeVal=millis();    
      tmpState=false;    
      output();
    }    
  }
}  

void output(){
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("C : ");
   lcd.setCursor(6, 0);
   lcd.print(C);  
   lcd.setCursor(0, 1);
   lcd.print("F : ");
   lcd.setCursor(6, 1);
   lcd.print(F);  
}
void switchFn(){
  switchState=true;
}
float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}


4. 결과


영상으로는 정확히 의미를 전달되지 않은 것 같습니다. 직접 공개회로도에 가셔서 TMP36 온도센서를 가상시뮬레이터에서 직접 제어해서 결과를 직접 체험해 보셨으면 합니다.


마무리


오늘은 코딩에 대해서 살펴 보았습니다. 지난시간의 소스는 약간 불안정한 소스였고 오늘은 좀 더 개선된 소스 이면서 새롭게 인터럽트 방식을 적용해 보았습니다. 코딩은 딱 하나의 정답은 없습니다. 지난시간의 소스와 오늘 소스를 통해서 다양한 접근 방식의 코딩을 하셨으면 합니다. 어떤 코딩을 하고 그 코딩으로 결과가 나왔으니깐 마무리하지 말고 이런식으로 또 다른 접근법이 없는지 계속 상상을 하면 보이지 않았던 것이 보이고 코딩이 개선되고 상상코딩의 능력이 올라가게 됩니다.

그리고, 여러분들은 지금까지의 배웠던 부품 중 떠오르시는 것이 있으면 부품을 더 결합해서 재밌는 형태로 변형 시켜 보셨으면 합니다.


댓글()

[아두이노] 온도센서(TMP36)+LCD16x2 경보 온도계 응용

IOT/아두이노|2019. 6. 2. 09:00

[아두이노] 온도센서(TMP36)+LCD16x2 경보 온도계 응용



오늘은 @uuu95님이 질문한 DHT11 실험을 가상시뮬레이터에서 한번 구현해보고 싶어서 실험을 하게 되었네요. DHT11 부품이 가상시뮬레이터에서 제공되지 않기에 TMP36 부품으로 대신하여 실험을 할까 합니다. 내용을 보니깐 온도를 읽어서 LCD16x2 모니터에 결과를 출력하는데 5초단위로 지속적으로 출력하고 스위치를 누르면 현재 온도를 출력하고 일정온도 이하가 되면 피에조부저가 경고음을 울리게 하는 실험이더군요. 한번 위 내용을 가상시뮬레이터에서 제 나름대로 재구성하여 실험을 하겠습니다.

참고로 오늘 실험을 하기전에 위에 링크가 걸린 참고 post들은 각 부품에 대한 기초 내용으로 구성되어 있기 때문에 가셔서 각 부품의 사용법을 사전학습하시고 오세요. 아시는 분들은 그냥 넘어가셔도 되고요 중복되는 내용은 구지 처음부터 설명을 할 필요는 없겠죠.


1. 온도계 회로도


  • 준비물 : 스위치버턴 1개, TMP36 1개, 아두이노우노
  • 내용 : 스위치버턴은 2번핀에 연결하고 TMP36은 A0핀에 연결하여 값을 읽는다.
  • 공개회로도 : https://www.tinkercad.com/things/k9ksK4Tk94a(TMP36+스위치버턴)


온도센서와 스위치 버턴을 사용하여 온도값을 시리얼 모니터로 출력시켜 코딩을 우선 합시다.

2. 코딩


코딩은 5초 단위로 TMP35 센서의 값을 읽어와 온도와 습도를 출력하도록 할려고 했는데 시뮬레이터를 빠르게 동작시키기 위해 2초 단위로 수정하여 온도와 습도가 나오게 할 예정입니다. 이때 스위치 버턴을 누르면 현재 온도와 습도가 출력되게 설계합니다. 그런데 2초 단위로 온도와 습도가 출력되는데 delay(2000) 함수를 사용하면 2초 동안은 스위치를 눌러도 반응을 하지 않습니다. 대기 시간에는 아두이노는 휴먼상태가 되기 때문에 스위치를 누를 수 없기 때문에 delay()함수를 사용하지 않는 delay 효과를 부여해서 제어함으로써 실시간으로 스위치가 눌러지면 현재 온도와 습도가 출력되고 2초 단위로 현재 온도와 습도가 출력되게 코딩을 만들어 봅시다.

[delay()함수 없이 delay] 2초 단위로 if문 안에 명령문 수행

unsigned long timeVal=0; //이전시간

void loop(){
  if(millis()-timeVal>=2000){ //딜레이 시간 2초(2000)
    2초 단위로 동작;
    timeVal=millis();
  }
}

식 : 현재시간(millis) - 이전시간(timeVal) > 딜레이시간(2000)

와 같이 코딩을 하면 2초 단위로 if문안의 명령문을 수행합니다. 수행하고 수행 후 timeVal은 수행된 시간 millis()시간을 저장함으로써 다음 2초 시간을 구할 때 사용합니다.

[스위치버턴 풀업모드버턴]

const int switchPin = 2;
void setup() { 
  pinMode(switchPin, INPUT_PULLUP);
}
void loop(){
  if(digitalRead(switchPin)== LOW){
    스위치가 눌러질때 명령문;
    delay(500);
  }
}

풀엄모드 스위치버턴이라서 pinMode()은 INPUT_PULLUP으로 선언됩니다. 동작은 스위치를 누르지 않는 상태는 HIGH상태이고 스위치를 누르면 LOW상태가 됩니다 그래서, loop()함수에서 스위치가 눌러졌을 때 LOW랑 같은지로 체크하게 됩니다.

[온/습도 계산]

float V=0;
float C=0;
float F=0;

void loop(){
  V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산
  //V = analogRead(A0)*5.0/1023;
  C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
  F = C*9.0/5.0+32; //화씨 F = C*1.8+32;
}

float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}

C, F 공식에 대입하기 위해서 V값을 구할때 0~5V 사이의 전류값을 알아야 합니다. 하지만, analogRead(A0)함수로 읽게 되면은 0~1023의 값으로 읽게 되는데 그러면 주석으로 처리한 식으로 계산을 한번 더 해야 합니다. 그래서, map()함수를 변형 시켜서 다이렉트로 0~5V 사이의 전류값을 구하도록 수정했습니다. 원래 map()함수는 float형이 아닌데 실수값을 구해야 해서 float형으로 변형 사용자정의함수로 직접 만들었습니다 전류를 구해서 C, F를 식에 대입하여 온도와 습도를 구하게 됩니다.

설계

  1. TMP36을 읽어 온/습도를 계산한다.
  2. 스위치가 눌러졌는지 확인(스위치가 눌러졌으면 현재 온/습도 출력한다.) 출력된 시점을 기준으로 2초후 온습도가 출력하게 만든다.
  3. 2초단위로 온/습도를 출력한다.
const int switchPin = 2;
unsigned long timeVal=0;
float V=0;
float C=0;
float F=0;

void setup() {
  Serial.begin(9600);
  pinMode(switchPin, INPUT_PULLUP);
}

void loop() {

  //TMP36읽어 온도와 습도 계산
  V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산
  //V = analogRead(A0)*5.0/1023;

  C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
  F = C*9.0/5.0+32; //화씨 F = C*1.8+32;
  
  
  if(digitalRead(switchPin)== LOW){ //스위치 눌러졌는지
    output();
    timeVal=millis(); //현재시간을 이전시간변수에 저장
    delay(500);
  }
  if(millis()-timeVal>=2000){ //현재시간-이전시간의 차이 2000인지 확인
    output();  
    timeVal=millis(); //현재시간을 이전시간변수에 저장
  }  
}  

//온도와 습도 출력
void output(){   
   Serial.print("C : ");
   Serial.println(C);  
   Serial.print("F : ");   
   Serial.println(F);  
}

// TMP36에서 읽은 0~1023값을 0~5V로 변환
float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}

딜레이 함수를 사용하지 않기 때문에 실시간으로 계속 온도가 측정이 되고 스위치가 눌러지면 그때 현재 온/습도 값이 시리얼모니터로 출력된다. 그리고 출력된 시점이 이전시간이 되어 다음 2초 후에 온/습도가 출력된다. 스위치가 안눌러졌다면 2초단위로 온/습도가 출력된다.

3. 결과


2초후 부터 지속적으로 온도와 습도가 출력되는데 스위치 버턴을 누르면 바로 온도와 습도가 출력됩니다. 출력시간은 여러분들이 2000 대신에 다른 값으로 수정하시면 원하는 시간대 출력되도록 만들 수 있습니다.


4. 온도계에 피에조부저로 경보 알림


1) 회로도


  • 준비물 : 피에조 부저 1개, 스위치버턴 1개, TMP36 1개, 아두이노우노
  • 내용 : 추가로 피에조 부저를 12번 핀에 연결한다.
  • 공개회로도 : https://www.tinkercad.com/things/20FHbzZpihk(TMP36+스위치버턴+피에조부저)


12번 핀을 통해 피에조부저에 경보음을 출력한다.

2) 코딩


if(온도>50){
    tone(12,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);            
}

온도가 50도 이상이면 경보음이 울리게 됩니다. tone()~noTone()으로 도음을 끊어서 경보음이 울리게 한다.

[수정소스] 추가된 코드영역만 표시 합니다.

... 생략
const int piezoPin = 12;

void setup(){
  ... 생략
}
void loop() {
 
  ... 생략
    
    //온도가 50도이상이면 경보음
  if(C>50){
    output();
    tone(piezoPin,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);
    timeVal=millis();
  }
}
... 생략

나머지 부분은 위의 소스랑 동일합니다. 온도가 50도 이상이면 해당 온도/습도를 시리얼모니터에 출력하고 경보움이 짧게 끊어서 울린다. 그리고 현재시간을 이전시간으로 저장한다. 용도는 온도가 50도 이하로 떨어질때까지 지속적으로 경보음이 울리게 하는 목적이라고 생각하시면 되겠습니다.

3)결과


움짤로 만들다 보니깐 소리가 안나네요. 참고로 온도가 50도 이상이 되면 연속으로 온도와 습도가 출력되는 모습을 보실꺼에요. 그때 피에조부저도 같이 소리가 나온다고 생각하시면 될 듯 싶네요. 피에조부저가 울리는 명령문 안에 온도와 습도가 같이 출력되도록 하는 명령이 들어 있으니깐요. 그걸 감안하시고 연속으로 온도와 습도가 나오는 이미지 위치가 피에조부저가 같이 경고음을 울린다고 상상하시면 되겠습니다. 단점은 50이상인 경우는 연속적으로 온도가 출력되지만 50 이상이였다가 50이하로 떨어지면 2초후에나 결과를 확인할 수 있습니다. 스위치 버턴을 눌러서 바로 결과를 확인할 수 있지만 2초간의 딜레이 시간이 주어지기 때문에 이부분은 또다른 if문 락을 걸어서 50이상였다가 이하로 떨어지는 순간에 if문 락이 걸린 문장이 수행되어 현재온도를 출력되게 수정하면 됩니다. 이부분은 코딩하지 않았습니다. 숙제로 한번 이문제를 해결해 보세요.


5. 온도계에 LCD16x2 연결


1) 회로도



//LiquidCrystal(rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(3, 4, 8, 9, 10, 11);

핀이름을 잘보시고 해당 핀을 연결하시면 됩니다. 어려우시다면 위 링크된 사전학습 자료에 가셔서 사전학습을 하고 오세요.


선 연결이 좀 복잡하실꺼에요. 그래서 위에서 부터 나눠서 회로도를 순차적으로 만들었네요.

3) 코딩


LCD16x2 모니터 출력하기 위해서는

#include <LiquidCrystal.h>

//LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(3, 4, 8, 9, 10, 11);

데이터 4개의 핀으로 해서 글자를 출력합니다.

void setup(){
  lcd.begin(16,2); //가로x세로
  lcd.setCursor(0, 0); //시작위치 첫번째줄의 0번째칸 위치에서 시작
  lcd.print("Hello World"); //시작위치에서 글자를 순서대로 출력
  delay(1000); 
  lcd.clear(); //출력된 값을 지움
}   

위 주석을 잘 확인하시면 됩니다.

 void output(){
   lcd.clear(); //LCD16x2에 값을 지우기
   lcd.setCursor(0, 0); //첫번째줄의 0번째 칸 위치
   lcd.print("C : "); //문자열 출력
   lcd.setCursor(6, 0); // 첫번째 줄 6번째 칸 위치
   lcd.print(C);  //C(온도값) 출력
   lcd.setCursor(0, 1); //두번째줄의 0번재 칸 위치
   lcd.print("F : "); //문자열 출력
   lcd.setCursor(6, 1); //두번째줄의 6번째 칸 위치
   lcd.print(F);  
 }

사용자 정의 output() 함수는 위에서는 Serial 모니터에 출력했다면 이제는 LCD16x2에 출력되어야 하기 때문에 Serial 대신에 lcd로만 변경해주시면 됩니다 lcd은 젤 처음 LCD16x2 객체변수로 선언한 네임입니다. 주석으로 다 달아놓았으니깐 간단히 읽어보시면 됩니다.

lcd.setCursor(칸, 줄) : 줄, 칸의 위치를 가리킴
lcd.print(값) : 줄, 칸의 위치에 값을 출력

이 두개의 함수만 알면 쉽게 LCD16x2에 값을 출력할 수 있습니다.

4) 종합소스


#include <LiquidCrystal.h>

//LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(3, 4, 8, 9, 10, 11);

const int switchPin = 2;
const int piezoPin = 12;
unsigned long timeVal=0;
float V=0;
float C=0;
float F=0;

void setup() {
  pinMode(switchPin, INPUT_PULLUP);

  lcd.begin(16,2);
  lcd.setCursor(0, 0);
  lcd.print("Hello World");
  delay(1000);
  lcd.clear();
}

void loop() { 
  V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산
  //float V = analogRead(A0)*5.0/1023;

  C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
  F = C*9.0/5.0+32; //화씨 F = C*1.8+32;
    
  if(digitalRead(switchPin)== LOW){
    output();
    timeVal=millis();
    delay(500);
  }
  if(millis()-timeVal>=2000){
    output();  
    timeVal=millis();
  }
  if(C>50){
    output();
    tone(piezoPin,523,1000/8);     // 도음으로 8분음표(음길이)
    delay(1000/4*1.30);             
    noTone(12);
    timeVal=millis();
  }
}  
 void output(){
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("C : ");
   lcd.setCursor(6, 0);
   lcd.print(C);  
   lcd.setCursor(0, 1);
   lcd.print("F : ");
   lcd.setCursor(6, 1);
   lcd.print(F);  
  }

float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}

5) 결과


이 결과도 움짤로 하려다가 소리도 들리는 결과물이 있어야 할 것 같아서 그냥 동영상으로 결과물을 만들었네요.


마무리


세 파트로 나눠서 설명을 했네요. 한번에 전부 다 합쳐진 상태로 설명을 하면 좀 코딩을 어려워 할 수 있고 회로도도 너무 복잡해 보일 수 있기 때문에 나눠서 설명했습니다. 결과적으로 post가 좀 길어졌네요. 설명도 사전학습내용은 다 뺄려고 했는데 빼면은 설명이 안되는 부분이 있어서 어쩔 수 없이 복습차원으로 추가했네요.

아무튼 @uuu95님이 실험하시는 주제에 대해 가상시뮬레이터로 재미있게 실험을 하셨습니다. 참고로 세파트로 나누어진 회로도는 공개회로도에 다 있으니깐 가셔서 한번 가상시뮬레이터를 직접 돌려보시고 어떻게 동작하는지 살펴보셨으면 합니다.


댓글()