手头正好有一块0.96寸的OLED屏,驱动芯片为ssd1306,心想怎么才能显示更为炫彩的图像。无意间,接触到U8g2图形库,遂决定将其移植到自己的工程中。
U8g2 是一个用于嵌入式设备的单色图形库。U8g2支持单色OLED和LCD,并支持如SSD1306等多种类型的OLED驱动。
github下载地址
我这块屏是i2c接口的,u8g2即支持软件模拟i2c,也支持硬件i2c。之前的工程里关于PC6 PC7软硬件i2c都有适配,这里用模拟i2c,因为简单,bug少啊。
软件i2c pc6 pc7gpio的配置代码如下:
void BOARD_I2C1_Init(void)
{
#if I2C_MODE == USE_HARD_I2C
GPIO_Init_Type gpio_init;
/* PC6 - I2C1_SCL. */
gpio_init.Pins = GPIO_PIN_6;
gpio_init.PinMode = GPIO_PinMode_AF_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, gpio_init.Pins, GPIO_AF_4);
/* PC7 - I2C1_SDA. */
gpio_init.Pins = GPIO_PIN_7;
gpio_init.PinMode = GPIO_PinMode_AF_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, gpio_init.Pins, GPIO_AF_4);
/* Setup I2C initialization values. */
I2C_Master_Init_Type i2c_init;
i2c_init.ClockFreqHz = CLOCK_APB1_FREQ;
i2c_init.BaudRate = I2C_BaudRate_100K;
/* Initialize I2C master. */
I2C_InitMaster(I2C1, &i2c_init);
/* The target device address needs to be configured before enabling. */
I2C_SetTargetAddr(I2C1, MSA311_I2CADDR_DEFAULT_7);
/* Enable I2C. */
I2C_Enable(I2C1, true);
#elif I2C_MODE == USER_SW_I2C
GPIO_Init_Type gpio_init;
gpio_init.Pins = SWI2C1_SCL_PIN;
gpio_init.PinMode = GPIO_PinMode_Out_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(SWI2C1_SCL_PORT, &gpio_init);
GPIO_PinAFConf(SWI2C1_SCL_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */
/* PC7 - I2C1_SDA. */
gpio_init.Pins = SWI2C1_SDA_PIN;
gpio_init.PinMode = GPIO_PinMode_Out_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */
SWI2C1_SDA_HIGH;
SWI2C1_SCL_HIGH;
#endif
}
.h文件
#define I2C_MODE USER_SW_I2C
#if I2C_MODE == USER_SW_I2C
// PC6 scl PC7 sda
#define SWI2C1_SCL_PORT GPIOC
#define SWI2C1_SCL_PIN GPIO_PIN_6
#define SWI2C1_SCL_HIGH GPIO_WriteBit(SWI2C1_SCL_PORT,SWI2C1_SCL_PIN,1u)
#define SWI2C1_SCL_LOW GPIO_WriteBit(SWI2C1_SCL_PORT,SWI2C1_SCL_PIN,0u)
#define SWI2C1_SDA_PORT GPIOC
#define SWI2C1_SDA_PIN GPIO_PIN_7
#define SWI2C1_SDA_HIGH GPIO_WriteBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN,1u)
#define SWI2C1_SDA_LOW GPIO_WriteBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN,0u)
#define SWI2C1_SDA_READ GPIO_ReadInDataBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN)
#define BIT0 0x01
#define BIT7 0x80
#endif
注意将gpio设置为开漏模式。
将下载的u8g2解压,我们只需要csrc文件夹的文件,其余可以先不关注。
由于u8g2支持的驱动种类繁多,所以我们只需要找到我们对应的驱动文件即可。
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch (msg) {
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
__NOP();
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
for (uint16_t n = 0; n < 320; n++)
__NOP();
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
BOARD_Delay1Ms(1);
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
BOARD_Delay1Us(3);
break; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
arg_int ? GPIO_WriteBit(SWI2C1_SCL_PORT,SWI2C1_SCL_PIN,1u) : GPIO_WriteBit(SWI2C1_SCL_PORT,SWI2C1_SCL_PIN,0u);
break; // arg_int=1: Input dir with pullup high for I2C clock pin
case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
arg_int ? GPIO_WriteBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN,1u) : GPIO_WriteBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN,0u);
break; // arg_int=1: Input dir with pullup high for I2C data pin
case U8X8_MSG_GPIO_MENU_SELECT:
u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);
break;
case U8X8_MSG_GPIO_MENU_NEXT:
u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);
break;
case U8X8_MSG_GPIO_MENU_PREV:
u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);
break;
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);
break;
default:
u8x8_SetGPIOResult(u8x8, 1); // default return value
break;
}
return 1;
}
主要是延时函数,以及scl sda对应的gpio的控制。
void u8g2Init(u8g2_t *u8g2)
{
u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay); // 初始化 u8g2 结构体
u8g2_InitDisplay(u8g2); // 根据所选的芯片进行初始化工作,初始化完成后,显示器处于关闭状态
u8g2_SetPowerSave(u8g2, 0); // 打开显示器
u8g2_ClearBuffer(u8g2);
}
void draw(u8g2_t *u8g2)
{
u8g2_SetFontMode(u8g2, 1); /*字体模式选择*/
u8g2_SetFontDirection(u8g2, 0); /*字体方向选择*/
u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/
u8g2_DrawStr(u8g2, 0, 20, "U");
u8g2_SetFontDirection(u8g2, 1);
u8g2_SetFont(u8g2, u8g2_font_inb30_mn);
u8g2_DrawStr(u8g2, 21,8,"8");
u8g2_SetFontDirection(u8g2, 0);
u8g2_SetFont(u8g2, u8g2_font_inb24_mf);
u8g2_DrawStr(u8g2, 51,30,"g");
u8g2_DrawStr(u8g2, 67,30,"\xb2");
u8g2_DrawHLine(u8g2, 2, 35, 47);
u8g2_DrawHLine(u8g2, 3, 36, 47);
u8g2_DrawVLine(u8g2, 45, 32, 12);
u8g2_DrawVLine(u8g2, 46, 33, 12);
u8g2_SetFont(u8g2, u8g2_font_4x6_tr);
u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");
}
main函数调用:
// BOARD_InitPins();
u8g2_t u8g2;
u8g2Init(&u8g2);
while(1)
{
// Msa311_GetXYZData();
// BOARD_Delay1Ms(1000);
u8g2_FirstPage(&u8g2);
do
{
draw(&u8g2);
} while (u8g2_NextPage(&u8g2));
}
烧录后,可以看见u8g2官方的logo了。
移植好的代码