MCP23S17 Arduino库
一个全面的Arduino库 MCP23S17 Microchip的16位SPI I/O扩展器。
✨ 特性
- 🎯 Arduino型API -pinMode、数字写入、数字读取
- ⚡ 中断支持 -完整的中断配置和处理
- 🔌 电阻 -每个引脚均可配置
- 📦 港口业务 -同时控制8个引脚
- 🔢 16位GPIO -一次读取/写入所有16个引脚
- 🔗 多芯片 -每个CS引脚最多8个MCP23S17
- 🎛️ 灵活的SPI -三种初始化方法
- 🚀 ESP32优化 -针对ESP32进行了测试和优化
- 📝 证据充分的 -大量评论和示例
📋 目录
🔧 硬件要求
- Arduino兼容板(推荐ESP32)
- MCP23S17 SPI I/O扩展器
- SPI连接(至少4线)
测试平台
- ✅ ESP32
- ✅ Arduino Uno
- ✅ Arduino Mega
- ✅ Arduino Nano
📥 安装
方法1:Arduino库管理器(推荐)
- 打开Arduino IDE
- 首选
Sketch→Include Library→Manage Libraries... - 搜索“MCP23S17”
- 点击“安装”
方法2:手动安装
- 以ZIP格式下载最新版本
- 在Arduino IDE中:
Sketch→Include Library→Add .ZIP Library... - 选择下载的ZIP文件
- 重新启动Arduino IDE
方法3:Git克隆
cd ~/Arduino/libraries
git clone https://github.com/yourusername/MCP23S17.git🔌 布线
标准ESP32至MCP23S17
| ESP32引脚 | MCP23S17引脚 | 功能 |
|---|---|---|
| GPIO 18 | SCK(12) | SPI时钟 |
| GPIO 23 | (13) | SPI MoSi |
| GPIO 19 | SO(14) | SPI味噌 |
| GPIO 5 | CS(11) | 芯片选择 |
| 3.3V | VDD(9) | 电源 |
| 3.3V | 复位(18) | 复位(高) |
| GND | VSS(10) | 接地 |
硬件寻址(A0、A1、A2)
连接引脚A0、A1、A2(引脚15、16、17)以设置芯片地址:
| A2 | A1 | A0 | 地址 |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 |
| 0 | 1 | 0 | 2 |
| 0 | 1 | 1 | 3 |
| 1 | 0 | 0 | 4 |
| 1 | 0 | 1 | 5 |
| 1 | 1 | 0 | 6 |
| 1 | 1 | 1 | 7 |
对于地址0:将所有三个连接到GND。
可选中断引脚
- 国际商标协会 (引脚20):中断A
- INTB (引脚19):中断B
连接ESP32 GPIO进行中断处理。
🚀 快速开始
#include
#define CS_PIN 5
MCP23S17 mcp(CS_PIN, 0); // CS pin 5, address 0
void setup() {
Serial.begin(115200);
if (!mcp.begin()) {
Serial.println("MCP23S17 not found!");
while(1);
}
mcp.pinMode(0, MCP23S17_OUTPUT); // Pin 0 as output
}
void loop() {
mcp.digitalWrite(0, HIGH);
delay(1000);
mcp.digitalWrite(0, LOW);
delay(1000);
}🎛️ SPI初始化方法
图书馆提供 三种灵活的方式 初始化MCP23S17:
方法1:标准SPI引脚(最简单)
使用电路板的默认SPI引脚。
MCP23S17 mcp(CS_PIN, 0);
void setup() {
mcp.begin(); // Uses default pins
}ESP32默认引脚(VSPI):
- SCK=GPIO 18
- MISO = GPIO 19
- MOSI=GPIO 23
______________________________________________________________________
方法2:定制SPI引脚(柔性)
指定自己的SPI引脚。
MCP23S17 mcp(CS_PIN, 0);
void setup() {
mcp.begin(14, 12, 13); // SCK=14, MISO=12, MOSI=13
}在以下情况下使用:
- 默认引脚已在使用中
- 特殊PCB布线要求
- 需要不同的引脚布局
______________________________________________________________________
方法3:现有SPI总线(最强大)
与多个设备共享SPI总线。
SPIClass mySPI(HSPI);
MCP23S17 mcp(CS_PIN, 0);
void setup() {
// Initialize bus first
mySPI.begin(14, 12, 13, 15);
// Connect MCP to existing bus
mcp.begin(&mySPI);
}在以下情况下使用:
- 同一总线上的多个SPI设备
- 需要完全控制SPI设置
- 不同设备组的单独总线
- 使用其他SPI库
______________________________________________________________________
对比表
| 功能 | 标准 | 自定义引脚 | 现有总线 |
|---|---|---|---|
| 简单 | ⭐⭐⭐ | ⭐⭐ | ⭐ |
| 灵活性 | ⭐ | ⭐⭐ | ⭐⭐⭐ |
| 巴士共享 | ❌ | ❌ | ✅ |
| 引脚选择 | ❌ | ✅ | ✅ |
| SPI控制 | ❌ | ❌ | ✅ |
📚 api参考
构造函数
MCP23S17(uint8_t csPin, uint8_t address = 0, uint32_t spiFrequency = 10000000)csPin:GPIO引脚用于芯片选择address:硬件地址0-7(通过A0、A1、A2)spiFrequency:SPI频率,单位为Hz(默认值:10 MHz)
初始化
begin()
bool begin()使用默认SPI引脚进行初始化。
退货: true 关于成功, false 失败时
开始(sck、味噌、mosi)
bool begin(int8_t sck, int8_t miso, int8_t mosi)使用自定义SPI引脚进行初始化。
参数:
sck:串行时钟引脚miso:主从输出针mosi:主人出奴隶入针
退货: true 关于成功, false 失败时
开始(spi)
bool begin(SPIClass* spi)使用现有的SPI总线进行初始化。
参数:
spi:指向已初始化SPIClass对象的指针
退货: true 关于成功, false 失败时
重要提示: 调用此命令之前必须初始化SPI总线!
GPIO基本功能
pinMode
void pinMode(uint8_t pin, uint8_t mode)配置引脚模式。
参数:
pin:0-15(0-7=端口A,8-15=端口B)mode:
- MCP23S17_INPUT -无上拉输入 - MCP23S17_OUTPUT -输出 - MCP23S17_INPUT_PULLUP -上拉输入
例子:
mcp.pinMode(0, MCP23S17_OUTPUT);
mcp.pinMode(8, MCP23S17_INPUT_PULLUP);数字写入
void digitalWrite(uint8_t pin, uint8_t value)将数字值写入引脚。
参数:
pin: 0-15value:HIGH或LOW
例子:
mcp.digitalWrite(0, HIGH);数字阅读
uint8_t digitalRead(uint8_t pin)从引脚读取数字值。
参数:
pin: 0-15
退货: HIGH 或 LOW
例子:
if (mcp.digitalRead(8) == HIGH) {
// Pin 8 is HIGH
}港口业务
端口模式
void portMode(uint8_t port, uint8_t modes)配置端口的所有8个引脚。
参数:
port:MCP23S17_PORTA或MCP23S17_PORTBmodes:8位值(1=输出,0=输入)
例子:
mcp.portMode(MCP23S17_PORTA, 0xFF); // All outputswritePort
void writePort(uint8_t port, uint8_t value)将8位值写入端口。
例子:
mcp.writePort(MCP23S17_PORTA, 0b10101010);readPort
uint8_t readPort(uint8_t port)从端口读取8位值。
例子:
uint8_t value = mcp.readPort(MCP23S17_PORTA);writeGPIO
void writeGPIO(uint16_t value)同时写入所有16个引脚。
参数:
value:16位值(低字节=端口A,高字节=端口B)
例子:
mcp.writeGPIO(0x00FF); // Port A = 0xFF, Port B = 0x00readGPIO
uint16_t readGPIO()同时读取所有16个引脚。
例子:
uint16_t allPins = mcp.readGPIO();拉起配置
setPullup
void setPullup(uint8_t pin, bool enable)启用/禁用单引脚上拉。
例子:
mcp.setPullup(8, true); // Enable pull-upsetPortPullups
void setPortPullups(uint8_t port, uint8_t value)为整个端口配置下拉菜单。
例子:
mcp.setPortPullups(MCP23S17_PORTB, 0xFF); // All pull-ups on中断功能
启用Interrupt
void enableInterrupt(uint8_t pin, uint8_t mode = MCP23S17_INT_CHANGE, uint8_t defaultValue = 0)为引脚启用中断。
参数:
pin: 0-15mode:
- MCP23S17_INT_CHANGE -变更时中断 - MCP23S17_INT_COMPARE -与默认值不同时中断
defaultValue:比较值(仅适用于COMPARE模式)
例子:
mcp.enableInterrupt(0, MCP23S17_INT_CHANGE);DisableInterrupt
void disableInterrupt(uint8_t pin)禁用引脚中断。
setPort中断
void setPortInterrupts(uint8_t port, uint8_t mask, uint8_t mode = MCP23S17_INT_CHANGE)为整个端口配置中断。
设置InterruptPolarity
void setInterruptPolarity(bool activeHigh)设置中断极性。
参数:
true:活动高false:活动低(默认)
setInterruptMirror
void setInterruptMirror(bool enable)连接INTA和INTB引脚。
getInterruptFlags
uint8_t getInterruptFlags(uint8_t port)读取哪些引脚触发了中断。
例子:
uint8_t flags = mcp.getInterruptFlags(MCP23S17_PORTA);
if (flags & 0x01) {
// Pin 0 triggered interrupt
}getInterruptCapture
uint8_t getInterruptCapture(uint8_t port)读取中断时的GPIO状态。
clear中断
void clearInterrupts()清除所有中断。
高级功能
重置
void reset()将所有寄存器重置为默认值。
读寄存器/写寄存器
uint8_t readRegister(uint8_t reg)
void writeRegister(uint8_t reg, uint8_t value)直接注册访问高级应用程序。
📖 例子
该库包括7个综合示例:
1.MCP23S17_链路
简单的LED闪烁示例-非常适合入门。
2.MCP23S17_自定义SPI
使用自定义SPI引脚而不是默认引脚。
3.MCP23S17_现有SPI
连接到现有的SPI总线-非常适合多个SPI设备。
4.MCP23S17_中断
带有中断处理和ISR处理的按钮。
5.MCP23S17_端口操作
使用端口操作同时控制8个引脚。
6.MCP23S17_多芯片
使用多个MCP23S17芯片(每个CS引脚最多8个)。
7.MCP23S17_完全测试
完整的功能测试和诊断。
🔥 高级用法
同一总线上的多个芯片
MCP23S17 mcp1(CS_PIN, 0); // Address 0
MCP23S17 mcp2(CS_PIN, 1); // Address 1
MCP23S17 mcp3(CS_PIN, 2); // Address 2
void setup() {
mcp1.begin();
mcp2.begin();
mcp3.begin();
// Control independently
mcp1.digitalWrite(0, HIGH);
mcp2.digitalWrite(0, HIGH);
mcp3.digitalWrite(0, HIGH);
}与其他设备共享SPI总线
SPIClass sharedBus(HSPI);
MCP23S17 mcp(15, 0);
// + SD card, display, etc.
void setup() {
sharedBus.begin(14, 12, 13, 15);
mcp.begin(&sharedBus);
SD.begin(4, sharedBus);
display.begin(&sharedBus);
}不同速度的独立巴士
SPIClass fastBus(VSPI);
SPIClass slowBus(HSPI);
MCP23S17 mcpFast(5, 0);
MCP23S17 mcpSlow(15, 0);
void setup() {
fastBus.begin();
fastBus.setFrequency(40000000); // 40 MHz
slowBus.begin(14, 12, 13, 15);
slowBus.setFrequency(1000000); // 1 MHz
mcpFast.begin(&fastBus);
mcpSlow.begin(&slowBus);
}中断处理
#define INT_PIN 4
volatile bool interruptFlag = false;
void IRAM_ATTR handleInterrupt() {
interruptFlag = true;
}
void setup() {
mcp.begin();
pinMode(INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INT_PIN), handleInterrupt, FALLING);
mcp.pinMode(0, MCP23S17_INPUT_PULLUP);
mcp.enableInterrupt(0);
mcp.clearInterrupts();
}
void loop() {
if (interruptFlag) {
interruptFlag = false;
uint8_t flags = mcp.getInterruptFlags(MCP23S17_PORTA);
uint8_t capture = mcp.getInterruptCapture(MCP23S17_PORTA);
// Process interrupt
mcp.clearInterrupts(); // Important!
}
}🐛 故障排除
未找到芯片
问题: begin() 返回false
解决:
- 检查接线(特别是VDD和GND)
- 验证SPI连接
- 确保RESET引脚为高电平(3.3V)
- 检查地址引脚(A0、A1、A2)
- 尝试较慢的SPI频率:
MCP23S17 mcp(5, 0, 1000000);
引脚没有响应
问题: digital写入/数字读取不工作
解决:
- 验证
pinMode()被呼叫 - 对于输入:检查是否需要上拉
- 对于输出:验证端口配置
- 使用寄存器转储进行测试:
Serial.println(mcp.readRegister(MCP23S17_IOCON), HEX);
中断不起作用
问题: 未触发中断
解决:
- 呼叫
clearInterrupts()处理后 - 检查中断极性设置
- 验证ESP32中断引脚配置
- 确保已启用中断:
mcp.enableInterrupt(pin) - 检查INTA/INTB连接
多芯片冲突
问题: 芯片相互干扰
解决:
- 确保不同的地址(A0、A1、A2)
- 如果地址相同:使用不同的CS引脚
- 检查HAEN位是否启用(自动完成)
- 验证每个芯片初始化:检查
begin()返回值
💡 提示和最佳实践
演出
- 使用端口操作而不是单个引脚,以获得更好的速度
- 寄存器缓存减少了不必要的SPI传输
- 最高速度:使用
writeGPIO()同时适用于所有16个引脚
电源管理
- MCP23S17支持1.8V-5.5V操作
- ESP32:使用3.3V
- 每个引脚的最大电流:25mA
- 为高电流负载使用外部驱动器
调试
// Print configuration
Serial.print("IOCON: 0x");
Serial.println(mcp.readRegister(MCP23S17_IOCON), HEX);
// Dump all GPIO states
uint16_t state = mcp.readGPIO();
Serial.print("GPIO: 0b");
Serial.println(state, BIN);SPI总线共享
与其他设备共享SPI总线时:
- MCP自动处理交易
- 无需手动交易管理
- 不同的设备可以使用不同的CS引脚
- 或者对多个MCP使用硬件寻址
🤝 贡献
欢迎投稿!请随时提交拉取请求。
开发设置
git clone https://github.com/yourusername/MCP23S17.git
cd MCP23S17编码标准
- 遵循现有代码样式
- 为复杂逻辑添加注释
- 包括新功能的示例
- 更新文档
📄 许可证
此库根据MIT许可证发布。有关详细信息,请参阅LICENSE文件。
🙏 致谢
- MCP23S17数据表的微芯片
- Arduino社区寻求灵感
- 所有贡献者和测试人员
📞 支持
- 问题:
- 讨论:
🔗 链接
⭐ 星迹
如果你觉得这个图书馆有用,请考虑给它一颗星! ⭐
