本帖最后由 tpgf 于 2023-8-15 08:31 编辑
i2c使用
i2c是一种半双工同步通信方式,在硬件上包含两条线分别为时钟线SCL和数据线SDA。i2c总线上可以挂载多个从设备,每个从设备都有唯一的地址,主设备通过地址与指定的从设备进行通信。
如上所示为RTT的i2c框架图,主要分为设备层-框架层-驱动层。
设备层:设备就是杂七杂八的使用I2C的总线的设备。而这些设备可以选择使用RTT驱动框架的API,也可以选择RTT封装好的API
核心层:
bit_ops是RTT为软件I2C提供的中间层,它的作用:为底层模拟I2C驱动提供回调接口,为核心层提供统一I2C通信接口
硬件I2C则直接对接核心层,提供统一I2C通信接口
dev是提供RTT设备驱动框架的统一的API(实现箭头);RTT在核心层core上,封装了一套API(虚线箭头),供用户直接使用
驱动层:分为硬件I2C驱动和软件I2C驱动
软件i2c驱动层:主要进行软件I2C所用到scl引脚,sda引脚初始化。scl引脚和sda引脚的获取电平和设置电平接口和延时函数(udelay)。并对接bit_opt层提供的操作结构体:struct rt_i2c_bit_ops。并通过rt_i2c_bit_add_bus注册,提供给bit_opt层回调。
struct rt_i2c_bit_ops结构体:
struct rt_i2c_bit_ops
{
void *data; /* private data for lowlevel routines */
void (*set_sda)(void *data, rt_int32_t state);
void (*set_scl)(void *data, rt_int32_t state);
rt_int32_t (*get_sda)(void *data);
rt_int32_t (*get_scl)(void *data);
void (*udelay)(rt_uint32_t us);
rt_uint32_t delay_us; /* scl and sda line delay */
rt_uint32_t timeout; /* in tick */
};
bit_opt层:可以归纳为驱动层。其主要实现软件I2C的时序等逻辑,并提供对应的I2C的收发处理函数,为drv_soft_i2c层提供提供了(struct rt_i2c_bit_ops)注册接口和(rt_i2c_bit_add_bus)接口,为i2c_core层提供主机模式的数据处理函数i2c_bit_xfer()。rt-thread的软件i2c,如果要对接其他平台,只需要对接好结构体:struct rt_i2c_bit_ops,而软件i2c的逻辑完全不用理会,全部由bit_opt层管理。
硬件i2c驱动层:无需对接bit_ops层,直接对接i2c_core层提供的结构体:struct rt_i2c_bus_device_ops。
i2c驱动框架会将需要发送的数据或者接收的数据封装成一个message进行发送和接收。rt-thread下的message的数据结构如下:
struct rt_i2c_msg
{
rt_uint16_t addr; /* 从机地址 */
rt_uint16_t flags; /* 读写标志 */
rt_uint16_t len; /* 数据长度 */
rt_uint8_t *buf; /* 读写buffer指针 */
};
如上所示,使用rt_i2c_msg将需要的读写数据封装起来,然后调用i2c的发送函数即可,rt-thread的发送函数为:
rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
以上第一个参数bus为struct rt_i2c_bus_device的指针。i2c设备会被抽象成一个结构体对象来进行描述,rt_i2c_bus_device就是对i2c控制器设备的抽象,具体如下:
struct rt_i2c_bus_device
{
struct rt_device parent;
const struct rt_i2c_bus_device_ops *ops;
rt_uint16_t flags;
struct rt_mutex lock;
rt_uint32_t timeout;
rt_uint32_t retries;
void *priv;
};
i2c在用应用层的操作:在完成i2c设备注册后,首先调用通用接口rt_device_find根据设备名查找rt_i2c_bus_device,然后用rt_i2c_msg封装要发送或者接收的数据,最后调用rt_i2c_transfer进行数据收发。
i2c驱动框架
rt-thread的i2c驱动框架中,使用rt_i2c_bus_device对i2c控制器进行抽象。i2c驱动框架仅需关注rt_i2c_bus_device结构体中的rt_device parent和rt_i2c_bus_device_ops ops成员。parent成员的作用,是将i2c控制器设备挂载到内核的设备信息链表中进行统一的 管理。ops成员就是I2C设备操作函数的集合,一般为数据的收发函数。ops对应的结构体(I2C控制的操作函数)如下:
struct rt_i2c_bus_device_ops
{
rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
rt_uint32_t,
rt_uint32_t);
};
其中,master_xfer函数是对i2c设备进行数据交互的核心函数。rt_i2c_bus_device_register函数向rt-thread内核设备注册设备对象,其一般封装在rt_i2c_bit_add_bus函数中。
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
bus->ops = &i2c_bit_bus_ops;
return rt_i2c_bus_device_register(bus, bus_name);
}
rt_i2c_bit_add_bus函数的作用就是向rt-thread内核注册i2c设备内核对象,进行统一管理。在进行注册之前,需要对rt_i2c_bus_device 结构体中的成员函数进行初始化,如上rt_i2c_bus_device 中的rt_i2c_bus_device_ops被初始化为i2c_bit_bus_ops,i2c_bit_bus_ops中存在对i2c设备进行数据交互的核心函数,如下:
static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
{
i2c_bit_xfer,
RT_NULL,
RT_NULL
};
rt_i2c_bus_device_register注册函数,调用rt_i2c_bus_device_device_init,其实现为:
rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
const char *name)
{
struct rt_device *device;
RT_ASSERT(bus != RT_NULL);
device = &bus->parent;
device->user_data = bus;
/* set device type */
device->type = RT_Device_Class_I2CBUS;
/* initialize device interface */
#ifdef RT_USING_DEVICE_OPS
device->ops = &i2c_ops;
#else
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = i2c_bus_device_read;
device->write = i2c_bus_device_write;
device->control = i2c_bus_device_control;
#endif
/* register to device manager */
rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}
如代码所示 ,rt_device的标准操作函数与i2c设备操作函数一一对应,对应关系:
rt_device_read ---> i2c_bus_device_read
rt_device_write ---> i2c_bus_device_write
rt_device_control ---> i2c_bus_device_control
以rt_device_write为例,其最终调用到底层ops操作函数的过程:
rt_device_write
i2c_bus_device_write
rt_i2c_master_send
rt_i2c_transfer
master_xfer --> i2c_bit_xfer
其中,master_xfer函数就是i2c控制器与i2c设备进行数据交互的最底层函数。在rt_i2c_bus_device注册中,该函数已经被初始化为i2c_bit_xfer。i2c_bit_xfer函数的实现,根据i2c协议实现响应的读写时序。
软件i2c代码框架,以stm32某型号为例:
对应的驱动层的drv_soft_i2c代码调用如下,针对不同硬件的功能函数,统一放在priv成员:
框架层下的i2c_bit_xfer函数操作过程中对priv对应是ops中的函数进行调用操作。pico的软件i2c操作与stm相似,读写操作在驱动框架层下的i2c_bit_xfer函数中实现,驱动层需要实现rt_i2c_ops中的函数(如:void (*set_sda)、void (*set_scl)、rt_int32_t (*get_sda)、rt_int32_t (*get_scl))。
综上,软件i2c驱动主要针对pin引脚进行设置
软件i2c参考:
https://blog.csdn.net/xiaoyuanwuhui/article/details/107430279
硬件i2c代码框架,以pico为例:
同样,以rt_device_write为例,其最终调用到底层ops操作函数的过程:
rt_device_write
i2c_bus_device_write
rt_i2c_master_send
rt_i2c_transfer
master_xfer --> raspi_i2c_mst_xfer(需要写读写操作函数)
驱动代码drv_i2c.c
#include "drv_i2c.h"
#include "drv_gpio.h"
#include "hardware/i2c.h"
#define PICO_I2C i2c1
#define LED_PIN 25
//OLED type for init function
enum {
OLED_128x128 = 1,
OLED_128x32,
OLED_128x64,
OLED_132x64,
OLED_64x32,
OLED_96x16,
OLED_72x40
};
typedef struct mybbi2c
{
uint8_t iSDA, iSCL;
i2c_inst_t * picoI2C;
} BBI2C;
typedef struct ssoleds
{
uint8_t oled_addr;
uint8_t oled_type;
uint8_t *ucScreen;
BBI2C bbi2c;
} SSOLED;
struct raspi_i2c_hw_config
{
rt_uint32_t bsc_rate;
rt_uint32_t bsc_address;
rt_uint32_t sda_pin;
rt_uint32_t scl_pin;
};
SSOLED oled;
int32_t speed;
void oled_init(BBI2C *pI2C, uint32_t iClock)
{
if (pI2C == NULL) return;
if ((pI2C->iSDA + 2 * i2c_hw_index(pI2C->picoI2C))%4 != 0) return ;
if ((pI2C->iSCL + 3 + 2 * i2c_hw_index(pI2C->picoI2C))%4 != 0) return ;
i2c_init(pI2C->picoI2C, iClock);
gpio_set_function(pI2C->iSDA, GPIO_FUNC_I2C);
gpio_set_function(pI2C->iSCL, GPIO_FUNC_I2C);
gpio_pull_up(pI2C->iSDA);
gpio_pull_up(pI2C->iSCL);
return;
}
static rt_ssize_t raspi_i2c_mst_xfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
int rc =0;
oled.oled_type = OLED_128x64;
oled.oled_addr = ((struct raspi_i2c_hw_config *)bus->priv)->bsc_address;
oled.bbi2c.picoI2C = PICO_I2C;
oled.bbi2c.iSDA = ((struct raspi_i2c_hw_config *)bus->priv)->sda_pin;
oled.bbi2c.iSCL = ((struct raspi_i2c_hw_config *)bus->priv)->scl_pin;
speed = ((struct raspi_i2c_hw_config *)bus->priv)->bsc_rate;
// 初始化 init
oled_init(&oled.bbi2c,(int32_t) speed);
i2c_write_blocking((&oled.bbi2c)->picoI2C, oled.oled_addr, msgs->buf, msgs->len, true);
return 0;
}
static rt_ssize_t raspi_i2c_slv_xfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
return 0;
}
static rt_err_t raspi_i2c_bus_control(struct rt_i2c_bus_device *bus,
rt_uint32_t cmd,
rt_uint32_t arg)
{
return RT_EOK;
}
static const struct rt_i2c_bus_device_ops raspi_i2c_ops =
{
.master_xfer = raspi_i2c_mst_xfer,
.slave_xfer = raspi_i2c_slv_xfer,
.i2c_bus_control = raspi_i2c_bus_control,
};
#if defined (BSP_USING_I2C0)
#define I2C0_BUS_NAME "i2c0"
static struct raspi_i2c_hw_config hw_device0 =
{
.bsc_num = 0,
.bsc_rate = 100000,
.bsc_address = BSC0_BASE,
.sda_pin = GPIO_PIN_0,
.scl_pin = GPIO_PIN_1,
.sda_mode = ALT0,
.scl_mode = ALT0,
};
struct rt_i2c_bus_device device0 =
{
.ops = &raspi_i2c_ops,
.priv = (void *)&hw_device0,
};
#endif
#if defined (BSP_USING_I2C1)
#define I2C1_BUS_NAME "i2c1"
static struct raspi_i2c_hw_config hw_device1 =
{
.bsc_rate = 100000,
.bsc_address = PKG_USING_SSD1306_I2C_ADDRESS,
.sda_pin = BSP_I2C1_SDA_PIN,
.scl_pin = BSP_I2C1_SCL_PIN,
};
struct rt_i2c_bus_device device1 =
{
.ops = &raspi_i2c_ops,
.priv = (void *)&hw_device1,
};
#endif
int rt_hw_i2c_init(void)
{
#if defined(BSP_USING_I2C0)
rt_i2c_bus_device_register(&device0, I2C0_BUS_NAME);
#endif
#if defined(BSP_USING_I2C1)
rt_i2c_bus_device_register(&device1, I2C1_BUS_NAME);
#endif
return 0;
}
INIT_DEVICE_EXPORT(rt_hw_i2c_init);
oled显示代码:
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
#define SSD1306_I2C_BUS_NAME "i2c1"
#define SSD1306_ADDR 0x3c
#define SSD1306_CTRL_CMD 0x00
#define SSD1306_CTRL_DATA 0x40
const unsigned char ucSmallFonts[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x06, 0x00, 0x07, 0x03, 0x00, 0x07,
0x03, 0x24, 0x7e, 0x24, 0x7e, 0x24, 0x24, 0x2b, 0x6a, 0x12, 0x00, 0x63, 0x13, 0x08, 0x64, 0x63, 0x36, 0x49,
0x56, 0x20, 0x50, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x41, 0x00, 0x00, 0x00, 0x41, 0x3e, 0x00, 0x00,
0x08, 0x3e, 0x1c, 0x3e, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0xe0, 0x60, 0x00, 0x00, 0x08, 0x08, 0x08,
0x08, 0x08, 0x00, 0x60, 0x60, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x51, 0x49, 0x45, 0x3e, 0x00,
0x42, 0x7f, 0x40, 0x00, 0x62, 0x51, 0x49, 0x49, 0x46, 0x22, 0x49, 0x49, 0x49, 0x36, 0x18, 0x14, 0x12, 0x7f,
0x10, 0x2f, 0x49, 0x49, 0x49, 0x31, 0x3c, 0x4a, 0x49, 0x49, 0x30, 0x01, 0x71, 0x09, 0x05, 0x03, 0x36, 0x49,
0x49, 0x49, 0x36, 0x06, 0x49, 0x49, 0x29, 0x1e, 0x00, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0xec, 0x6c, 0x00, 0x00,
0x08, 0x14, 0x22, 0x41, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x41, 0x22, 0x14, 0x08, 0x02, 0x01, 0x59,
0x09, 0x06, 0x3e, 0x41, 0x5d, 0x55, 0x1e, 0x7e, 0x11, 0x11, 0x11, 0x7e, 0x7f, 0x49, 0x49, 0x49, 0x36, 0x3e,
0x41, 0x41, 0x41, 0x22, 0x7f, 0x41, 0x41, 0x41, 0x3e, 0x7f, 0x49, 0x49, 0x49, 0x41, 0x7f, 0x09, 0x09, 0x09,
0x01, 0x3e, 0x41, 0x49, 0x49, 0x7a, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x41, 0x7f, 0x41, 0x00, 0x30, 0x40,
0x40, 0x40, 0x3f, 0x7f, 0x08, 0x14, 0x22, 0x41, 0x7f, 0x40, 0x40, 0x40, 0x40, 0x7f, 0x02, 0x04, 0x02, 0x7f,
0x7f, 0x02, 0x04, 0x08, 0x7f, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x7f, 0x09, 0x09, 0x09, 0x06, 0x3e, 0x41, 0x51,
0x21, 0x5e, 0x7f, 0x09, 0x09, 0x19, 0x66, 0x26, 0x49, 0x49, 0x49, 0x32, 0x01, 0x01, 0x7f, 0x01, 0x01, 0x3f,
0x40, 0x40, 0x40, 0x3f, 0x1f, 0x20, 0x40, 0x20, 0x1f, 0x3f, 0x40, 0x3c, 0x40, 0x3f, 0x63, 0x14, 0x08, 0x14,
0x63, 0x07, 0x08, 0x70, 0x08, 0x07, 0x71, 0x49, 0x45, 0x43, 0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x02, 0x04,
0x08, 0x10, 0x20, 0x00, 0x41, 0x41, 0x7f, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x80, 0x80, 0x80, 0x80, 0x80,
0x00, 0x03, 0x07, 0x00, 0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x7f, 0x44, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44,
0x44, 0x28, 0x38, 0x44, 0x44, 0x44, 0x7f, 0x38, 0x54, 0x54, 0x54, 0x08, 0x08, 0x7e, 0x09, 0x09, 0x00, 0x18,
0xa4, 0xa4, 0xa4, 0x7c, 0x7f, 0x04, 0x04, 0x78, 0x00, 0x00, 0x00, 0x7d, 0x40, 0x00, 0x40, 0x80, 0x84, 0x7d,
0x00, 0x7f, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x00, 0x7c, 0x04, 0x18, 0x04, 0x78, 0x7c, 0x04,
0x04, 0x78, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0xfc, 0x44, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0xfc,
0x44, 0x78, 0x44, 0x04, 0x08, 0x08, 0x54, 0x54, 0x54, 0x20, 0x04, 0x3e, 0x44, 0x24, 0x00, 0x3c, 0x40, 0x20,
0x7c, 0x00, 0x1c, 0x20, 0x40, 0x20, 0x1c, 0x3c, 0x60, 0x30, 0x60, 0x3c, 0x6c, 0x10, 0x10, 0x6c, 0x00, 0x9c,
0xa0, 0x60, 0x3c, 0x00, 0x64, 0x54, 0x54, 0x4c, 0x00, 0x08, 0x3e, 0x41, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00,
0x00, 0x00, 0x41, 0x41, 0x3e, 0x08, 0x02, 0x01, 0x02, 0x01, 0x00, 0x3c, 0x26, 0x23, 0x26, 0x3c };
/*i2c总线设备句柄*/
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
static rt_bool_t initialized = RT_FALSE;
static int ssd1306_init(const char *name){
i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
if (i2c_bus == RT_NULL)
{
rt_kprintf("can't find %s device!\n", name);
return RT_ERROR;}
else{
rt_kprintf("find %s device!\n", name);
return RT_EOK;}
}
static rt_err_t write_position(struct rt_i2c_bus_device *bus, rt_uint8_t *data, int len)
{
rt_uint8_t buf[4];
struct rt_i2c_msg msgs;
rt_uint32_t buf_size = len;
buf[0] = data[0]; //cmd
if (data != RT_NULL)
{
buf[1] = data[1];
buf[2] = data[2];
buf[3] = data[3];
buf_size = len;}
msgs.addr = SSD1306_ADDR;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = buf_size;
/* 调用I2C设备接口传输数据 */
if (rt_i2c_transfer(bus, &msgs, 1) == 1)
{
return RT_EOK;}
else
{
return -RT_ERROR;}
}
static void set_position(int x, int y)
{
unsigned char temp[4];
temp[0] = SSD1306_CTRL_CMD;
temp[1] = 0xb0 | y;
temp[2] = x & 0xf;
temp[3] = 0x10 | (x >> 4);
write_position(i2c_bus, temp, 4);
}
static rt_err_t write_data(struct rt_i2c_bus_device *bus, rt_uint8_t *data, int len)
{
rt_uint8_t buf[129];
struct rt_i2c_msg msgs;
msgs.addr = SSD1306_ADDR;
msgs.flags = RT_I2C_WR;
msgs.buf = data;
msgs.len = len;
if (rt_i2c_transfer(bus, &msgs, 1) == 1)
{
return RT_EOK;}
else
{
return -RT_ERROR;}
}
static void set_data(int x, int y, char *src){
unsigned char c, ucTemp[40], Temp[129];
int i = 0, ilen = 6;
while(src != 0){
c = src - 32;
ucTemp[0] = SSD1306_CTRL_CMD;
memcpy(&ucTemp[1], &ucSmallFonts[(int) c * 5], 5);
Temp[0] = 0x40;
memcpy(&Temp[1], ucTemp, ilen);
write_data(i2c_bus, Temp, ilen+1);
i++;}
}
static int write_cmd(struct rt_i2c_bus_device *bus, char type, char byte){
rt_uint8_t buf[2];
struct rt_i2c_msg msgs;
rt_uint32_t buf_size = 2;
buf[0] = type; //cmd
buf[1] = byte;
msgs.addr = SSD1306_ADDR;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = buf_size;
if (rt_i2c_transfer(bus, &msgs, 1) == 1)
{
return RT_EOK;}
else
{
return -RT_ERROR;}
}
/* 清屏 */
static void clear_screen(){
int i,n;
for(int i=0;i<8;i++){
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xB0+i);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x10);
for(n=0;n<128;n++){
write_cmd(i2c_bus, SSD1306_CTRL_DATA, 0);}
}
}
/* oled设备初始化 */
static void init(){
rt_thread_mdelay(100);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xAE);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x20);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xB0);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xC8);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x10);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x40);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xFF);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA1);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA6);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA8);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x3F);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xA4);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xD3);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x00);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xD5);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xF0);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xD9);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x22);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xDA);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x12);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xDB);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x20);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x8D);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0x14);
write_cmd(i2c_bus, SSD1306_CTRL_CMD, 0xAF);
}
static void i2c_ssd1306(int argc, char* argv[]){
char name[RT_NAME_MAX];
if(argc ==3){
rt_strncpy(name, argv[1], RT_NAME_MAX);}
else{
rt_strncpy(name, SSD1306_I2C_BUS_NAME, RT_NAME_MAX);}
if (!initialized)
{
int rc;
rc = ssd1306_init(name);
if(rc){return;}}
char *str = argv[2];
rt_kprintf("argv[2]:%s\n",argv[2]);
init();
clear_screen();
set_position(0,1);
set_data(0, 1, argv[2]);
}
MSH_CMD_EXPORT(i2c_ssd1306, i2c SSD1306 sample);
————————————————
版权声明:本文为CSDN博主「weixin_42734533」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42734533/article/details/131815804
|
|