.. note::
Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.
**Why Join?**
- **Expert Support**: Solve post-sale issues and technical challenges with help from our community and team.
- **Learn & Share**: Exchange tips and tutorials to enhance your skills.
- **Exclusive Previews**: Get early access to new product announcements and sneak peeks.
- **Special Discounts**: Enjoy exclusive discounts on our newest products.
- **Festive Promotions and Giveaways**: Take part in giveaways and holiday promotions.
👉 Ready to explore and create with us? Click [|link_sf_facebook|] and join today!
.. _3.1.7_c_mcp3008:
3.1.7 Overheat Monitor(MCP3008)
==================================
.. note::
.. image:: ../img/mcp3008_and_adc0834.jpg
:width: 25%
:align: left
Depending on your kit version, please identify whether you have **ADC0834** or **MCP3008** and proceed with the matching section.
Introduction
-------------------
You may want to make an overheat monitoring device that applies to
various situations, ex., in the factory, if we want to have an alarm and
the timely automatic turning off of the machine when there is a circuit
overheating. In this project, we will use thermistor, joystick, buzzer,
LED and LCD to make an smart temperature monitoring device whose
threshold is adjustable.
Required Components
------------------------------
In this project, we need the following components.
.. image:: ../img/list2_Overheat_Monitor.png
:align: center
It's definitely convenient to buy a whole kit, here's the link:
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - Name
- ITEMS IN THIS KIT
- LINK
* - Raphael Kit
- 337
- |link_Raphael_kit|
You can also buy them separately from the links below.
.. list-table::
:widths: 30 20
:header-rows: 1
* - COMPONENT INTRODUCTION
- PURCHASE LINK
* - :ref:`cpn_gpio_board`
- |link_gpio_board_buy|
* - :ref:`cpn_breadboard`
- |link_breadboard_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_led`
- |link_led_buy|
* - :ref:`cpn_joystick`
- \-
* - :ref:`cpn_mcp3008`
- \-
* - :ref:`cpn_transistor`
- |link_transistor_buy|
* - :ref:`cpn_i2c_lcd`
- |link_i2clcd1602_buy|
* - :ref:`cpn_thermistor`
- |link_thermistor_buy|
* - :ref:`cpn_buzzer`
- \-
Schematic Diagram
--------------------------
============ ======== ======== ===
T-Board Name physical 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
Experimental Procedures
-----------------------------
**Step 1:** Build the circuit.
.. image:: ../img/july24_3.1.8_overheat_monitor_mcp3008.png
**Step 2**: Go to the folder of the code.
.. raw:: html
.. code-block::
cd ~/raphael-kit/c/3.1.7-2/
**Step 3**: Compile the code.
.. raw:: html
.. code-block::
gcc 3.1.7_OverheatMonitor.c -lm -lwiringPi
**Step 4**: Run the executable file.
.. raw:: html
.. code-block::
sudo ./a.out
As the code runs, the current temperature and the high-temperature
threshold **40** are displayed on **I2C LCD1602**. If the current
temperature is larger than the threshold, the buzzer and LED are started
to alarm you.
**Joystick** here is for your pressing to adjust the high-temperature
threshold. Toggling the **Joystick** in the direction of X-axis and
Y-axis can adjust (turn up or down) the current high-temperature
threshold. Press the **Joystick** once again to reset the threshold to
initial value.
.. note::
* If there is an error prompt ``wiringPi.h: No such file or directory``, please refer to :ref:`install_wiringpi`.
* If you get ``Unable to open I2C device: No such file or directory`` error, you need to refer to :ref:`i2c_config` to enable I2C and check if the wiring is correct.
* If the code and wiring are fine, but the LCD still does not display content, you can turn the potentiometer on the back to increase the contrast.
Code Explanation
----------------------
.. 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 Explanation
---------------------
.. 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];
}
Reads a 10-bit analog value from MCP3008 channel (CH0–CH7) using SPI and returns an integer from 0 to 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;
}
Reads joystick X and Y analog values from CH1 and CH2. Returns an integer indicating movement direction based on thresholds.
.. 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);
}
Allows user to adjust the upper temperature threshold using the joystick. Prevents repeated changes if direction is held.
.. 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;
}
Reads analog value from CH0 connected to the thermistor. Uses the Steinhart–Hart equation to calculate Celsius temperature.
.. 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);
}
}
Continuously reads the current temperature and displays it along with the threshold. If the temperature exceeds the threshold, the buzzer and LED are activated.
.. 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);
}
Initializes LCD, SPI, GPIO pins for joystick button, buzzer, and LED. Also sets pull-up for the joystick button.
.. 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;
}
Main loop switches between two modes:
1. Temperature monitoring.
2. Upper limit adjustment using the joystick.
The mode switches when the joystick button is released (rising edge trigger).
.. Phenomenon Picture
.. -------------------------
.. .. image:: ../img/image259.jpeg
:align: center