.. note:: ¡Hola! Bienvenido a la Comunidad de Entusiastas de SunFounder Raspberry Pi & Arduino & ESP32 en Facebook. Profundiza en Raspberry Pi, Arduino y ESP32 junto con otros entusiastas. **¿Por qué unirse?** - **Soporte experto**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo. - **Aprender y compartir**: Intercambia consejos y tutoriales para mejorar tus habilidades. - **Vistas previas exclusivas**: Obtén acceso anticipado a nuevos anuncios de productos y adelantos. - **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes. - **Promociones y sorteos festivos**: Participa en sorteos y promociones de temporada. 👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo. .. _2.1.4_c_mcp3008: 2.1.4 Potenciómetro (MCP3008) ============================= .. note:: .. image:: img/mcp3008_and_adc0834.jpg :width: 25% :align: left Dependiendo de la versión de tu kit, identifica si tienes **ADC0834** o **MCP3008** y procede con la sección correspondiente. Introducción ------------ La función ADC se utiliza para convertir señales analógicas en valores digitales. En este experimento, usamos el chip ADC MCP3008 para realizar esta conversión. Un potenciómetro se utiliza para generar un voltaje variable, que cambia la magnitud física. El MCP3008 convierte este voltaje analógico en un valor digital que puede ser leído y procesado por la Raspberry Pi. Componentes necesarios ---------------------- En este proyecto, necesitamos los siguientes componentes. .. image:: img/list2_2.1.4_potentiometer.png Principio --------- **MCP3008** MCP3008 es un convertidor analógico-digital (ADC) de aproximaciones sucesivas de 10 bits con 8 canales de entrada y un protocolo de comunicación SPI (Serial Peripheral Interface). Puede comunicarse con un microcontrolador para convertir señales analógicas en datos digitales para su posterior procesamiento. .. image:: img/MCP3008.jpg :width: 40% **Secuencia de funcionamiento** Una conversión en el MCP3008 comienza poniendo el pin CS (chip select) en bajo, lo que activa la comunicación con el dispositivo. El microcontrolador envía entonces un flujo de control de 3 bytes a través de la interfaz SPI para especificar la configuración y seleccionar el canal de entrada. El primer byte enviado contiene el bit de inicio y el bit de selección simple/diferencial. Los siguientes bits indican cuál de los 8 canales (CH0–CH7) se va a leer. Los datos se introducen en el dispositivo en cada flanco ascendente del reloj SPI (SCLK) y el resultado de la conversión se devuelve simultáneamente. Se incluye un breve retardo interno para que el canal de entrada seleccionado se estabilice antes de que comience la conversión. Luego, el MCP3008 realiza una conversión ADC de 10 bits utilizando un circuito de muestreo y retención y un comparador SAR. El resultado de la conversión se transmite de nuevo al microcontrolador a través de la línea MISO (Master In Slave Out). El bit más significativo (MSB) del resultado de 10 bits se envía primero, seguido por los bits restantes. El microcontrolador lee el resultado por el bus SPI durante este tiempo. Después de que se desplaza el valor digital completo de 10 bits, el MCP3008 completa el ciclo y espera el siguiente comando. * `Hoja de datos de la serie MCP3008 `_ .. image:: img/MCP3008detail.png **Potenciómetro** El potenciómetro es también un componente resistivo con 3 terminales y su valor de resistencia puede ajustarse según una variación regulada. Generalmente consiste en una resistencia y un cursor móvil. Cuando el cursor se desplaza a lo largo de la resistencia, se obtiene una cierta resistencia o voltaje de salida dependiendo del desplazamiento. .. image:: img/image310.png :width: 300 :align: center Las funciones del potenciómetro en el circuito son las siguientes: 1. Servir como divisor de voltaje Un potenciómetro es una resistencia ajustable de forma continua. Cuando ajustas el eje o el deslizador, el contacto móvil se desplazará sobre la resistencia. En ese momento, se puede obtener un voltaje de salida que depende del voltaje aplicado al potenciómetro y del ángulo o distancia recorrida por el brazo móvil. Diagrama esquemático -------------------- .. list-table:: :widths: 30 30 30 30 :header-rows: 1 * - Nombre T-Board - Físico - WiringPi - BCM * - SPICE0 - pin24 - 10 - 8 * - SPIMOSI - pin19 - 12 - 10 * - SPIMISO - pin21 - 13 - 9 * - SPISCLK - pin23 - 14 - 11 * - GPIO22 - pin15 - 3 - 22 .. image:: img/schematic_2.1.7_potentiometer_mcp3008.png Procedimientos experimentales ----------------------------- **Paso 1:** Construye el circuito. .. image:: img/july24_2.1.7_potentiometer_mcp3008.png .. note:: Coloca el chip según la posición mostrada en la imagen. Ten en cuenta que las muescas del chip deben quedar a la izquierda al colocarlo. Para usuarios de lenguaje C ^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Paso 2:** Abre el archivo de código. .. code-block:: cd ~/davinci-kit-for-raspberry-pi/c/2.1.4-2/ **Paso 3:** Compila el código. .. code-block:: gcc 2.1.4_Potentiometer.c -lwiringPi **Paso 4:** Ejecuta. .. code-block:: sudo ./a.out Cuando el código se ejecute, al girar la perilla del potenciómetro, la intensidad del LED cambiará en consecuencia. .. note:: Si no funciona después de ejecutar o aparece el error "wiringPi.h: No such file or directory", consulta :ref:`install_wiringpi`. **Código** .. code-block:: c #include #include #include #include #define SPI_CHANNEL 0 // CE0 #define SPI_SPEED 1000000 // 1MHz #define LedPin 3 int readADC(int channel) { if (channel < 0 || channel > 7) return -1; unsigned char buffer[3]; buffer[0] = 1; // Bit de inicio buffer[1] = (8 + channel) << 4; // Modo de un solo extremo, canal buffer[2] = 0; wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3); int value = ((buffer[1] & 3) << 8) | buffer[2]; return value; } int main(void) { if (wiringPiSetup() == -1) { printf("¡Fallo en la inicialización de WiringPi!\n"); return 1; } if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) { printf("¡Fallo en la configuración SPI!\n"); return 1; } softPwmCreate(LedPin, 0, 100); while (1) { int analogVal = readADC(0); // CH0 printf("Valor ADC: %d\n", analogVal); int pwmVal = analogVal * 100 / 1023; // Normalizar a 0–100 softPwmWrite(LedPin, pwmVal); delay(100); } return 0; } Explicación del código ~~~~~~~~~~~~~~~~~~~~~~ #. Se definen las constantes para el canal SPI (CE0), la velocidad (1 MHz) y el pin del LED (GPIO3). .. code-block:: c #define SPI_CHANNEL 0 // CE0 #define SPI_SPEED 1000000 // 1MHz #define LedPin 3 #. La función ``readADC`` lee datos analógicos del MCP3008. Comprueba que el canal esté entre 0 y 7, configura los bytes de control, realiza la transferencia SPI y extrae el valor ADC de 10 bits. .. code-block:: c int readADC(int channel) { if (channel < 0 || channel > 7) return -1; unsigned char buffer[3]; buffer[0] = 1; // Start bit buffer[1] = (8 + channel) << 4; // Single-ended mode, channel buffer[2] = 0; wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3); int value = ((buffer[1] & 3) << 8) | buffer[2]; return value; } #. En la función ``main``: * ``wiringPiSetup()`` inicializa la biblioteca WiringPi. * ``wiringPiSPISetup()`` configura la comunicación SPI en el canal 0 a 1 MHz. * ``softPwmCreate()`` configura el PWM por software en GPIO3. Luego entra en un bucle infinito que: * Lee el valor del canal 0. * Lo imprime. * Lo convierte a un ciclo de trabajo PWM entre 0 y 100. * Ajusta el brillo del LED según la posición del potenciómetro. .. code-block:: c int main(void) { if (wiringPiSetup() == -1) { printf("WiringPi init failed!\n"); return 1; } if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) { printf("SPI setup failed!\n"); return 1; } softPwmCreate(LedPin, 0, 100); while (1) { int analogVal = readADC(0); // CH0 printf("ADC Value: %d\n", analogVal); int pwmVal = analogVal * 100 / 1023; // Normalize to 0–100 softPwmWrite(LedPin, pwmVal); delay(100); } return 0; } Para usuarios de Python ^^^^^^^^^^^^^^^^^^^^^^^ **Paso 2:** Configura la interfaz SPI e instala la librería ``spidev`` (consulta :ref:`spi_configuration` para instrucciones detalladas). Si ya lo hiciste, puedes omitir este paso. **Paso 3:** Abre el archivo de código. .. code-block:: cd ~/davinci-kit-for-raspberry-pi/python **Paso 4:** Ejecuta. .. code-block:: sudo python3 2.1.4-2_Potentiometer.py Al ejecutar el código, al girar la perilla del potenciómetro, la intensidad del LED cambiará en consecuencia. .. warning:: Si aparece el error ``RuntimeError: Cannot determine SOC peripheral base address``, consulta :ref:`faq_soc`. **Código** .. code-block:: python #!/usr/bin/env python3 import spidev import time import RPi.GPIO as GPIO PWM_PIN = 22 GPIO.setmode(GPIO.BCM) GPIO.setup(PWM_PIN, GPIO.OUT) pwm = GPIO.PWM(PWM_PIN, 1000) pwm.start(0) spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000 def read_adc(channel): if channel < 0 or channel > 7: return -1 adc = spi.xfer2([1, (8 + channel) << 4, 0]) value = ((adc[1] & 3) << 8) | adc[2] return value def MAP(x, in_min, in_max, out_min, out_max): return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min try: while True: res = read_adc(0) print('res = %d' % res) duty_cycle = MAP(res, 0, 1023, 0, 100) pwm.ChangeDutyCycle(duty_cycle) time.sleep(0.2) except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close() Explicación del código ~~~~~~~~~~~~~~~~~~~~~~ #. ``RPi.GPIO`` se utiliza para generar señales PWM que controlan un LED. ``spidev`` maneja la comunicación SPI con el MCP3008. ``time`` se usa para las pausas. .. code-block:: python #!/usr/bin/env python3 import spidev import time import RPi.GPIO as GPIO #. Se configura el pin GPIO22 para salida PWM. Se establece la comunicación SPI en el bus 0, CE0, a 1 MHz. .. code-block:: python PWM_PIN = 22 GPIO.setmode(GPIO.BCM) GPIO.setup(PWM_PIN, GPIO.OUT) pwm = GPIO.PWM(PWM_PIN, 1000) # 1kHz frequency pwm.start(0) # Start with 0% duty cycle spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000 #. ``read_adc`` lee datos analógicos del MCP3008 (canales 0–7) y devuelve un valor entero de 0 a 1023. .. code-block:: python def read_adc(channel): if channel < 0 or channel > 7: return -1 adc = spi.xfer2([1, (8 + channel) << 4, 0]) value = ((adc[1] & 3) << 8) | adc[2] return value #. ``MAP`` convierte un valor de un rango numérico a otro, usado aquí para escalar el valor ADC al ciclo de trabajo PWM (0–100). .. code-block:: python def MAP(x, in_min, in_max, out_min, out_max): return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min #. En el bucle principal: * Lee el canal 0. * Imprime el valor. * Lo mapea a un porcentaje PWM. * Ajusta el brillo del LED. El bucle se repite cada 0,2 segundos. Con Ctrl+C se detiene y limpia la configuración. .. code-block:: python try: while True: res = read_adc(0) print('res = %d' % res) duty_cycle = MAP(res, 0, 1023, 0, 100) pwm.ChangeDutyCycle(duty_cycle) time.sleep(0.2) except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close()