Nota

¡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 [Aquí] y únete hoy mismo.

2.1.4 Potenciómetro (MCP3008)

Nota

_images/mcp3008_and_adc0834.jpg

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.

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

_images/MCP3008.jpg

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.

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

_images/image310.png

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

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

_images/schematic_2.1.7_potentiometer_mcp3008.png

Procedimientos experimentales

Paso 1: Construye el circuito.

_images/july24_2.1.7_potentiometer_mcp3008.png

Nota

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.

cd ~/davinci-kit-for-raspberry-pi/c/2.1.4-2/

Paso 3: Compila el código.

gcc 2.1.4_Potentiometer.c -lwiringPi

Paso 4: Ejecuta.

sudo ./a.out

Cuando el código se ejecute, al girar la perilla del potenciómetro, la intensidad del LED cambiará en consecuencia.

Nota

Si no funciona después de ejecutar o aparece el error «wiringPi.h: No such file or directory», consulta Instalar y Comprobar WiringPi.

Código

#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#include <softPwm.h>

#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

  1. Se definen las constantes para el canal SPI (CE0), la velocidad (1 MHz) y el pin del LED (GPIO3).

#define SPI_CHANNEL 0  // CE0
#define SPI_SPEED   1000000  // 1MHz
#define LedPin      3
  1. 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.

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;
}
  1. 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.

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 Configuración de SPI para instrucciones detalladas). Si ya lo hiciste, puedes omitir este paso.

Paso 3: Abre el archivo de código.

cd ~/davinci-kit-for-raspberry-pi/python

Paso 4: Ejecuta.

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.

Advertencia

Si aparece el error RuntimeError: Cannot determine SOC peripheral base address, consulta Si gpiozero no funciona..

Código

#!/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

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

    #!/usr/bin/env python3
    
    import spidev
    import time
    import RPi.GPIO as GPIO
    
  2. Se configura el pin GPIO22 para salida PWM. Se establece la comunicación SPI en el bus 0, CE0, a 1 MHz.

    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
    
  3. read_adc lee datos analógicos del MCP3008 (canales 0–7) y devuelve un valor entero de 0 a 1023.

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

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

    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()