ESP32S3 IDF 对 16路输入输出芯片MCP23017做了个简单的测试

这次还是使用了idf老版本4.4.7,上次用了5.3,感觉不好用,官方的MCP23017芯片是英文版,真的很难读明白,可能是我英语水平不够吧。先看看每个寄存器的功能:

在这里插入图片描述

IODIRA 和 IODIRB: 输入/输出方向寄存器
IPOLA 和 IPOLB: 输入极性寄存器
GPINTENA 和 GPINTENB: GPIO 中断使能寄存器
DEFVALA 和 DEFVALB: 默认值寄存器
INTCONA 和 INTCONB: 中断控制寄存器
IOCONA 和 IOCONB: 配置寄存器
GPPUA 和 GPPUB: 上拉电阻寄存器
INTFA 和 INTFB: 中断标志寄存器
INTCAPA 和 INTCAPB: 中断捕获寄存器
GPIOA 和 GPIOB: 数据方向寄存器
OLATA 和 OLATB: 输出锁存器寄存器

寄存器说明

  1. 输入/输出方向寄存器 (IODIRA 和 IODIRB)
    地址: IODIRA 的地址是 0x00,IODIRB 的地址是 0x01。
    功能: 这些寄存器用于设置 Port A 和 Port B 上每个 GPIO 引脚的输入/输出方向。
    0: 对应的引脚配置为输出。
    1: 对应的引脚配置为输入。
  2. 输入极性寄存器 (IPOLA 和 IPOLB)
    地址: IPOLA 的地址是 0x02,IPOLB 的地址是 0x03。
    功能: 这些寄存器用于反转 Port A 和 Port B 上每个 GPIO 引脚的输入状态。
    0: 对应的引脚保持原始输入状态。
    1: 对应的引脚输入状态被反转。
  3. GPIO 中断使能寄存器 (GPINTENA 和 GPINTENB)
    地址: GPINTENA 的地址是 0x04,GPINTENB 的地址是 0x05。
    功能: 这些寄存器用于启用 Port A 和 Port B 上每个 GPIO 引脚的中断功能。
    0: 对应的引脚的中断功能禁用。
    1: 对应的引脚的中断功能启用。
  4. 默认值寄存器 (DEFVALA 和 DEFVALB)
    地址: DEFVALA 的地址是 0x06,DEFVALB 的地址是 0x07。
    功能: 这些寄存器用于设置 Port A 和 Port B 上每个 GPIO 引脚的默认比较值。当 GPIO 引脚的输入状态与默认值寄存器中的值不同时,会产生中断。
  5. 中断控制寄存器 (INTCONA 和 INTCONB)
    地址: INTCONA 的地址是 0x08,INTCONB 的地址是 0x09。
    功能: 这些寄存器用于配置 Port A 和 Port B 上每个 GPIO 引脚的中断触发方式(上升沿、下降沿或变化)。
    0: 对应的引脚中断触发方式为变化。
    1: 对应的引脚中断触发方式为上升沿或下降沿。
  6. 配置寄存器 (IOCONA 和 IOCONB)
    地址: IOCONA 的地址是 0x0A,IOCONB 的地址是 0x0B。
    功能: 这些寄存器用于配置全局设置,如中断行为、序列号等。
  7. 上拉电阻寄存器 (GPPUA 和 GPPUB)
    地址: GPPUA 的地址是 0x0C,GPPUB 的地址是 0x0D。
    功能: 这些寄存器用于启用 Port A 和 Port B 上每个 GPIO 引脚的内部上拉电阻。
    0: 对应的引脚的上拉电阻禁用。
    1: 对应的引脚的上拉电阻启用。
  8. 中断标志寄存器 (INTFA 和 INTFB)
    地址: INTFA 的地址是 0x0E,INTFB 的地址是 0x0F。
    功能: 这些寄存器用于指示 Port A 和 Port B 上每个 GPIO 引脚是否产生了中断。当某个引脚产生中断时,相应的位将被设置为 1。
  9. 中断捕获寄存器 (INTCAPA 和 INTCAPB)
    地址: INTCAPA 的地址是 0x10,INTCAPB 的地址是 0x11。
    功能: 这些寄存器用于存储 Port A 和 Port B 上每个 GPIO 引脚在产生中断时的输入状态。
  10. 数据方向寄存器 (GPIOA 和 GPIOB)
    地址: GPIOA 的地址是 0x12,GPIOB 的地址是 0x13。
    功能: 这些寄存器用于读取 Port A 和 Port B 上每个 GPIO 引脚的当前输入状态。
  11. 输出锁存器寄存器 (OLATA 和 OLATB)
    地址: OLATA 的地址是 0x14,OLATB 的地址是 0x15。
    功能: 这些寄存器用于设置 Port A 和 Port B 上每个 GPIO 引脚的输出状态。

代码,已经测试读写寄存器没有问题,输入可以检测(没用中断),也可以正常输出:

#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);
}

void set_output_direction(uint8_t port, uint8_t direction) {
    // 设置输出方向
    // 方向:0为输出,1为输入
    write_register(port == 0 ? 0x00 : 0x01, direction);
}

void set_output_value(uint8_t port, uint8_t value) {
    // 设置输出值
    // value: 输出值
    //write_register(port == 0 ? 0x12 : 0x13, value);
    write_register(port == 0 ? 0x14 : 0x15, value);
}

void example() {
    i2c_master_init();
    // 设置PORTA为全输出
    set_output_direction(0, 0x00);
    // 设置PORTA的输出值为0xFF
    set_output_value(0, 0x0f);
}

void app_main() {
    i2c_master_init();
    // 设置PORT A B为全输出
    set_output_direction(0, 0x00);
    set_output_direction(1, 0x00);

    // 设置PORTA的输出值为0xf5	B为0xAF
    set_output_value(0, 0xf5);
    set_output_value(1, 0xAf);




    // 设置PORT A B为输入
    set_output_direction(0, 0xff);
    set_output_direction(1, 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);
    }
    

}

希望对你有帮助。

  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是ESP32-S3 IDF读取SD卡音频文件通过I2S输出的详细程序: 首先,需要在`menuconfig`中配置SD卡和I2S驱动程序。在`Component config -> ESP32-S3-specific`中,启用`SD Card Support`和`I2S`选项。 接下来,需要包含必要的头文件: ```c #include <stdio.h> #include <string.h> #include "esp_log.h" #include "driver/i2s.h" #include "sdmmc_cmd.h" #include "driver/sdmmc_host.h" #include "driver/sdmmc_defs.h" ``` 然后定义一些常量和变量: ```c #define TAG "SD_I2S_PLAYER" #define I2S_NUM 0 // I2S设备编号 #define I2S_SAMPLE_RATE 44100 // I2S采样率 #define I2S_BITS_PER_SAMPLE 16 // I2S每个采样位数 #define I2S_CHANNEL_NUM 2 // I2S通道数 #define I2S_BUF_SIZE 1024 // I2S缓冲区大小 static const char *SD_MOUNT_POINT = "/sdcard"; // SD卡挂载点 static const char *AUDIO_FILE_PATH = "/sdcard/audio.wav"; // 音频文件径 static uint8_t i2s_buf[I2S_BUF_SIZE] = {0}; // I2S缓冲区 ``` 接下来是SD卡初始化的代码: ```c static esp_err_t sd_card_init(void) { ESP_LOGI(TAG, "Initializing SD card..."); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); slot_config.gpio_cd = GPIO_NUM_34; // SD卡检测引脚 slot_config.width = 1; // SD卡总线宽度为1位 esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = true, .max_files = 5, .allocation_unit_size = 16 * 1024 }; sdmmc_card_t *card = NULL; esp_err_t ret = esp_vfs_fat_sdmmc_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &card); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to mount SD card (%s)", esp_err_to_name(ret)); return ret; } return ESP_OK; } ``` 接下来是I2S初始化的代码: ```c static esp_err_t i2s_init(void) { ESP_LOGI(TAG, "Initializing I2S..."); i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_TX, .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_I2S, .dma_buf_count = 2, .dma_buf_len = I2S_BUF_SIZE / 2, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .tx_desc_auto_clear = true }; i2s_pin_config_t pin_config = { .bck_io_num = GPIO_NUM_26, .ws_io_num = GPIO_NUM_25, .data_out_num = GPIO_NUM_22, .data_in_num = I2S_PIN_NO_CHANGE }; esp_err_t ret = i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to install I2S driver (%s)", esp_err_to_name(ret)); return ret; } ret = i2s_set_pin(I2S_NUM, &pin_config); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set I2S pins (%s)", esp_err_to_name(ret)); return ret; } return ESP_OK; } ``` 接下来是读取音频文件并通过I2S输出的代码: ```c static esp_err_t play_audio(void) { FILE *file = fopen(AUDIO_FILE_PATH, "rb"); if (file == NULL) { ESP_LOGE(TAG, "Failed to open audio file (%s)", AUDIO_FILE_PATH); return ESP_FAIL; } size_t bytes_read = 0; size_t bytes_written = 0; while ((bytes_read = fread(i2s_buf, 1, I2S_BUF_SIZE, file)) > 0) { bytes_written = i2s_write_bytes(I2S_NUM, (const char *) i2s_buf, bytes_read, portMAX_DELAY); if (bytes_written != bytes_read) { ESP_LOGE(TAG, "Failed to write I2S data (%d/%d)", bytes_written, bytes_read); fclose(file); return ESP_FAIL; } } fclose(file); return ESP_OK; } ``` 最后是主函数,调用以上函数: ```c void app_main(void) { ESP_ERROR_CHECK(sd_card_init()); ESP_ERROR_CHECK(i2s_init()); ESP_ERROR_CHECK(play_audio()); } ``` 以上就是ESP32-S3 IDF读取SD卡音频文件通过I2S输出的详细程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值