上次已经测试了MCP23017,看到说明书上有句话:
16-Bit Remote Bidirectional I/O Port (Pins GPA7, GPB7 are output only for MCP23017):
我的理解是GPA7, GPB7只能用于输出,不能用于输入检测
我心里还想,这个芯片好奇怪,居然还有这样的规定,但实际测试下来,并不是这样,16个脚完全可以检测输入的。
还有要注意的是在检测输入前需要配置几个寄存器:
1.上拉电阻寄存器,如果不上拉,又没有接外部上拉电阻,管脚悬空状态输入数据是随机的。
2.必须配置输入极性寄存器,如果不配置,它的默认值是一个随机值,导致检测输入数据是有错的。
#include <driver/i2c.h>
#include <esp_log.h>
#define I2C_MASTER_SCL_IO 15 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 16 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define MCP23017_ADDRESS 0x20 /*!< I2C address of MCP23017 */
static const char *TAG = "I2C_MASTER";
void i2c_master_init() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
void read_register(uint8_t reg, uint8_t *value)
{
uint8_t data[1] = {reg};
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
// 写入寄存器地址
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, data, 1, true);
// 读取数据
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_READ, true);
i2c_master_read(cmd, value, 1, I2C_MASTER_LAST_NACK);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
}
void write_register(uint8_t reg, uint8_t value) {
uint8_t data[2] = {reg, value};
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, data, sizeof(data), true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
}
uint16_t rotate_left(uint16_t value, unsigned int shift) {
// 计算移出的高位部分
uint16_t high_bits = (value >> (16 - shift)) & ((1U << shift) - 1);
// 将剩余部分左移
value <<= shift;
// 将移出的高位部分放到低位
value |= high_bits;
return value;
}
void app_main() {
i2c_master_init();
// 设置PORT A B为全输出
write_register(0x00, 0x00);
write_register(0x01, 0x00);
// 设置PORTA的输出值为0xFF
write_register(0x14, 0x0f);
write_register(0x15, 0xf0);
// 设置PORT A B为输入
write_register(0x00, 0xFF); //设置为输入
write_register(0x01, 0xFF); //设置为输入
write_register(0x02, 0x00); //输入极性寄存器设置为和输入一致
write_register(0x03, 0x00); //输入极性寄存器设置为和输入一致
write_register(0x0c, 0xFF); //上拉电阻寄存器设置为上拉
write_register(0x0d, 0xFF); //上拉电阻寄存器设置为上拉
uint8_t data1[1] = {0};
uint8_t data2[1] = {0};
while (true)
{
read_register(0x12, data1);
read_register(0x13, data2);
ESP_LOGI(TAG, "read register 0x12: %02X 0x13: %02X", data1[0], data2[0]);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
希望对你有所帮助。