原理图
注:模块和控制器的需要使用同一个电源
features
1、High-Speed I2C Interface (MCP23017):
- 100 kHz
- 400 kHz
- 1.7 MHz
2、3.3V,5V都可
寄存器
官网历程用的也是bank0的
寄存器 | 作用 | 使用 | 默认 |
---|---|---|---|
IODIR | 控制pin输入输出 | 1输入,0输出 | 输入 |
IPOL | 控制输入引脚的极性反转 | 1,反应引脚的反相值 | 0,不反转 |
GPINTEN | 使能对应的pin输入中断(与DEFVAL and INTCON配套使用) | 1使能中断,0不使能 | 不使能 |
DEFVAL | 比较值(引脚值与这个值不同则发生中断) | 0 | |
INTCON | 设置比较方式 | 为1,引脚值与默认值DEFVAL比较。为0,引脚与先前值比较 | 0,与先前值比较 |
GPPU | 输入时使用,配置相应的引脚上拉 | 1上拉使能,0不上拉 | 不上拉 |
INTF(flag) | 反应了对应引脚(使能中断的引脚)的中断状态(只读) | 1中断发生了,0中断没有发生 | 0 |
INTCAP | 中断发生时捕获端口值(只读,只在中断发生时才会更新。在还没有读取寄存器的值时(或GPIO值),其值一直都保持不变) | 1,逻辑高,0逻辑低 | 低 |
GPIO | 可以读(获得端口值),写入该寄存器将修改输出锁存(OLAT)寄存器的值 | 1高 | |
OLAT | 输出锁存寄存器,读的话会读到OLAT,而不是端口 | 1高 |
配置寄存器IOCON
- BANK(bit7):控制寄存器地址
- MIRROR(bit6): 为1,任何一个端口上的中断都会使INTA和INTB激活。 为0,B端口中断使INTB激活,A端口中断INTA激活
- SEQOP(bit5):连续操作模式位。 为1,禁止连续操作,地址指针不递增。 为0,使能连续操作,地址指针递增
- DISSLW(bit4):不用他
- HAEN(bit3):硬件地址使能位(1使用地址引脚配置地址)
- ODR(bit2):开漏控制位,用于使能或禁止INT引脚的开漏输出,1使能
- INTPOL(bit1):INT的输出极性,1高电平
- bit0:保留
INTCON两种中断解释:
- 默认值的时候,引脚只要与默认值不同则产生中断(可以设置为高电平中断,低电平中断)
- 先前值,则当引脚值发生改变的时候就产生一次中断(电平变化中断)
代码
F407,HAL库代码
MCP23017.C
#include "MCP23017.h"
//--------------------------------------------------------------------------------------
// 函数名称:bit MCP23017_INIT(unsigned char deviceAddr,unsigned char ab,unsigned char hwa,unsigned char o)
// 函数功能:初始化指定地址的MCP23017器件
// 参数:deviceAddr——设备地址,有A0,A1,A2决定
// intab——配置INTA、INTB是否关联,取值INTA_INTB_CONJUNCTION、INTA_INTB_INDEPENDENT
// hwa——配置A0、A1、A2硬件地址是否使能,取值HWA_EN、HWA_DIS
// o——配置INTA、INTB的输出类型,取值INT_OD、INT_PUSHPULL_HIGH、INT_PUSHPULL_LOW
//--------------------------------------------------------------------------------------
HAL_StatusTypeDef MCP23017_INIT(uint16_t deviceAddr,unsigned char intab,unsigned char hwa,unsigned char o)
{
unsigned char state;
HAL_StatusTypeDef res;
//首先设置其他位的默认状态
state = 0x2E; //001011 10,BANK = 0,默认不关联AB(bit = 0),禁用顺序操作,使能变化率控制、使能硬件地址,开漏输出
if(intab==INTA_INTB_CONJUNCTION)
{
state |= 0x40;
}
if(hwa==HWA_DIS)
{
state &= (~0x08);
}
if(o==INT_PUSHPULL_HIGH)
{
state &= (~0x04);
state |= 0x02;
}
if(o==INT_PUSHPULL_LOW)
{
state &= (~0x04);
state &= (~0x02);
}
//写回方向寄存器
res =HAL_I2C_Mem_Write(&hi2c1,deviceAddr,MCP23017_IOCON, I2C_MEMADD_SIZE_8BIT,&state, 1, 100);
return res;
}
//--------------------------------------------------------------------------------------
// 函数名称:MCP23017_IO_DIR(unsigned char deviceAddr,unsigned char port,unsigned char pin,unsigned char dir)
// 函数功能:设置制定地址的MCP23017的指定端口的指定引脚为输入或输出状态,其他引脚维持不变
// 参数:deviceAddr——设备地址,有A0,A1,A2决定
// port——端口名称,取值MCP23017_PORTA、MCP23017_PORTB
// pin——引脚号,取值PIN0-PIN7对应端口的8个引脚,ALLPIN包括端口所有8个引脚
// dir——输入输出方向,取值INPUT、OUTPUT
//--------------------------------------------------------------------------------------
HAL_StatusTypeDef MCP23017_IO_DIR(uint16_t deviceAddr,unsigned char port,unsigned char pin,unsigned char dir)
{
unsigned char *portState;
HAL_StatusTypeDef res;
//首先读取当前端口方向的配置状态
//因为B端口的地址比A端口的寄存器的地址都是大1,所以采用+的技巧切换寄存器
res = HAL_I2C_Mem_Read(&hi2c1, deviceAddr, MCP23017_IODIR+port, I2C_MEMADD_SIZE_8BIT, portState, 1, 100);
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)//需要加上这一段,不然会出错
{
}
//如果出错则返回
if(res != HAL_OK)
{
return res;
}
if(dir==INPUT)
{
*portState |= pin;
}
else
{
*portState &= (~pin);
}
//写回方向寄存器
res =HAL_I2C_Mem_Write(&hi2c1,deviceAddr,MCP23017_IODIR+port, I2C_MEMADD_SIZE_8BIT,portState, 1, 100);
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
return res;
}
//--------------------------------------------------------------------------------------
// 函数名称:bit MCP23017_WRITE_GPIO(unsigned char deviceAddr,unsigned char port,unsigned char val)
// 函数功能:向指定地址的MCP23017的指定端口写值
// 参数:deviceAddr——设备地址,有A0,A1,A2决定
// port——端口名称,取值MCP23017_PORTA、MCP23017_PORTB
// val——要写入端口寄存器的值
//--------------------------------------------------------------------------------------
HAL_StatusTypeDef