.. 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.