CO2 센서(MHZ-14A)와 기온 기압 습도 센서(BME280)의 측정값을 Arduino로 취득하여 이더넷을 통해 라즈파이로 기록

제목 길어서 죄송합니다

계기



 나 「Arduino를 모처럼 샀으므로 센서류를 Arduino에 옮겨 보자」
※이전 라즈파이에 센서류를 달고 놀고 있었습니다
Raspberry Pi에서 CO2 센서 모듈 (MH-Z14A)을 사용하여 실내 CO2 농도 측정
 
 나 「Arduino를 이더넷에 연결하는 모듈이 적당히 구르고 있었으므로 사용해 보자」
 나「멀리 떨어진 곳에서 센서의 값을 취득할 수 있어」

준비한 것



・라즈파이(Raspberry Pi3 B+)
・Arduino Uno
· Arduino 용 이더넷 모듈
・CO2 농도 센서(MHZ-14A)
・기온 기압 습도 센서(BME280)
・풀업용 저항 1 kΩ
· 점퍼 와이어 (수컷 - 수컷)
・브레드보드

이더넷 모듈은 이런 느낌


마이크로 SD를 꽂아 다양한 수있는 것 같지만 다시
뒤에는 MAC 주소가 인쇄된 씰이 붙여져 있다

절차



연결



Arduino에 이더넷 모듈 연결

CO2 센서(MHZ-14A)



이번에도 마지막으로 UART 방식으로 연결
아래 그림과 같이 연결



덧붙여서 배선은 이런 느낌


할당
배색


전원(5V)
레드

GND
블랙

UART(RXD)
블루

UART(TXD)
노랑


기온 기압 습도 센서 (BME280)



이 기사와 마찬가지로 연결
온도·습도·기압 센서(BME280)의 값을 Arduino로 취득

Arduino 스케치



AdvancedChatServer.ino
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <SoftwareSerial.h>

#define BME280_ADDRESS 0x76
SoftwareSerial SerialCom (2,3);
int myDelay = 5000;
byte addArray[] = { 0XFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79 };
byte addcalib[] = { 0XFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78 };
char dataValue[9];
String dataString = "";


unsigned long int hum_raw,temp_raw,pres_raw;
signed long int t_fine;

uint16_t dig_T1;
 int16_t dig_T2;
 int16_t dig_T3;
uint16_t dig_P1;
 int16_t dig_P2;
 int16_t dig_P3;
 int16_t dig_P4;
 int16_t dig_P5;
 int16_t dig_P6;
 int16_t dig_P7;
 int16_t dig_P8;
 int16_t dig_P9;
 int8_t  dig_H1;
 int16_t dig_H2;
 int8_t  dig_H3;
 int16_t dig_H4;
 int16_t dig_H5;
 int8_t  dig_H6;

byte mac[] = {
0x90, 0xA2, 0x0D, 0xD2, 0xDD}; //イーサネットシールドに記載されているMACアドレスを指定する

IPAddress ip( 192,168,0,50); //Arduinoサーバーに割り当てるIPアドレスを指定する

EthernetServer server(80); 

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
SerialCom.begin(9600);
uint8_t osrs_t = 1;             //Temperature oversampling x 1
uint8_t osrs_p = 1;             //Pressure oversampling x 1
uint8_t osrs_h = 1;             //Humidity oversampling x 1
uint8_t mode = 3;               //Normal mode
uint8_t t_sb = 5;               //Tstandby 1000ms
uint8_t filter = 0;             //Filter off 
uint8_t spi3w_en = 0;           //3-wire SPI Disable

uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
uint8_t config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en;
uint8_t ctrl_hum_reg  = osrs_h;

Wire.begin();

writeReg(0xF2,ctrl_hum_reg);
    writeReg(0xF4,ctrl_meas_reg);
    writeReg(0xF5,config_reg);
    readTrim();                    //


//addcalib
SerialCom.write(addcalib, 9);
delay(30);


while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Ethernet.begin(mac, ip); 
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
EthernetClient client = server.available(); 
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 30"); // refresh the page automatically every 5 sec
client.println();
client.println();
client.println();
// output the value of each analog input pin

double temp_act = 0.0, press_act = 0.0,hum_act=0.0;
signed long int temp_cal;
unsigned long int press_cal,hum_cal;


for (int analogChannel = 0; analogChannel < 1; analogChannel++) {

readData();
SerialCom.write(addArray, 9);
SerialCom.readBytes(dataValue, 9);
int resHigh = (int) dataValue[2];
int resLow  = (int) dataValue[3];
int pulse = (256*resHigh)+resLow;
dataString = String(pulse);




temp_cal = calibration_T(temp_raw);
press_cal = calibration_P(pres_raw);
hum_cal = calibration_H(hum_raw);
temp_act = (double)temp_cal / 100.0;
press_act = (double)press_cal / 100.0;
hum_act = (double)hum_cal / 1024.0;
//client.print("TEMP : ");
client.print(temp_act);
client.print(" ");
//client.print(" DegC  PRESS : ");
client.print(press_act);
client.print(" ");
//client.print(" hPa  HUM : ");
client.print(hum_act);
client.print(" ");
client.print(pulse);
//client.println(" %");
//delay(30000);

//int sensorReading = analogRead(analogChannel);
//client.print("analog input ");
//client.print(analogChannel);
//client.print(" is ");
//client.print(sensorReading);
//client.println();
}
client.println();
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(30);
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}

void readTrim()
{
    uint8_t data[32],i=0;                      // Fix 2014/04/06
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0x88);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,24);       // Fix 2014/04/06
    while(Wire.available()){
        data[i] = Wire.read();
        i++;
    }

    Wire.beginTransmission(BME280_ADDRESS);    // Add 2014/04/06
    Wire.write(0xA1);                          // Add 2014/04/06
    Wire.endTransmission();                    // Add 2014/04/06
    Wire.requestFrom(BME280_ADDRESS,1);        // Add 2014/04/06
    data[i] = Wire.read();                     // Add 2014/04/06
    i++;                                       // Add 2014/04/06

    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xE1);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,7);        // Fix 2014/04/06
    while(Wire.available()){
        data[i] = Wire.read();
        i++;    
    }
    dig_T1 = (data[1] << 8) | data[0];
    dig_T2 = (data[3] << 8) | data[2];
    dig_T3 = (data[5] << 8) | data[4];
    dig_P1 = (data[7] << 8) | data[6];
    dig_P2 = (data[9] << 8) | data[8];
    dig_P3 = (data[11]<< 8) | data[10];
    dig_P4 = (data[13]<< 8) | data[12];
    dig_P5 = (data[15]<< 8) | data[14];
    dig_P6 = (data[17]<< 8) | data[16];
    dig_P7 = (data[19]<< 8) | data[18];
    dig_P8 = (data[21]<< 8) | data[20];
    dig_P9 = (data[23]<< 8) | data[22];
    dig_H1 = data[24];
    dig_H2 = (data[26]<< 8) | data[25];
    dig_H3 = data[27];
    dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
    dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F); // Fix 2014/04/06
    dig_H6 = data[31];                                   // Fix 2014/04/06
}
void writeReg(uint8_t reg_address, uint8_t data)
{
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(reg_address);
    Wire.write(data);
    Wire.endTransmission();    
}

void readData()
{
    int i = 0;
    uint32_t data[8];
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xF7);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,8);
    while(Wire.available()){
        data[i] = Wire.read();
        i++;
    }
    pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
    temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
    hum_raw  = (data[6] << 8) | data[7];
}


signed long int calibration_T(signed long int adc_T)
{

    signed long int var1, var2, T;
    var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;

    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;
    return T; 
}

unsigned long int calibration_P(signed long int adc_P)
{
    signed long int var1, var2;
    unsigned long int P;
    var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
    var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
    var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
    var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
    var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
    var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
    if (var1 == 0)
    {
        return 0;
    }    
    P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
    if(P<0x80000000)
    {
       P = (P << 1) / ((unsigned long int) var1);   
    }
    else
    {
        P = (P / (unsigned long int)var1) * 2;    
    }
    var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
    var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
    P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
    return P;
}

unsigned long int calibration_H(signed long int adc_H)
{
    signed long int v_x1;

    v_x1 = (t_fine - ((signed long int)76800));
    v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) + 
              ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) * 
              (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) * 
              ((signed long int) dig_H2) + 8192) >> 14));
   v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
   v_x1 = (v_x1 < 0 ? 0 : v_x1);
   v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
   return (unsigned long int)(v_x1 >> 12);   
}

이 예에서는 Arduino의 IP를 192.168.0.50로 고정
스케치가 끝나면 Arduino의 마이크로 컴퓨터에 쓴 후 측정하려는 곳 근처의 콘센트에서 USB 전원 공급

라즈파이 측에서 데이터 취득



파이썬에서 다음과 같은 코드 작성

read.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
from datetime import datetime

r = requests.get('http://192.168.0.50')


day =datetime.now().strftime('%Y %m %d %H %M') 
dayname =datetime.now().strftime('%Y%m%d') 
data = r.content.decode().splitlines()

with open( "/home/pi/ethernet/" + dayname + ".dat", "a") as f:
    f.write(day + ' ' + data[2] + '\n')

print(data[2])
192.168.0.50 에서 데이터를 검색하고 파일에 저장하는 느낌

데이터를 검색해 보았습니다.



cron을 사용하여 5 분마다 파이썬 스크립트를 실행하여 데이터를 검색했습니다.

20200115.dat
        ・
        ・
        ・
#年  月  日 時 分  温度   気圧    湿度   CO2濃度
2020 01 15 21 35 24.12 1003.41 28.25 1193
2020 01 15 21 40 24.13 1003.41 28.58 1270
2020 01 15 21 45 24.09 1003.41 28.50 1576
2020 01 15 21 50 24.06 1003.49 28.30 1627

일단 제대로 측정되는 것 같습니다.
돈이 있다면 WiFi 또는 Bluetooth 모듈을 원합니다.

참고로 한 사이트



· 이더넷 스케치가 실려 있던 사이트
htps : //에서 ゔぃせ pぅs. jp / 호 by / 엔 try_006 /
· 스위치 과학의 스케치
htp://t 등 c. 슈 tch-s 시엔세. 코 m / 우키 / B 280

유용한 정보 감사합니다.

좋은 웹페이지 즐겨찾기