.. note:: こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 愛好家コミュニティ(Facebook)へようこそ! Raspberry Pi、Arduino、ESP32 を仲間とともに深く学び、楽しみましょう。 **参加する理由** - **専門的なサポート**: 購入後の問題や技術的な課題を、コミュニティとチームがサポートします。 - **学びと共有**: ヒントや作例を共有してスキルを高めます。 - **限定先行情報**: 新製品発表やプレビューをいち早く入手できます。 - **特別割引**: 最新製品の限定割引を受けられます。 - **季節イベントと景品**: プレゼント企画や季節イベントに参加できます。 👉 ものづくりの世界を一緒に探検しませんか?[|link_sf_facebook|] をクリックして今すぐ参加! .. _3.1.8_c_pi5_mcp3008: 3.1.8 過熱モニター(MCP3008) =========================== .. note:: .. image:: ../img/mcp3008_and_adc0834.jpg :width: 25% :align: left 使用しているキットによって、 **ADC0834** または **MCP3008** のどちらを使っているかを確認し、該当する説明を進めてください。 はじめに -------- 工場などで回路の過熱を検知し、警報や自動停止を行う監視装置を作りたい場合があります。 このプロジェクトでは、サーミスタ、ジョイスティック、ブザー、LED、LCD を使い、しきい値を調整できる温度監視装置を作ります。 必要な部品 ---------- このプロジェクトで使用する部品は以下の通りです。 .. image:: ../img/list2_Overheat_Monitor.png :align: center 回路図 ------ ============ ======== ======== === 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 ============ ======== ======== === .. image:: ../img/Schematic_three_one8.png :align: center 実験手順 -------- **手順1:** 回路を組み立てます。 .. image:: ../img/july24_3.1.8_overheat_monitor_mcp3008.png **手順2:** コードのあるフォルダへ移動します。 .. code-block:: cd ~/davinci-kit-for-raspberry-pi/c/3.1.8-2/ **手順3:** コードをコンパイルします。 .. code-block:: gcc 3.1.8_OverheatMonitor.c -lm -lwiringPi **手順4:** 実行します。 .. code-block:: sudo ./a.out 実行すると、現在の温度と高温しきい値 **40** が **I2C LCD1602** に表示されます。 現在温度がしきい値を超えると、ブザーと LED が作動して警告します。 **ジョイスティック** はしきい値の調整に使用します。X軸またはY軸方向に倒すと、しきい値を上げ下げできます。 ジョイスティックを押すとしきい値を初期値にリセットします。 .. note:: * 「wiringPi.h: No such file or directory」というエラーが出た場合は、:ref:`install_wiringpi` を参照してください。 * 「Unable to open I2C device: No such file or directory」というエラーが出た場合は、:ref:`i2c_config` を参照し、I2C を有効にして配線を確認してください。 * コードと配線が正しいのに LCD が表示しない場合は、背面のボリュームを回してコントラストを調整してください。 コード ------ .. code-block:: c #include #include #include #include #include #include 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; } コード解説 ---------- .. code-block:: c 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 の整数で返します。 .. code-block:: c 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)の値を読み取り、しきい値判定に基づき方向を数値で返します。 .. code-block:: c 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); } ジョイスティックで高温しきい値を調整します。方向を押し続けた場合の連続変更を防ぐ制御を行います。 .. code-block:: c 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 の式を用いて摂氏温度に変換します。 .. code-block:: c 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 を作動させます。 .. code-block:: c 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 の初期化を行い、ジョイスティックボタンにプルアップ設定をします。 .. code-block:: c 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: しきい値調整