You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用WiringPi库在树莓派3上通过C++实现3路MCP3008的SPI通信?

嘿,我之前刚好解决过一模一样的问题——用WiringPi在C++里同时控制3个MCP3008来读取24路模拟输入!这就把我踩过坑后总结的方案分享给你,亲测好用~

核心思路

MCP3008是SPI设备,它的片选(CE/CS)引脚是关键:每个MCP3008需要独立的CE引脚,而SPI的MISO、MOSI、SCLK三个引脚是所有设备共用的。我们只需要给每个MCP3008分配一个GPIO引脚作为CE,手动控制引脚高低电平来选中对应的设备,就能实现多设备的SPI通信了。

一、硬件连接

  • 所有3个MCP3008的MISO引脚都接到树莓派的MISO引脚(WiringPi引脚12,对应物理引脚21)
  • 所有3个MCP3008的MOSI引脚都接到树莓派的MOSI引脚(WiringPi引脚11,对应物理引脚19)
  • 所有3个MCP3008的SCLK引脚都接到树莓派的SCLK引脚(WiringPi引脚14,对应物理引脚23)
  • 给每个MCP3008分配独立的CE引脚:比如选WiringPi的0、2、3引脚(对应物理引脚11、13、15),分别连接到三个MCP3008的CE引脚
  • 别忘了给每个MCP3008接3.3V电源和GND,MCP3008不支持5V供电哦!

二、代码实现步骤

1. 初始化WiringPi与SPI

先在代码里完成基础初始化,把CE引脚设为输出模式:

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

#define SPI_CHANNEL 0  // 固定用SPI0通道,我们手动控制CE,通道仅用于初始化SPI
#define CE_MCP1 0      // 第一个MCP3008的CE引脚
#define CE_MCP2 2      // 第二个MCP3008的CE引脚
#define CE_MCP3 3      // 第三个MCP3008的CE引脚

int main() {
    // 初始化WiringPi
    if (wiringPiSetup() == -1) {
        printf("WiringPi初始化失败!\n");
        return 1;
    }

    // 初始化SPI,速度设为1MHz(MCP3008最高支持3.6MHz,按需调整)
    if (wiringPiSPISetup(SPI_CHANNEL, 1000000) == -1) {
        printf("SPI初始化失败!\n");
        return 1;
    }

    // 配置CE引脚为输出,初始高电平(未选中设备)
    pinMode(CE_MCP1, OUTPUT);
    digitalWrite(CE_MCP1, HIGH);
    pinMode(CE_MCP2, OUTPUT);
    digitalWrite(CE_MCP2, HIGH);
    pinMode(CE_MCP3, OUTPUT);
    digitalWrite(CE_MCP3, HIGH);

    // 后续读取逻辑...
    return 0;
}

2. 编写通用读取函数

写一个复用的函数,传入CE引脚和通道号,就能返回对应MCP3008的通道值:

// 读取指定MCP3008的指定通道ADC值
int readMCP3008(int cePin, int channel) {
    if (channel < 0 || channel > 7) {
        return -1;  // 通道号范围是0-7,非法值返回-1
    }

    // SPI传输的数据包:符合MCP3008的通信协议
    unsigned char data[3] = {
        0x01,                      // 起始位
        (0x08 + channel) << 4,     // 单端模式 + 通道号编码
        0x00                       // 占位字节,用于接收返回数据
    };

    // 选中目标MCP3008:拉低CE引脚
    digitalWrite(cePin, LOW);
    // 发送指令并读取返回数据
    wiringPiSPIDataRW(SPI_CHANNEL, data, 3);
    // 取消选中:拉高CE引脚,避免干扰其他设备
    digitalWrite(cePin, HIGH);

    // 计算最终ADC值:返回数据的低10位
    int adcValue = ((data[1] & 0x03) << 8) + data[2];
    return adcValue;
}

3. 读取所有24路通道

现在就可以循环读取三个MCP3008的所有通道了:

int main() {
    // 前面的初始化代码...

    while (1) {
        // 读取第一个MCP3008的8个通道
        printf("=== MCP3008 #1 ===\n");
        for (int ch = 0; ch < 8; ch++) {
            int val = readMCP3008(CE_MCP1, ch);
            printf("通道%d: %d\n", ch, val);
        }

        // 读取第二个MCP3008的8个通道
        printf("\n=== MCP3008 #2 ===\n");
        for (int ch = 0; ch < 8; ch++) {
            int val = readMCP3008(CE_MCP2, ch);
            printf("通道%d: %d\n", ch, val);
        }

        // 读取第三个MCP3008的8个通道
        printf("\n=== MCP3008 #3 ===\n");
        for (int ch = 0; ch < 8; ch++) {
            int val = readMCP3008(CE_MCP3, ch);
            printf("通道%d: %d\n", ch, val);
        }

        printf("\n------------------------\n");
        delay(1000);  // 每秒刷新一次数据
    }

    return 0;
}

三、注意事项

  • 先确保树莓派的SPI功能已启用:可以通过raspi-config的「Interface Options」里开启SPI
  • CE引脚的电平控制必须严格:选中时拉低,读取完成立刻拉高,防止多个设备同时响应SPI信号
  • SPI速度不要超过MCP3008的额定最大值3.6MHz,否则会出现读取错误
  • 编译时需要链接WiringPi库:编译命令示例:g++ your_code.cpp -o adc_reader -lwiringPi

内容的提问来源于stack exchange,提问作者Juanea7

火山引擎 最新活动