如何用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




