.. note::
Ciao, benvenuto nella Community SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts su Facebook! Approfondisci Raspberry Pi, Arduino ed ESP32 con altri appassionati.
**Perché unirsi?**
- **Supporto esperto**: Risolvi problemi post-vendita e sfide tecniche con l'aiuto della nostra community e del nostro team.
- **Impara e condividi**: Scambia suggerimenti e tutorial per migliorare le tue competenze.
- **Anteprime esclusive**: Accedi in anticipo agli annunci dei nuovi prodotti e alle anteprime.
- **Sconti speciali**: Goditi sconti esclusivi sui nostri prodotti più recenti.
- **Promozioni festive e giveaway**: Partecipa a giveaway e promozioni festive.
👉 Pronto a esplorare e creare con noi? Clicca [|link_sf_facebook|] e unisciti oggi stesso!
.. _3.1.4_c_pi5_mcp3008:
3.1.4 Ventilatore Intelligente (MCP3008)
==========================================
.. note::
.. image:: ../img/mcp3008_and_adc0834.jpg
:width: 25%
:align: left
A seconda della versione del tuo kit, identifica se hai **ADC0834** o **MCP3008** e procedi con la sezione corrispondente.
Introduzione
-----------------
In questo progetto utilizzeremo motori, pulsanti e termistori per realizzare un ventilatore intelligente manuale + automatico con velocità regolabile.
Componenti necessari
------------------------------
In questo progetto sono necessari i seguenti componenti.
.. image:: ../img/list2_Smart_Fan.png
:align: center
È sicuramente conveniente acquistare un kit completo, ecco il link:
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - Nome
- ELEMENTI IN QUESTO KIT
- LINK
* - Kit Raphael
- 337
- |link_Raphael_kit|
Puoi anche acquistarli separatamente dai link sottostanti.
.. list-table::
:widths: 30 20
:header-rows: 1
* - INTRODUZIONE COMPONENTE
- LINK DI ACQUISTO
* - :ref:`cpn_gpio_extension_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_power_module`
- \-
* - :ref:`cpn_thermistor`
- |link_thermistor_buy|
* - :ref:`cpn_l293d`
- \-
* - :ref:`cpn_mcp3008`
- \-
* - :ref:`cpn_button`
- |link_button_buy|
* - :ref:`cpn_motor`
- |link_motor_buy|
Schema elettrico
------------------------
============ ======== ======== ===
Nome T-Board fisico wiringPi BCM
SPICE0 Pin 24 10 8
SPIMOSI Pin 19 12 10
SPIMISO Pin 21 13 9
SPISCLK Pin 23 14 11
GPIO22 Pin 15 3 22
GPIO5 Pin 29 21 5
GPIO6 Pin 31 22 6
GPIO13 Pin 33 23 13
============ ======== ======== ===
.. image:: ../img/schematic_3.1.4_smart_fan_mcp3008.png
:align: center
Procedure sperimentali
-----------------------------
**Passo 1:** Monta il circuito.
.. image:: ../img/july24_3.1.4_smart_fan_mcp3008.png
:align: center
.. note::
Il modulo di alimentazione può utilizzare una batteria da 9V con il connettore per batteria 9V incluso nel kit. Inserisci il ponticello del modulo di alimentazione nel bus a 5V della breadboard.
.. image:: ../img/image118.jpeg
:align: center
**Passo 2**: Entra nella cartella del codice.
.. raw:: html
.. code-block::
cd ~/raphael-kit/c/3.1.4-2/
**Passo 3**: Compila.
.. raw:: html
.. code-block::
gcc 3.1.4_SmartFan.c -o SmartFan -lwiringPi -lm
**Passo 4**: Esegui il file eseguibile sopra.
.. raw:: html
.. code-block::
./SmartFan
Quando il codice è in esecuzione, avvia il ventilatore premendo il pulsante.
Ogni volta che premi, la velocità aumenta o diminuisce di 1 livello.
Sono disponibili **5** livelli di velocità: **0~4**.
Quando è impostata la 4\ :sup:`a` velocità e premi il pulsante, il ventilatore si ferma con velocità **0**.
Una volta che la temperatura sale o scende di oltre 2℃, la velocità viene automaticamente aumentata o diminuita di un livello.
.. note::
Se non funziona dopo l'esecuzione o compare un errore del tipo: \"wiringPi.h: No such file or directory\", fai riferimento a :ref:`install_wiringpi_pi5`.
Codice
--------
.. code-block:: c
#include
#include
#include
#include
#include
#define SPI_CHANNEL 0
#define SPI_SPEED 1000000
#define MotorPin1 21
#define MotorPin2 22
#define MotorEnable 23
#define BtnPin 3
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Bit di avvio
buffer[1] = (8 + channel) << 4; // Modalità single-ended e canale
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int result = ((buffer[1] & 3) << 8) | buffer[2];
return result;
}
int temperture()
{
int analogVal = read_ADC(0);
double Vr = 3.3 * analogVal / 1023.0; // Usa 3.3V come Vref per MCP3008
double Rt = 10000.0 * Vr / (3.3 - Vr);
double temp = 1 / (((log(Rt / 10000.0)) / 3950.0) + (1 / (273.15 + 25.0)));
double cel = temp - 273.15;
double Fah = cel * 1.8 + 32;
printf("Celsius: %.2f C Fahrenheit: %.2f F\n", cel, Fah);
return (int)cel;
}
int motor(int level)
{
if (level == 0) {
digitalWrite(MotorEnable, LOW);
return 0;
}
if (level >= 4) {
level = 4;
}
digitalWrite(MotorEnable, HIGH);
softPwmWrite(MotorPin1, level * 25);
return level;
}
void setup()
{
if (wiringPiSetup() == -1) {
printf("setup wiringPi fallito!\n");
return;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("setup SPI fallito!\n");
return;
}
softPwmCreate(MotorPin1, 0, 100);
softPwmCreate(MotorPin2, 0, 100);
pinMode(MotorEnable, OUTPUT);
pinMode(BtnPin, INPUT);
}
int main(void)
{
setup();
int currentState, lastState = 0;
int level = 0;
int currentTemp, markTemp = 0;
while (1) {
currentState = digitalRead(BtnPin);
currentTemp = temperture();
if (currentTemp <= 0) continue;
if (currentState == 1 && lastState == 0) {
level = (level + 1) % 5;
markTemp = currentTemp;
delay(500);
}
lastState = currentState;
if (level != 0) {
if (currentTemp - markTemp <= -2) {
level = level - 1;
markTemp = currentTemp;
}
if (currentTemp - markTemp >= 2) {
level = level + 1;
markTemp = currentTemp;
}
}
level = motor(level);
}
return 0;
}
Spiegazione del codice
----------------------
.. code-block:: c
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Bit di avvio
buffer[1] = (8 + channel) << 4; // Modalità single-ended e canale
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int result = ((buffer[1] & 3) << 8) | buffer[2];
return result;
}
Questa funzione legge l'ingresso analogico dal MCP3008 sul canale specificato.
Invia un comando SPI di 3 byte e restituisce un valore digitale a 10 bit compreso tra 0 e 1023.
.. code-block:: c
int temperture()
{
int analogVal = read_ADC(0);
double Vr = 3.3 * analogVal / 1023.0; // Usa 3.3V come Vref per MCP3008
double Rt = 10000.0 * Vr / (3.3 - Vr);
double temp = 1 / (((log(Rt / 10000.0)) / 3950.0) + (1 / (273.15 + 25.0)));
double cel = temp - 273.15;
double Fah = cel * 1.8 + 32;
printf("Celsius: %.2f C Fahrenheit: %.2f F\n", cel, Fah);
return (int)cel;
}
La funzione ``temperture()`` legge il segnale analogico del termistore tramite MCP3008, calcola tensione e resistenza, quindi converte in gradi Celsius e Fahrenheit utilizzando la formula del termistore (approssimazione Steinhart–Hart).
.. code-block:: c
int motor(int level)
{
if (level == 0) {
digitalWrite(MotorEnable, LOW);
return 0;
}
if (level >= 4) {
level = 4;
}
digitalWrite(MotorEnable, HIGH);
softPwmWrite(MotorPin1, level * 25);
return level;
}
La funzione ``motor()`` controlla la velocità del ventilatore tramite PWM.
Il livello varia da 0 a 4, dove 0 spegne il ventilatore e ciascun livello aumenta il duty cycle del 25%.
.. code-block:: c
void setup()
{
if (wiringPiSetup() == -1) {
printf("setup wiringPi fallito!\n");
return;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("setup SPI fallito!\n");
return;
}
softPwmCreate(MotorPin1, 0, 100);
softPwmCreate(MotorPin2, 0, 100);
pinMode(MotorEnable, OUTPUT);
pinMode(BtnPin, INPUT);
}
La funzione ``setup()`` inizializza WiringPi, configura SPI, imposta PWM e i pin GPIO necessari per il controllo del motore e la lettura del pulsante.
.. code-block:: c
int main(void)
{
setup();
int currentState, lastState = 0;
int level = 0;
int currentTemp, markTemp = 0;
while (1) {
currentState = digitalRead(BtnPin);
currentTemp = temperture();
if (currentTemp <= 0) continue;
if (currentState == 1 && lastState == 0) {
level = (level + 1) % 5;
markTemp = currentTemp;
delay(500);
}
lastState = currentState;
if (level != 0) {
if (currentTemp - markTemp <= -2) {
level = level - 1;
markTemp = currentTemp;
}
if (currentTemp - markTemp >= 2) {
level = level + 1;
markTemp = currentTemp;
}
}
level = motor(level);
}
return 0;
}
La funzione ``main()`` contiene il ciclo del programma:
1. Controlla continuamente lo stato del pulsante e legge la temperatura corrente.
2. Alla pressione del pulsante, il livello della ventola aumenta (cicli 0–4) e salva la temperatura.
3. Se la temperatura varia di ±2°C, la velocità della ventola viene regolata automaticamente.
4. Chiama ``motor(level)`` per aggiornare l'uscita PWM in base al livello corrente.