RP2040 C SDK I2C外设使用
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 5
void 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 picotool
bi_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);
// 初始化I2C
i2c_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.c
ssd1306.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 5
const 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的时钟频率为400KHz
i2c_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 picotool
bi_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 picotool
bi_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;
}