u8g2 是一个在嵌入式中使用的开源的单色图形库,支持单色 OLED和 LCD,目前支持的设备有:SSD1305, SSD1306, SSD1309, SSD1322, SSD1325, SSD1327, SSD1329, SSD1606, SSD1607, SH1106, SH1107, SH1108, SH1122, T6963, RA8835, LC7981, PCD8544, PCF8812, HX1230, UC1601, UC1604, UC1608, UC1610, UC1611, UC1701, ST7565, ST7567, ST7588, ST75256, NT7534, IST3020, ST7920, LD7032, KS0108, SED1520, SBN1661, IL3820, MAX7219 等
官方资源有:
- 源码:u8g2 github
- 文档、说明:u8g2 wiki
- gallery:这里展示了很多例子
获取源码:
直接 git clone 获取:
下载下来如下:
0.96 OLED,SSD1306 128X64,SPI 接口
把 u8g2 源码放到工程目录下面,然后开始移植。
添加源文件,u8g2 相关源码主要放在 u8g2 目录中 csrc 中,该目录中不止有 u8g2 图形相关源码,还有屏的驱动,添加源码的时候除了添加 u8g2 相关源码外,还需要添加所使用 屏的驱动,根据我所使用的屏,添加源码如下:
添加包含路径
这里使用模拟SPI,定义所使用 IO 口宏,并实现初始化函数:
#define U8G2_DC_PIN GPIO_PIN_10
#define U8G2_DC_PORT GPIOB
#define U8G2_CS_PIN GPIO_PIN_11
#define U8G2_CS_PORT GPIOB
#define U8G2_RST_PIN GPIO_PIN_1
#define U8G2_RST_PORT GPIOB
#define U8G2_D1_PIN GPIO_PIN_0
#define U8G2_D1_PORT GPIOB
#define U8G2_D0_PIN GPIO_PIN_7
#define U8G2_D0_PORT GPIOA
#define U8G2_D0_LOW() gpio_bit_reset (U8G2_D0_PORT, U8G2_D0_PIN)
#define U8G2_D0_HIGH() gpio_bit_set(U8G2_D0_PORT, U8G2_D0_PIN)
#define U8G2_D1_LOW() gpio_bit_reset(U8G2_D1_PORT, U8G2_D1_PIN)
#define U8G2_D1_HIGH() gpio_bit_set(U8G2_D1_PORT, U8G2_D1_PIN)
#define U8G2_DC_LOW() gpio_bit_reset (U8G2_DC_PORT, U8G2_DC_PIN)
#define U8G2_DC_HIGH() gpio_bit_set(U8G2_DC_PORT, U8G2_DC_PIN)
#define U8G2_CS_LOW() gpio_bit_reset(U8G2_CS_PORT, U8G2_CS_PIN)
#define U8G2_CS_HIGH() gpio_bit_set(U8G2_CS_PORT, U8G2_CS_PIN)
#define U8G2_RST_LOW() gpio_bit_reset(U8G2_RST_PORT, U8G2_RST_PIN)
#define U8G2_RST_HIGH() gpio_bit_set(U8G2_RST_PORT, U8G2_RST_PIN)
void gd32_u8g2_io_init(void)
{
gpio_mode_set(U8G2_D0_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U8G2_D0_PIN);
gpio_output_options_set(U8G2_D0_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U8G2_D0_PIN);
gpio_mode_set(U8G2_D1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U8G2_D1_PIN);
gpio_output_options_set(U8G2_D1_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U8G2_D1_PIN);
gpio_mode_set(U8G2_DC_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U8G2_DC_PIN);
gpio_output_options_set(U8G2_DC_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U8G2_DC_PIN);
gpio_mode_set(U8G2_CS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U8G2_CS_PIN);
gpio_output_options_set(U8G2_CS_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U8G2_CS_PIN);
gpio_mode_set(U8G2_RST_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U8G2_RST_PIN);
gpio_output_options_set(U8G2_RST_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U8G2_RST_PIN);
}
实现操作 IO 口的回调函数:
u8g2_t u8g2;
void delay_ns(uint32_t delay)
{
uint32_t i=0,j=0;
for(i=0;i<delay;i++)
for(j=0;j<10;j++)
__NOP();
}
uint8_t u8x8_gd32_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch(msg)
{
case U8X8_MSG_DELAY_MILLI:
delay_1ms(arg_int);
break;
default:
return 0;
}
return 1;
}
uint8_t u8x8_gd32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch(msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT:
gd32_u8g2_io_init();
break;
case U8X8_MSG_GPIO_SPI_CLOCK:
if(arg_int)
U8G2_D0_HIGH();
else
U8G2_D0_LOW();
break;
case U8X8_MSG_GPIO_SPI_DATA:
if(arg_int)
U8G2_D1_HIGH();
else
U8G2_D1_LOW();
break;
case U8X8_MSG_GPIO_CS:
if(arg_int)
U8G2_CS_HIGH();
else
U8G2_CS_LOW();
break;
case U8X8_MSG_GPIO_DC:
if(arg_int)
U8G2_DC_HIGH();
else
U8G2_DC_LOW();
break;
case U8X8_MSG_GPIO_RESET:
if(arg_int)
U8G2_RST_HIGH();
else
U8G2_RST_LOW();
break;
default:
if (u8x8_gd32_delay(u8x8, msg, arg_int, arg_ptr))
return 1;
u8x8_SetGPIOResult(u8x8, 1);
break;
}
return 1;
}
调用相关初始化函数,并写个测试程序:
void ssd1306_128X64_u8g2_init(void)
{
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi , u8x8_gd32_gpio_and_delay);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_helvR12_tf);
u8g2_DrawStr(&u8g2, 0,32, "U8g2 on GD32");
u8g2_DrawStr(&u8g2, 60, 56, "By Halin");
u8g2_SendBuffer(&u8g2);
}
编译运行:
再来个,在 OLED 上显示计数,先实现个显示 2 位数的程序:
#define X_P 45
#define Y_P 49
void show_num(uint8_t Num)
{
char buf[2] = {0};
uint8_t temp =0;
temp = (Num) / 10;
buf[0] = temp +'0';
temp = (Num) % 10;
buf[1] = temp +'0';
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2, X_P,Y_P, buf);
u8g2_SendBuffer(&u8g2);
}
然后在主循环里面计数,并显示:
int main(void)
{
uint8_t counter = 0;
systick_config();
rcu_periph_clock_enable(RCU_GPIOB);
led_init();
u8g2_sw_spi_io_init();
ssd1306_128X64_u8g2_init();
while (1){
GPIO_TG(GPIOF) = GPIO_PIN_6;
delay_1ms(500);
show_num(counter);
counter ++;
if(counter > 100)
counter = 0;
}
}
原作者:哈拎