본문 바로가기

.etc/Arduino

[211220] 아두이노 실습 (3) SSD 텍스트 출력

 

OLED SSD1306 연결

 

연결

아두이노 SSD1306
A5  SCL
A4  SDA
GND  GND
3.3V UCC

아두이노-장비 연결

 

아두이노 프로그램

스케치 > 라이브러리 관리 > 라이브러리 매니저 창에서 SSD1306 검색

 

2번째 것 설치

설치

 

 

파일 > 예제 > Adafruit SSD1306 > ssd1306_128-32_i2c 

 

업로드로 테스트 출력 후,

 

실습용으로는 텍스트 출력만 필요하므로 필요없는 메소드, 주석 정리한다.

 

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


int x = 0;


void setup() {
  Serial.begin(9600);
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();
  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);

}

void loop() {
  displayText();
  x++;
}

void displayText() {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(10,0);             // Start at top-left corner
  display.println(F("Hello, world!"));
  display.println(x);
  display.display(); //show initial text
  delay(2000);
}

 

testdrawstyles -> displayText로 메소드명 변경하였고 

테스트를 위해 전역변수 int x = 0; 선언 후 loop 돌려서 증가하는 숫자 함께 출력

 

실습(2) 온도 습도 결합하고 온/습도 출력문 만들기

(저항 잘 맞추기, 전구의 다리가 긴 쪽이 + 극)

 

온/습도 출력문

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

#define DHTPIN        2    // 보드에 연결된 출력핀 번호
#define DHTTYPE    DHT11    // 센서 종류
#define RED             4
#define BLE              7
#define GRN             8

DHT_Unified dht(DHTPIN, DHTTYPE);   // 핀번호와 센서 종류를 dht 함수에 전달

uint32_t delayMS;


//SSD1306 OLED
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


int x = 0;

void setup() {
  Serial.begin(9600);    // 시리얼 동작하여 시리얼 모니터에 출력하도록 함
  dht.begin();    // 센서 동작 시킴

  pinMode(RED, OUTPUT);
  pinMode(BLE, OUTPUT);
  pinMode(GRN, OUTPUT);
  
  sensor_t sensor;    // 센서 변수 생성
  dht.temperature().getSensor(&sensor);   // 생성한 센서 변수의 참조 주소 전달하여 온도 측정관련 셋팅값 저장할 수 있도록 함.
  delayMS = sensor.min_delay / 1000;    // 측정 딜레이 설정


  //SSD1306 OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();
  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);

}

void loop() {
  display.clearDisplay(); //디스플레이 텍스트 지움
  
  digitalWrite(GRN, HIGH);
  delay(delayMS / 8);    // 일정 시간동안 멈춤
  sensors_event_t event;    // 센서 이벤트 변수 생성
  dht.temperature().getEvent(&event);    // 생성한 센서 이벤트 변수 참조 주소 전달하여 이벤트 발생시의 측정값을 저장할 수 있도록 함
  if (isnan(event.temperature)) {    // non 인지 검사
    Serial.println(F("Error reading temperature!"));
  }
  else {
    Serial.print(F("Temperature: "));
    Serial.print(event.temperature);    // 측정된 온도 출력
    Serial.println(F("°C"));
    displayText("TMP:", event.temperature, 0);

    if(event.temperature >= 30.0) {
      digitalWrite(RED, HIGH);
    } else {
      digitalWrite(RED, LOW);
    }
  }
  
  dht.humidity().getEvent(&event);    // 생성한 센서 이벤트 변수 참조 주소 전달하여 이벤트 발생시의 측정값을 저장할 수 있도록 함
  if (isnan(event.relative_humidity)) {    // non 인지 검사
    Serial.println(F("Error reading humidity!"));
  }
  else {
    Serial.print(F("Humidity: "));
    Serial.print(event.relative_humidity);    // 측정된 습도 출력
    Serial.println(F("%"));
    displayText("Hum":", event.relative_humidity, 15);

    if(event.relative_humidity >= 50.0) {
      digitalWrite(BLE, HIGH);
    } else {
      digitalWrite(BLE, LOW);
    }
  }
  digitalWrite(GRN, LOW);
  delay(delayMS / 8);

  display.display();//디스플레이에 출력
}

//SSD1306 OLED
void displayText(String s, double val, int y) {
  //display.clearDisplay(); 온도나오고 클리어하고 습도나오고 클리어하고 이렇게 될 거기 때문에 모아서 한번만 하게
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,y);             // Start at top-left corner
  display.print(s);
  display.print(var);
  //display.display(); //show initial text 반드시 작성해야 디스플레이에 텍스트 뜬다. 모아서 한번에
  delay(2000);
}

 

 

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

디스플레이가 이 크기인 모듈을 쓰면

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

이걸 사용해라 

 

 


 

아두이노 이더넷 쉴드 

 

스케치 새로 만들기 > 예제 > Ethernet > DhcpAddressPrinter

 

 

아두이노 장비 위에 이더넷 장비 끼운 후에 인터넷 선까지 연결하기 (나는 거실 공유기 선을 연결했다.)

연결 마치고 DhcpAddressPrinter 업로드 후, 시리얼 모니터 켜면 ip 주소 볼 수 있다. (홈 네트워크)

 

용도에 맞게 DhcpAddressPrinter 수정, 정리, 구문추가

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02
};

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
  //Ethernet.init(10);  // Most Arduino shields
  //Ethernet.init(5);   // MKR ETH shield
  //Ethernet.init(0);   // Teensy 2.0
  //Ethernet.init(20);  // Teensy++ 2.0
  //Ethernet.init(15);  // ESP8266 with Adafruit Featherwing Ethernet
  //Ethernet.init(33);  // ESP32 with Adafruit Featherwing Ethernet

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("DHCP 연결 구성을 시작합니다.");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("DHCP 구성에 실패하였습니다.");
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("이더넷 쉴드 장치를 찾지 못하였습니다.");
    } else if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("이더넷 케이블이 연결되어 있지 않습니다.");
    }
    // no point in carrying on, so do nothing forevermore:
    while (true) {
      delay(1);
    }
  }
  // print your local IP address:
  Serial.print("아이피 주소:");Serial.println(Ethernet.localIP());
  Serial.print("서브넷 마스크:");Serial.println(Ethernet.subnetMask());
  Serial.print("게이트 웨이:");Serial.println(Ethernet.gatewayIP());
  Serial.print("DNS 서버:");Serial.println(Ethernet.dnsServerIP());
  Serial.println("DHCP 연결 구성이 완료되었습니다.");
}

void loop() {
  newIPAddress();
  delay(1000 * 60); //1분에 1번씩 요청
}

//DHCP 임대 갱신하기(다시 주소받기)
void newIPAddress(){
  switch (Ethernet.maintain()) {
    case 1:
      Serial.println("Error: 갱신 실패");
      break;

    case 2:
      Serial.println("갱신 성공");
      Serial.print("아이피 주소: ");
      Serial.println(Ethernet.localIP());
      break;

    case 3:
      Serial.println("Error: 리바인드 실패");
      break;

    case 4:
      Serial.println("리바인드 성공");
      Serial.print("아이피 주소: ");
      Serial.println(Ethernet.localIP());
      break;
  }
}

 

 

온/습도,전구 합쳐봤는데 전구는 작동 안 하는 내 코드...

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02
};


//온습도, OLED 연결
#define DHTPIN        2    // 보드에 연결된 출력핀 번호
#define DHTTYPE    DHT11    // 센서 종류
#define RED             4
#define BLE              7
#define GRN             8

DHT_Unified dht(DHTPIN, DHTTYPE);   // 핀번호와 센서 종류를 dht 함수에 전달

uint32_t delayMS;


//SSD1306 OLED
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int x = 0;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  Serial.println("DHCP 연결 구성을 시작합니다.");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("DHCP 구성에 실패하였습니다.");
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("이더넷 쉴드 장치를 찾지 못하였습니다.");
    } else if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("이더넷 케이블이 연결되어 있지 않습니다.");
    }
    // no point in carrying on, so do nothing forevermore:
    while (true) {
      delay(1);
    }
  }
  // print your local IP address:
  Serial.print("아이피 주소:");Serial.println(Ethernet.localIP());
  Serial.print("서브넷 마스크:");Serial.println(Ethernet.subnetMask());
  Serial.print("게이트 웨이:");Serial.println(Ethernet.gatewayIP());
  Serial.print("DNS 서버:");Serial.println(Ethernet.dnsServerIP());
  Serial.println("DHCP 연결 구성이 완료되었습니다.");

  //온습도, OLED
  dht.begin();    // 센서 동작 시킴

  pinMode(RED, OUTPUT);
  pinMode(BLE, OUTPUT);
  pinMode(GRN, OUTPUT);
  
  sensor_t sensor;    // 센서 변수 생성
  dht.temperature().getSensor(&sensor);   // 생성한 센서 변수의 참조 주소 전달하여 온도 측정관련 셋팅값 저장할 수 있도록 함.
  delayMS = sensor.min_delay / 1000;    // 측정 딜레이 설정


  //SSD1306 OLED
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();
  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);

}

void loop() {
  newIPAddress();
  delay(1000 * 60); //1분에 1번씩 요청
}

//DHCP 임대 갱신하기(다시 주소받기)
void newIPAddress(){
  switch (Ethernet.maintain()) {
    case 1:
      Serial.println("Error: 갱신 실패");
      break;

    case 2:
      Serial.println("갱신 성공");
      Serial.print("아이피 주소: ");
      Serial.println(Ethernet.localIP());
      break;

    case 3:
      Serial.println("Error: 리바인드 실패");
      break;

    case 4:
      Serial.println("리바인드 성공");
      Serial.print("아이피 주소: ");
      Serial.println(Ethernet.localIP());
      break;
  }

  //온습도, OLED
  display.clearDisplay(); //디스플레이 텍스트 지움
  
  digitalWrite(GRN, HIGH);
  delay(delayMS / 8);    // 일정 시간동안 멈춤
  sensors_event_t event;    // 센서 이벤트 변수 생성
  dht.temperature().getEvent(&event);    // 생성한 센서 이벤트 변수 참조 주소 전달하여 이벤트 발생시의 측정값을 저장할 수 있도록 함
  if (isnan(event.temperature)) {    // non 인지 검사
    Serial.println(F("Error reading temperature!"));
  }
  else {
    Serial.print(F("Temperature: "));
    Serial.print(event.temperature);    // 측정된 온도 출력
    Serial.println(F("°C"));
    displayText("TMP:", event.temperature, 0);

    if(event.temperature >= 30.0) {
      digitalWrite(RED, HIGH);
    } else {
      digitalWrite(RED, LOW);
    }
  }
  
  dht.humidity().getEvent(&event);    // 생성한 센서 이벤트 변수 참조 주소 전달하여 이벤트 발생시의 측정값을 저장할 수 있도록 함
  if (isnan(event.relative_humidity)) {    // non 인지 검사
    Serial.println(F("Error reading humidity!"));
  }
  else {
    Serial.print(F("Humidity: "));
    Serial.print(event.relative_humidity);    // 측정된 습도 출력
    Serial.println(F("%"));
    displayText("Hum:", event.relative_humidity, 15);

    if(event.relative_humidity >= 50.0) {
      digitalWrite(BLE, HIGH);
    } else {
      digitalWrite(BLE, LOW);
    }
  }
  digitalWrite(GRN, LOW);
  delay(delayMS / 8);

  display.display();//디스플레이에 출력
}

//온습도 OLED
void displayText(String s, double val, int y) {
  //display.clearDisplay(); 온도나오고 클리어하고 습도나오고 클리어하고 이렇게 될 거기 때문에 모아서 한번만 하게
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,y);             // Start at top-left corner
  display.print(s);
  display.print(val);
  //display.display(); //show initial text 반드시 작성해야 디스플레이에 텍스트 뜬다. 모아서 한번에
  delay(2000);
}

 

아주 잘 작동하는 선생님 코드

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//#include <EthernetUdp.h>
//#include <Time.h>

#define DHTPIN 2
#define DHTTYPE DHT11
#define RED 4
#define BLE 7
#define GRN 8
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET 4
#define SCREEN_ADDRESS 0x3C

DHT_Unified dht(DHTPIN, DHTTYPE);
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
EthernetUDP Udp;
unsigned int localPort = 8888;
const char timeServer[] = "time.nist.gov";
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];
struct tm timeinfo;
int min_delay = 1000;
sensors_event_t event;
int cnt = 1;

void setup() {
  pinMode(RED, OUTPUT);
  pinMode(BLE, OUTPUT);
  pinMode(GRN, OUTPUT);
  
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);
  }
  display.display(); delay(min_delay * 2);
  initDisplay();
  
  dht.begin();
  
  while(!startEthernet()) {
    delay(min_delay * 3); // 3초 간격으로 재시도.
  }

  clsDisplay();
  display.println(F("Success..."));
  infoEthernet();

//  Serial.begin(9600);
//  
//  Udp.begin(localPort);
//  sendNTPpacket(timeServer);
//  
}

void loop() {
  getTempHum();
  delay(min_delay / 5);

  if(cnt % 50 == 0) { // 10초마다?
    infoEthernet();
    cnt = 1;
  }
  cnt++;
  
  // newIpAddress();
  // delay(min_delay * 60);
}

bool startEthernet() {
  clsDisplay();
  display.print(F("DHCP Connection..."));
  display.display(); delay(1000);
  if (Ethernet.begin(mac) == 0) {
    clsDisplay();
    display.println("DHCP Config Fail");
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      display.print(F("    Ethernet Device Not Found!!"));
    } else if (Ethernet.linkStatus() == LinkOFF) {
      display.print(F("    Cable Disconnect!!"));
    }
    display.display(); delay(1000);
  } else {
    return true;
  }
  return false;
}

void infoEthernet() {
  clsDisplay();
  display.print(F("IP:"));  display.println(Ethernet.localIP());
  display.print(F("Subnet:")); display.println(Ethernet.subnetMask());
  display.print(F("GW:")); display.println(Ethernet.gatewayIP());
  display.print(F("DNS:")); display.println(Ethernet.dnsServerIP());
  display.display(); delay(min_delay * 2);
}

// DHCP 임대 갱신하기.(다시 주소 받기)
void newIpAddress() {
  switch (Ethernet.maintain()) {
    case 1:
      display.println(F("Error: renew fail"));
      return;

    case 2:
      display.println(F("renew success"));
      break;

    case 3:
      Serial.println(F("Error: rebind fail"));
      return;

    case 4:
      display.println(F("rebind success"));
      break;
  }
  infoEthernet();
}

void initDisplay() {
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
}

void clsDisplay() {
  display.clearDisplay(); display.setCursor(0, 0);
}


void getTempHum() {
  clsDisplay();
  digitalWrite(GRN, HIGH);
  dht.temperature().getEvent(&event);
  if (isnan(event.temperature)) {
    display.println(F("Error reading temperature!"));
  }
  else {
    display.print(F("Tmp:"));
    display.println(event.temperature);
    if(event.temperature >= 30.0) {
      digitalWrite(RED, HIGH);
    } else {
      digitalWrite(RED, LOW);
    }
  }
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    display.println(F("Error reading humidity!"));
  }
  else {
    display.print(F("Hum:"));
    display.println(event.relative_humidity);
    if(event.relative_humidity >= 50.0) {
      digitalWrite(BLE, HIGH);
    } else {
      digitalWrite(BLE, LOW);
    }
  }
  delay(min_delay / 5); digitalWrite(GRN, LOW);
  display.display();
}

void sendNTPpacket(const char * address) {
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  packetBuffer[0] = 0b11100011;
  packetBuffer[1] = 0;
  packetBuffer[2] = 6;
  packetBuffer[3] = 0xEC;
  
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  Udp.beginPacket(address, 123);
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();

  delay(1000);
  if (Udp.parsePacket()) {
    Udp.read(packetBuffer, NTP_PACKET_SIZE);

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    const unsigned long seventyYears = 2208988800UL;
    unsigned long epoch = secsSince1900 - seventyYears;
    
    Serial.print(epoch);
  }
}