Controlar ventilador con arduino

Hola a todos!

Estoy tratando de controlar un ventilador con el arduino usando el siguiente esquema:

Los +12 los tomo de la salida del arduino VIN ya que lo alimento a 12V. El ventilador va a 12V 0.35A.

El código es el siguiente:

int fan = 11;
int fanSpeed = 0; // for incoming serial data
int fanSpedMap = 0;
int analogvalue;
void setup() {
  Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
  pinMode(fan, OUTPUT);
}

//  Entradas serial: 1 = 49  2 = 50  3 = 51 ...

void loop() {
  // send data only when you receive data:
  if (Serial.available() > 0) { // read the incoming byte:
    fanSpeed = Serial.read(); // say what you got:
    Serial.print("I received: ");
    if (fanSpeed == 48) {
      fanSpeed = 0;
    } else if (fanSpeed == 49) {
      fanSpeed = 1;
    } else if (fanSpeed == 50) {
      fanSpeed = 2;
    } else if (fanSpeed == 51) {
      fanSpeed = 3;
    } else if (fanSpeed == 52) {
      fanSpeed = 4;
    } else if (fanSpeed == 53) {
      fanSpeed = 5;
    } else if (fanSpeed == 54) {
      fanSpeed = 6;
    } else if (fanSpeed == 55) {
      fanSpeed = 7;
    } else if (fanSpeed == 56) {
      fanSpeed = 8;
    } else if (fanSpeed == 57) {
      fanSpeed = 9;
    }
    Serial.println(fanSpeed, DEC);
    analogvalue = analogRead(fan);
    Serial.println(analogvalue, DEC);
  }
  fanSpedMap = map(fanSpeed, 0, 9, 0, 255);
  analogWrite(fan, fanSpedMap);
}

El resultado de esto es
0
I received: 0
371
0.0 Voltios
Ventilador parado
1
I received: 1
371
0.74 Voltios
Ventilador parado
2
I received: 2
381
8.8 Voltios
Ventilador en movimiento despacio
3
I received: 3
378
10.44 - 10.60
Ventilador en movimiento algo mas rapido
4
I received: 4
379
11.10 Voltios
Ventilador en movimiento aun mas rapido
5
I received: 5
378
11.34 voltios
Ventilador en movimiento aun mas rapido? No lo aprecio...
6
I received: 6
378
11.50 Voltios
Igual que antes
7
I received: 7
377
10.56 Voltios
Ventilador muy rapido (ya se le escucha..)
8
I received: 8
379
10.75 Voltios
Aun mas rapido
9
I received: 9
377
10.88
A tope ya.

Entonces segun veo el programa funciona pero no entiendo porque la lectura de analogvalue es casi la misma ni tampoco la escala de valores la hace bien. De 1 a 0.7 voltios pasamos a 2 a 8.8 voltios. No me parece muy lineal.

El control imagino que es por corriente y por eso los valores van aumentando y en los valores máximos el voltaje cae porque el arduino no es capad de dar el máximo.

Como veis ando un poco liado. El programa funciona pero no lo acabo de entender del todo el funcionamiento.

Un saludo

Para empezar no se porque pusiste un capacitor de 100uF en la base del transitor?
Si controlas con PWM controlas con PWM, no con su valor medio, promediado con el capacitor.
Saca el capacitor.
Tu control es de a 25 pasos por cada numero de velocidad digitado.
No olvides eso.
usa un Serial.parseint() y envia directamente la velocidad de 0 a 255.
con fanSpeed definida como int.

fanSpeed = Serial.paseInt(); // say what you got:

olvida el map y directamente

analogWrite(fan, fanSpeed);

Hola sur byte.

Ocurre que si elimino el condensador el control es más lineal pero se escucha un ruido constante en el ventilador. He pensado en poner uno menor quizás que se descargue antes. Serviría?

Por otro lado la función serialparseint no la conocía pero me ha eliminado mucho código absurdo.

Aquí no te entiendo: Tu control es de a 25 pasos por cada numero de velocidad digitado.
No olvides eso.

Gracias por todo y un saludo.

Hola oOVitoOo

Sigo con curiosidad este hilo y, como nadie lo dice, lo diré yo.
¿ Por qué haces esto en tu código ?

    Serial.println(fanSpeed, DEC);
    analogvalue = analogRead(fan);
    Serial.println(analogvalue, DEC);

si al comienzo ya declaras:

void setup() {
  Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
  pinMode(fan, OUTPUT);
}

Si estás declarando el pin como OUTPUT ¿ que sentido tiene leerlo ?
Y aunque leyeses algo coherente ¿ como averiguar su valor cuando la señal en ese pin es una señal PWM con frecuencias entre 450 y 1000 Hz ?

Por otro lado yo apostaria por un pequeño integrador como el que pones, pero usando un condensador con valor de 10uF, 4,7uF, o 2,2uF para evitar el ruido del motor que probablemente sea debido a que los impulsos que recibe son de una frecuencia mas elevada de lo que su respuesta mecanica admite.

Por último, si usas un solo digito para la regulación de la velocidad, y teniendo en cuenta que el rango es de 0 a 255, verás que 255/10 = 25, tal y como te indicaba surbyte

Hola Alfaville,

Jejeje lo de analogvalue = analogRead(fan); lo hago simplemente por ver que dato envía finalmente el pin. Yo también lo encuentro un sinsentido pero pensé... si le mando un 100 y leo un 370... si mando un 150 leeré 390?

Simplemente a modo de control y entender que esta pasando. Está claro que me falta teoría... estamos en ello.

Vale! Ahora entiendo lo de los 25 pasos. Gracias.
Realmente del ventilador no necesito tanto control con encendido, medio y máximo me sirve. Si más adelante lo necesitara creo que me decantaría por la función MAP que me parece que el la idónea para parametrizar el comportamiento.

Supongo que con el condensador de 100uF la curva que describe es muy pronunciada y por eso me altera tanto los valores de como el tiempo de respuesta.

Probaré con los condensadores que me indicas a ver si encuentro un compromiso entre linealidad - ruido.

Gracias por tu aportación.

oOVitoOo:
Jejeje lo de analogvalue = analogRead(fan); lo hago simplemente por ver que dato envía finalmente el pin. Yo también lo encuentro un sinsentido pero pensé... si le mando un 100 y leo un 370... si mando un 150 leeré 390?

Simplemente a modo de control y entender que esta pasando. Está claro que me falta teoría... estamos en ello.

El problema es que la señal que pretendes leer cambia constantemente (es PWM) y no vas a sacar nada en claro (como parece que te pasa). Recuerda que es de SALIDA y estás intentando leerla sobre el mismo pin (si es OUTPUT, no puede ser INPUT simultaneamente).
Usa otro pin (A0-A5) y conectalo como INPUT a la base del transistor, quizas así obtengas algún resultado

Ocurre que si elimino el condensador el control es más lineal pero se escucha un ruido constante en el ventilador

Tal vez debas cambiar la frecuencia de la portadora PWM.
Veamos.. pin 11 esta con el TIMER2 en el UNO de modo que esa es la frecuencia a cambiar.
Esta rutina te ayudará

/**
 * Divides a given PWM pin frequency by a divisor.
 * 
 * The resulting frequency is equal to the base frequency divided by
 * the given divisor:
 *   - Base frequencies:
 *      o The base frequency for pins 3, 9, 10, and 11 is 31250 Hz.
 *      o The base frequency for pins 5 and 6 is 62500 Hz.
 *   - Divisors:
 *      o The divisors available on pins 5, 6, 9 and 10 are: 1, 8, 64,
 *        256, and 1024.
 *      o The divisors available on pins 3 and 11 are: 1, 8, 32, 64,
 *        128, 256, and 1024.
 * 
 * PWM frequencies are tied together in pairs of pins. If one in a
 * pair is changed, the other is also changed to match:
 *   - Pins 5 and 6 are paired on timer0
 *   - Pins 9 and 10 are paired on timer1
 *   - Pins 3 and 11 are paired on timer2
 * 
 * Note that this function will have side effects on anything else
 * that uses timers:
 *   - Changes on pins 3, 5, 6, or 11 may cause the delay() and
 *     millis() functions to stop working. Other timing-related
 *     functions may also be affected.
 *   - Changes on pins 9 or 10 will cause the Servo library to function
 *     incorrectly.
 * 
 * Thanks to macegr of the Arduino forums for his documentation of the
 * PWM frequency divisors. His post can be viewed at:
 *   http://forum.arduino.cc/index.php?topic=16612#msg121031
 */
void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x07; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}

y la usas asi

// Set pin 11's PWM frequency to 3906 Hz (31250/8 = 3906)
// Note that the base frequency for pins 3, 9, 10, and 11 is 31250 Hz
setPwmFrequency(11, 8); // obtienes 3906 hz a la salida

También esta el otro método.

Fast PWM Mode with OCRA top
The following code fragment sets up fast PWM on pins 3 and 11 (Timer 2), using OCR2A as the top value for the timer. The waveform generation mode bits WGM are set to to 111 for fast PWM with OCRA controlling the top limit. The OCR2A top limit is arbitrarily set to 180, and the OCR2B compare register is arbitrarily set to 50. OCR2A's mode is set to "Toggle on Compare Match" by setting the COM2A bits to 01.

Traducción : El siguiente fragmento de código fija PWM rápido, en los pines 3 y 11, usando OCR2A como valor superior para el timer. Los bits WGM para la generación de la forma de onda son fijados a 111 para fast PWM con OCRA controlando el limite superior. El límite superior OCR2A es fijado arbitrariamente a 180, y el OCR2B registro de comparación está fijado tmb arbitrariamente a 50. El modo OCR2A esta fijado a "Toggle on COmpara Match" poniendo los bits COM2A en 01.

  pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;

Output A frequency: 16 MHz / 64 / (180+1) / 2 = 690.6Hz
Output A duty cycle: 50%
Output B frequency: 16 MHz / 64 / (180+1) = 1381.2Hz
Output B duty cycle: (50+1) / (180+1) = 28.2%
Note that in this example, the timer goes from 0 to 180, which takes 181 clock cycles, so the output frequency is divided by 181. Output A has half the frequency of Output B because the Toggle on Compare Match mode toggles Output A once each complete timer cycle.

fuente : enlace Secrets of Arduino PWM

Increíble... ahora funciona perfecto.

Eres un crack.

Muchísimas gracias por la ayuda y las fuentes. Poco a poco aprendiendo :slight_smile: