RP2040 C SDK I2C外设使用
- 📌相关篇《RP2040 VSCode C/C++开发环境快速部署》
- 📍I2C API 外设:
https://www.raspberrypi.com/documentation/pico-sdk/hardware.html#group_hardware_i2c
- 🔧驱动I2C ssd1306 屏幕需要使用到的库:
https://github.com/daschr/pico-ssd1306
RP2040有2 个硬件 I2C 控制器。
📗利用I2C扫描I2C设备地址
/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"-c "program RP2040_I2C_SCAN.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg -c "adapter speed 2000" -c "program RP2040_I2C_SCAN.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"// 板载LED连接的GPIO引脚
#define LED_PIN 25
// I2C defines
// This example will use I2C0 on GPIO4 (SDA) and GPIO5 (SCL) running at 400KHz.
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define I2C_PORT i2c0
#define I2C_SDA_PIN 4
#define I2C_SCL_PIN 5void i2c_setup() {// I2C Initialisation. Using it at 400Khz.i2c_init(I2C_PORT, 400 * 1000);gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);gpio_pull_up(I2C_SDA_PIN);//开启内部上拉gpio_pull_up(I2C_SCL_PIN);// Make the I2C pins available to picotoolbi_decl(bi_2pins_with_func(I2C_SDA_PIN, I2C_SCL_PIN, GPIO_FUNC_I2C));
}void scan_i2c_addresses() {for (uint8_t addr = 0x03; addr <= 0x7f; addr++) {uint8_t data = 0x00;int result = i2c_write_blocking(I2C_PORT, addr, &data, 1, false);if (result == 1) {printf("I2C device found at address 0x%02X\n", addr);}}
}int main()
{stdio_init_all();// 设置LED_PIN为输出模式gpio_init(LED_PIN);gpio_set_dir(LED_PIN, GPIO_OUT);// 初始化I2Ci2c_setup();scan_i2c_addresses();while (1) {tight_loop_contents();// 翻转LED状态gpio_put(LED_PIN,!gpio_get(LED_PIN));// 等待0.5秒sleep_ms(3500);scan_i2c_addresses();}return 0;
}
📘SSD1306 oled屏幕驱动显示
配合上面的库实现,很容易点亮屏幕。
- 调用库需要在项目的
CMakeLists.txt
中添加对应的源文件。推荐拷贝到项目文件夹内,这样就免去路径。
add_executable(RP2040_I2C_SSD1306 RP2040_I2C_SSD1306.cssd1306.c)
- 测试demo
/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"-c "program RP2040_I2C_SSD1306.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg -c "adapter speed 2000" -c "program RP2040_I2C_SSD1306.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"#include "ssd1306.h" // Include the SSD1306 library
#include "acme_5_outlines_font.h"
// I2C defines
// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define I2C_PORT i2c0
#define I2C_SDA_PIN 4
#define I2C_SCL_PIN 5const uint8_t num_chars_per_disp[]={7,7,7,5};
//const uint8_t *fonts[4]= {acme_font, bubblesstandard_font, crackers_font, BMSPA_font};
//const uint8_t *fonts[1]= {font_8x5};
// 板载LED连接的GPIO引脚
#define LED_PIN 25
#define SLEEPTIME 25/*** @brief 初始化I2C接口** 该函数用于初始化I2C接口,设置I2C的时钟频率为400KHz,* 并将I2C的SDA和SCL引脚设置为I2C功能,同时启用上拉电阻。** @param 无* @return 无*/
void i2c_setup() {// 初始化I2C接口,设置I2C的时钟频率为400KHzi2c_init(I2C_PORT, 400 * 1000);// 将I2C的SDA引脚设置为I2C功能gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);// 将I2C的SCL引脚设置为I2C功能gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);// 启用I2C的SDA引脚的上拉电阻gpio_pull_up(I2C_SDA_PIN);// 启用I2C的SCL引脚的上拉电阻gpio_pull_up(I2C_SCL_PIN);// Make the I2C pins available to picotoolbi_decl(bi_2pins_with_func(I2C_SDA_PIN, I2C_SCL_PIN, GPIO_FUNC_I2C));//需要包含binary_info.h头文件
}void animation(void) {const char *words[]= {"SSD1306", "DISPLAY", "DRIVER"};ssd1306_t disp;disp.external_vcc=false;ssd1306_init(&disp, 128, 64, 0x3C, i2c0);ssd1306_clear(&disp);printf("ANIMATION!\n");char buf[8];for(;;) {for(int y=0; y<31; ++y) {ssd1306_draw_line(&disp, 0, y, 127, y);ssd1306_show(&disp);sleep_ms(SLEEPTIME);ssd1306_clear(&disp);}for(int y=0, i=1; y>=0; y+=i) {ssd1306_draw_line(&disp, 0, 31-y, 127, 31+y);ssd1306_draw_line(&disp, 0, 31+y, 127, 31-y);ssd1306_show(&disp);sleep_ms(SLEEPTIME);ssd1306_clear(&disp);if(y==32) i=-1;}for(int i=0; i<sizeof(words)/sizeof(char *); ++i) {ssd1306_draw_string(&disp, 8, 24, 2, words[i]);ssd1306_show(&disp);sleep_ms(800);ssd1306_clear(&disp);}for(int y=31; y<63; ++y) {ssd1306_draw_line(&disp, 0, y, 127, y);ssd1306_show(&disp);sleep_ms(SLEEPTIME);ssd1306_clear(&disp);}// ssd1306_draw_string_with_font(&disp, 8, 24, 2, font_8x5, buf);ssd1306_draw_string_with_font(&disp, 8, 24, 2, acme_font, (char*)"Hello!");ssd1306_draw_string(&disp, 8, 0, 1, "Perseverance51");ssd1306_show(&disp);sleep_ms(800);ssd1306_clear(&disp);gpio_put(LED_PIN,!gpio_get(LED_PIN));sleep_ms(2000);}
}int main()
{stdio_init_all();gpio_init(LED_PIN);gpio_set_dir(LED_PIN, GPIO_OUT);i2c_setup();
while (1) {// tight_loop_contents()animation();}return 0;
}
📒利用I2C读写AT24C02数据操作
- AT24C02是一个只有256字节的存储器。
/*CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"-c "program RP2040_I2C_AT24C02.elf verify reset exit"jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg -c "adapter speed 2000" -c "program RP2040_I2C_AT24C02.elf verify reset exit"*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "pico/binary_info.h"// 板载LED连接的GPIO引脚
#define LED_PIN 25
// I2C defines
// This example will use I2C0 on GPIO4 (SDA) and GPIO5 (SCL) running at 400KHz.
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define I2C_PORT i2c0
#define I2C_SDA_PIN 4
#define I2C_SCL_PIN 5#define AT24C02_ADDR 0x50 // AT24C02的地址void i2c_setup() {// I2C Initialisation. Using it at 100Khz.i2c_init(I2C_PORT, 100 * 1000);gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);gpio_pull_up(I2C_SDA_PIN);//开启内部上拉gpio_pull_up(I2C_SCL_PIN);// Make the I2C pins available to picotoolbi_decl(bi_2pins_with_func(I2C_SDA_PIN, I2C_SCL_PIN, GPIO_FUNC_I2C));
}void scan_i2c_addresses() {for (uint8_t addr = 0x03; addr <= 0x7f; addr++) {uint8_t data = 0x00;int result = i2c_write_blocking(I2C_PORT, addr, &data, 1, false);if (result == 1) {printf("I2C device found at address 0x%02X\n", addr);}}
}// 向AT24C02写入一个字节
void at24c02_write_byte(uint8_t addr, uint8_t data) {uint8_t buffer[2];buffer[0] = addr;buffer[1] = data;i2c_write_blocking(I2C_PORT, AT24C02_ADDR, buffer, 2, false);sleep_ms(5); // AT24C02写入需要一定时间,这里简单延时等待
}// 从AT24C02读取一个字节
uint8_t at24c02_read_byte(uint8_t addr) {i2c_write_blocking(I2C_PORT, AT24C02_ADDR, &addr,1, true);uint8_t data;i2c_read_blocking(I2C_PORT, AT24C02_ADDR, &data, 1, false);return data;
}// 从AT24C02读取指定长度的数据
void at24c02_read(uint8_t addr, uint8_t *data, size_t length) {i2c_write_blocking(I2C_PORT, AT24C02_ADDR, &addr, 1, true);i2c_read_blocking(I2C_PORT, AT24C02_ADDR, data, length, false);
}int main()
{uint8_t EP_data[35];stdio_init_all();i2c_setup();gpio_init(LED_PIN);gpio_set_dir(LED_PIN, GPIO_OUT);scan_i2c_addresses();at24c02_write_byte(255, 'A');while (1) {// tight_loop_contents();// 翻转LED状态gpio_put(LED_PIN,!gpio_get(LED_PIN));// 读取AT24C02的状态uint8_t data = at24c02_read_byte(255);printf("AT24C02 Address 255 data: %c\n", data);at24c02_read(0, EP_data, 35);printf("EP_data: %s\n", EP_data);sleep_ms(1000);}// puts("Hello, world!");return 0;
}