注釈

こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 愛好家コミュニティ(Facebook)へようこそ! Raspberry Pi、Arduino、ESP32 を仲間とともに深く学び、楽しみましょう。

参加する理由

  • 専門的なサポート: 購入後の問題や技術的な課題を、コミュニティとチームがサポートします。

  • 学びと共有: ヒントや作例を共有してスキルを高めます。

  • 限定先行情報: 新製品発表やプレビューをいち早く入手できます。

  • 特別割引: 最新製品の限定割引を受けられます。

  • 季節イベントと景品: プレゼント企画や季節イベントに参加できます。

👉 ものづくりの世界を一緒に探検しませんか?[ここ] をクリックして今すぐ参加!

3.1.8 過熱モニター(MCP3008)

注釈

../_images/mcp3008_and_adc0834.jpg

使用しているキットによって、 ADC0834 または MCP3008 のどちらを使っているかを確認し、該当する説明を進めてください。

はじめに

工場などで回路の過熱を検知し、警報や自動停止を行う監視装置を作りたい場合があります。 このプロジェクトでは、サーミスタ、ジョイスティック、ブザー、LED、LCD を使い、しきい値を調整できる温度監視装置を作ります。

必要な部品

このプロジェクトで使用する部品は以下の通りです。

../_images/list2_Overheat_Monitor.png

回路図

T-Board 名

物理ピン

wiringPi

BCM

SPICE0

Pin 24

10

8

SPIMOSI

Pin 19

12

10

SPIMISO

Pin 21

13

9

SPISCLK

Pin 23

14

11

GPIO22

Pin15

3

22

GPIO23

Pin16

4

23

GPIO24

Pin18

5

24

SDA1

Pin 3

SCL1

Pin 5

../_images/Schematic_three_one81.png

実験手順

手順1: 回路を組み立てます。

../_images/july24_3.1.8_overheat_monitor_mcp3008.png

手順2: コードのあるフォルダへ移動します。

cd ~/davinci-kit-for-raspberry-pi/c/3.1.8-2/

手順3: コードをコンパイルします。

gcc 3.1.8_OverheatMonitor.c -lm -lwiringPi

手順4: 実行します。

sudo ./a.out

実行すると、現在の温度と高温しきい値 40I2C LCD1602 に表示されます。 現在温度がしきい値を超えると、ブザーと LED が作動して警告します。

ジョイスティック はしきい値の調整に使用します。X軸またはY軸方向に倒すと、しきい値を上げ下げできます。 ジョイスティックを押すとしきい値を初期値にリセットします。

注釈

  • 「wiringPi.h: No such file or directory」というエラーが出た場合は、wiringPi のインストールと確認 を参照してください。

  • 「Unable to open I2C device: No such file or directory」というエラーが出た場合は、I²C 設定 を参照し、I2C を有効にして配線を確認してください。

  • コードと配線が正しいのに LCD が表示しない場合は、背面のボリュームを回してコントラストを調整してください。

コード

#include <wiringPi.h>
#include <stdio.h>
#include <wiringPiI2C.h>
#include <wiringPiSPI.h>
#include <string.h>
#include <math.h>

typedef unsigned char uchar;
typedef unsigned int  uint;

#define Joy_BtnPin 3      // GPIO22 -> WiringPi 3
#define buzzPin    4      // GPIO23 -> WiringPi 4
#define LedPin     5      // GPIO24 -> WiringPi 5
#define SPI_CHANNEL 0
#define SPI_SPEED   1000000

int LCDAddr    = 0x27;
int BLEN       = 1;
int fd;
int upperTem   = 40;

// Global variable to store the last joystick change
int lastJoystickChange = 0;

int read_ADC(int channel) {
    if (channel < 0 || channel > 7) return -1;
    unsigned char buffer[3];
    buffer[0] = 1;
    buffer[1] = (8 + channel) << 4;
    buffer[2] = 0;
    wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
    return ((buffer[1] & 0x03) << 8) | buffer[2];
}

void write_word(int data){
    int temp = data;
    if (BLEN)      temp |= 0x08;
    else           temp &= 0xF7;
    wiringPiI2CWrite(fd, temp);
}

void send_command(int comm){
    int buf = comm & 0xF0;
    buf |= 0x04; write_word(buf); delay(2); buf &= 0xFB; write_word(buf);
    buf = (comm & 0x0F) << 4;
    buf |= 0x04; write_word(buf); delay(2); buf &= 0xFB; write_word(buf);
}

void send_data(int data){
    int buf = data & 0xF0;
    buf |= 0x05; write_word(buf); delay(2); buf &= 0xFB; write_word(buf);
    buf = (data & 0x0F) << 4;
    buf |= 0x05; write_word(buf); delay(2); buf &= 0xFB; write_word(buf);
}

void lcd_init(){
    send_command(0x33); delay(5);
    send_command(0x32); delay(5);
    send_command(0x28); delay(5);
    send_command(0x0C); delay(5);
    send_command(0x01); wiringPiI2CWrite(fd, 0x08);
}

void lcd_clear(){
    send_command(0x01);
}

void write_lcd(int x, int y, const char data[]){
    int addr = 0x80 + 0x40 * y + x;
    send_command(addr);
    for (int i = 0; i < (int)strlen(data); i++)
        send_data(data[i]);
}

int get_joystick_value(){
    int x = read_ADC(1);
    int y = read_ADC(2);

    // Dead-band filtering to reduce small fluctuations
    if (x > 900)      return  1;   //     else if (x < 100) return -1;   //     else if (y > 900) return -10;  //    else if (y < 100) return  10;  //    else              return   0;
}

void upper_tem_setting(){
    write_lcd(0,0, "Upper Adjust:");

    int change = get_joystick_value();

    // Only respond to actual direction change
    if (change != 0 && change != lastJoystickChange) {
        upperTem += change;
        lastJoystickChange = change;
    }
    else if (change == 0) {
        // Allow next change after returning to center
        lastJoystickChange = 0;
    }

    // Display current upperTem
    char str[6];
    snprintf(str, sizeof(str), "%d", upperTem);
    write_lcd(0,1, str);
    // Clear remaining LCD characters
    write_lcd(strlen(str),1, "            ");

    delay(100);
}

double temperature(){
    int raw = read_ADC(0);
    double Vr = 3.3 * ((double)raw / 1023.0);
    double Rt = 10000.0 * Vr / (3.3 - Vr);
    double tempK = 1.0 / ((log(Rt/10000.0)/3950.0) + 1.0/(273.15+25.0));
    return tempK - 273.15;
}

void monitoring_temp(){
    char str[6];
    double cel = temperature();
    snprintf(str, sizeof(str), "%.2f", cel);
    write_lcd(0,0, "Temp: ");
    write_lcd(6,0, str);

    snprintf(str, sizeof(str), "%d", upperTem);
    write_lcd(0,1, "Upper: ");
    write_lcd(7,1, str);
    delay(100);

    if (cel >= upperTem) {
        digitalWrite(buzzPin, HIGH);
        digitalWrite(LedPin,  HIGH);
    } else {
        digitalWrite(buzzPin, LOW);
        digitalWrite(LedPin,  LOW);
    }
}

void setup_all(){
    fd = wiringPiI2CSetup(LCDAddr);
    lcd_init();
    if (wiringPiSetup() == -1 ||
        wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
        printf("Setup failed!\n");
        return;
    }
    pinMode(Joy_BtnPin, INPUT);
    pullUpDnControl(Joy_BtnPin, PUD_UP);
    pinMode(buzzPin, OUTPUT);
    pinMode(LedPin,  OUTPUT);
}

int main(void){
    setup_all();

    int lastBtnState = HIGH;
    int stage = 0;

    while (1) {
        int curBtn = digitalRead(Joy_BtnPin);
        // Switch mode when button changes from LOW to HIGH (button released)
        if (curBtn == HIGH && lastBtnState == LOW) {
            stage = (stage + 1) % 2;
            lastJoystickChange = 0;  // Clear debounce status
            delay(100);
            lcd_clear();
        }
        lastBtnState = curBtn;

        if (stage == 1)
            upper_tem_setting();
        else
            monitoring_temp();
    }

    return 0;
}

コード解説

int read_ADC(int channel) {
    if (channel < 0 || channel > 7) return -1;
    unsigned char buffer[3];
    buffer[0] = 1;
    buffer[1] = (8 + channel) << 4;
    buffer[2] = 0;
    wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
    return ((buffer[1] & 0x03) << 8) | buffer[2];
}

MCP3008 の指定チャンネル(CH0〜CH7)から SPI を使って 10ビットのアナログ値を読み取り、0〜1023 の整数で返します。

int get_joystick_value() {
    int x = read_ADC(1);
    int y = read_ADC(2);

    if (x > 900)      return 1;   // Right
    else if (x < 100) return -1;  // Left
    else if (y > 900) return -10; // Up
    else if (y < 100) return 10;  // Down
    else              return 0;
}

ジョイスティックの X 軸(CH1)と Y 軸(CH2)の値を読み取り、しきい値判定に基づき方向を数値で返します。

void upper_tem_setting() {
    write_lcd(0,0, "Upper Adjust:");

    int change = get_joystick_value();

    if (change != 0 && change != lastJoystickChange) {
        upperTem += change;
        lastJoystickChange = change;
    }
    else if (change == 0) {
        lastJoystickChange = 0;
    }

    char str[6];
    snprintf(str, sizeof(str), "%d", upperTem);
    write_lcd(0,1, str);
    write_lcd(strlen(str),1, "            ");

    delay(100);
}

ジョイスティックで高温しきい値を調整します。方向を押し続けた場合の連続変更を防ぐ制御を行います。

double temperature() {
    int raw = read_ADC(0);
    double Vr = 3.3 * ((double)raw / 1023.0);
    double Rt = 10000.0 * Vr / (3.3 - Vr);
    double tempK = 1.0 / ((log(Rt/10000.0)/3950.0) + 1.0/(273.15+25.0));
    return tempK - 273.15;
}

CH0 のサーミスタからアナログ値を読み取り、Steinhart–Hart の式を用いて摂氏温度に変換します。

void monitoring_temp() {
    char str[6];
    double cel = temperature();
    snprintf(str, sizeof(str), "%.2f", cel);
    write_lcd(0,0, "Temp: ");
    write_lcd(6,0, str);

    snprintf(str, sizeof(str), "%d", upperTem);
    write_lcd(0,1, "Upper: ");
    write_lcd(7,1, str);
    delay(100);

    if (cel >= upperTem) {
        digitalWrite(buzzPin, HIGH);
        digitalWrite(LedPin,  HIGH);
    } else {
        digitalWrite(buzzPin, LOW);
        digitalWrite(LedPin,  LOW);
    }
}

現在の温度と設定されたしきい値を LCD に表示し、温度がしきい値以上になるとブザーと LED を作動させます。

void setup_all() {
    fd = wiringPiI2CSetup(LCDAddr);
    lcd_init();
    if (wiringPiSetup() == -1 || wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
        printf("Setup failed!\n");
        return;
    }
    pinMode(Joy_BtnPin, INPUT);
    pullUpDnControl(Joy_BtnPin, PUD_UP);
    pinMode(buzzPin, OUTPUT);
    pinMode(LedPin,  OUTPUT);
}

LCD、SPI、GPIO の初期化を行い、ジョイスティックボタンにプルアップ設定をします。

int main(void) {
    setup_all();

    int lastBtnState = HIGH;
    int stage = 0;

    while (1) {
        int curBtn = digitalRead(Joy_BtnPin);
        if (curBtn == HIGH && lastBtnState == LOW) {
            stage = (stage + 1) % 2;
            lastJoystickChange = 0;
            delay(100);
            lcd_clear();
        }
        lastBtnState = curBtn;

        if (stage == 1)
            upper_tem_setting();
        else
            monitoring_temp();
    }

    return 0;
}
  • モード切替はジョイスティックボタンの押下・解放で行います。

  • モード0: 温度監視

  • モード1: しきい値調整