本帖最后由 开发板 于 2024-1-7 21:31 编辑
废话少说,先上源码
点击直达项目链接
为了减少接线我选择了I2C接口的OELD模块。由于手头没有合适的转接线连接小安派和OLED,所以我把J9连接器拆了焊了4根杜邦线连接屏幕
移植完成后显示效果图如下
开发环境我使用的是博流官方SDK。源码编译很简单,搭建好开发环境后添加环境变量BL_SDK_BASE,路径为博流SDK根目录,直接make即可。WIN下添加环境变量如图
Linux在~/.bashrc添加
export BL_SDK_BASE="/home/$USER/bl_mcu_sdk"
将其中的路径换为自己的SDK所在路径即可。
接下来是移植步骤。
首先下载U8G2的源码
项目链接
点击Download ZIP即可
U8G2提供C和C++两个版本的源码,这里选择C版本。解压下载的zip,其中csrc文件夹下即为C语言版本的源码。在M61工程中新建oled文件夹,将csrc下的文件添加到工程中。
以u8x8_d_xxx.c的文件命名的文件只保留u8x8_d_ssd1306_128x64_noname.c,其他全部删掉(注意不要把u8g2_d_setup.c和u8g2_d_memory.c删了)
编辑u8g2_d_setup.c,保留需要的初始化函数,其他全部注释掉。因为我用的屏是I2C接口,所以保留 u8g2_Setup_ssd1306_i2c_128x64_noname_f
函数。
之后编辑u8g2_d_memory.c。同样只保留需要的函数,其他全部注释掉。u8g2_Setup_ssd1306_i2c_128x64_noname_f函数调用了u8g2_m_16_8_f函数,所以这里我要保留的函数就是u8g2_m_16_8_f。
之后新建oled.c和oled.h。在oled.c中首先新建初始化I2C相关的代码。
struct bflb_device_s *i2c0; //i2c0外设句柄
struct bflb_i2c_msg_s msgs; //I2C发送数据结构体数组
//初始化I2C引脚
void I2c0_gpio_init(void)
{
struct bflb_device_s* gpio;
gpio = bflb_device_get_by_name("gpio");
/* I2C0_SCL */
bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
/* I2C0_SDA */
bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
}
//初始化I2C
void I2c0_init(void)
{
I2c0_gpio_init();
i2c0 = bflb_device_get_by_name("i2c0");
//I2C初始化
bflb_i2c_init(i2c0, 400000);
}
之后新建OLED初始化函数,也就是u8g2初始化函数。
//OLED初始化函数
void OLED_Init(void)
{
u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2,0);
u8g2_ClearBuffer(&u8g2);
}
其中重点就是u8g2_Setup_ssd1306_i2c_128x64_noname_f函数,我们来看一下函数原型。
void u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
函数第一个参数为u8g2的句柄;第二个代表屏幕方向,这里填入U8G2_R0;第三个参数需要我们创建一个回调函数供u8g2使用,这里参照u8g2官方给出的模板创建了u8x8_byte_hw_i2c函数,这个函数稍后提到;第四个参数同样需要提供一个回调函数供u8g2使用,这里创建u8x8_gpio_and_delay函数。
接下来就是完善u8x8_byte_hw_i2c函数。参照官方模板创建该函数后,里面有以下部分需要我们自己完成。首先是case U8X8_MSG_BYTE_INIT,这里需要填入接口初始化函数,这里填入之前写的I2C初始化函数I2c0_init;case U8X8_MSG_BYTE_END_TRANSFER下需要填入发送数据的函数,这里我们填入I2C发送数据相关内容。完整函数如下
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
static uint8_t buffer[128];
static uint8_t buf_idx;
uint8_t *data;
switch (msg)
{
case U8X8_MSG_BYTE_INIT:
{
/*初始化I2C*/
I2c0_init();
}
break;
case U8X8_MSG_BYTE_START_TRANSFER:
{
buf_idx = 0;
}
break;
case U8X8_MSG_BYTE_SEND:
{
data = (uint8_t *)arg_ptr;
while (arg_int > 0)
{
buffer[buf_idx++] = *data;
data++;
arg_int--;
}
}
break;
case U8X8_MSG_BYTE_END_TRANSFER:
{
/*I2C发送数据*/
msgs.addr = OLED_ADDRESS;
msgs.buffer=buffer;
msgs.flags=0;
msgs.length= buf_idx;
bflb_i2c_transfer(i2c0, &msgs, 1);
}
break;
// case U8X8_MSG_BYTE_SET_DC:
// break;
default:
return 0;
}
return 1;
}
之后是u8x8_gpio_and_delay函数。u8g2自带模拟协议时序,这个函数就是u8g2模拟时序情况下使用的。由于我这里使用了硬件I2C,所以用不到该函数,直接全部注释掉即可。
u8g2到这里就移植完成了。之后直接在main函数里调用OLED_Init函数即可完成u8g2的初始化,然后就可以尽情绘制GUI了。