作为一个单片机开发者,平时最喜欢的外设就是各种各样的屏幕。可是在使用单色屏时,网络上常见的驱动程序大多只是显示几个标准字符,相比之下,各种商业产品使用同样的屏幕,同样可以显示出多样的图形效果,让人艳羡不已。
nt7534_tg12864r.jpg
u8g2作为一个适用于嵌入式设备的轻量级单色图形库,极大地解决了这个问题,它支持近 200 种单色屏,该显示库支持多种字体,具有完整的图形功能(直线、圆形、斜线、字符旋转、镜像反白、bitmap一应俱全),并具备很强的可移植性。u8g2开源项目在github上拥有1400+ Stars1900+ Commits和众多的维护者
进入正题,本节我们将在ufun开发板上使用u8g2驱动SSD1306 OLED显示屏,驱动方式为I2C
在上一节工程的基础上,我们只需添加I2C驱动与u8g2相关文件即可。
第一步、github下载u8g2工程。
Github地址如下:
    https://github.com/olikraus/u8g2/wiki
第二步、打开STM32CubeMX,配置工程
在上一节LED工程的基础上,我们添加I2C的驱动即可,其他配置保持不变。
IIC管脚.jpg
I2C配置如下,为了保证高刷新率,我们将I2C速度置为Fast Mode
配置IIC.jpg
接下来生成工程即可。
第三步、修改MDK工程
打开MDK工程目录,将u8g2源代码的csrc目录复制到MDK工程目录下,将其重命名为libu8g2
目录1.jpg
目录2.jpg
接下来,在MDK中添加u8g2源文件。
添加源文件.jpg
并添加头文件路径。
添加目录.jpg
第四步、增加移植代码
移植u8g2库,我们需要自己添加两个函数,一个是I2C底层驱动接口,另一个是延时函数接口。我们创建一个新的文件“u8x8_stm32_HAL.c”和“u8x8_stm32_HAL.h”来存放这两个接口函数。
实现代码如下:
u8x8_stm32_HAL.c
/*
  •   ******************************************************************************
  •   * File Name          : u8x8_stm32_HAL.c
  •   * Description        : Porting Codes
  •   ******************************************************************************
  •   * spezifische Anweisungen zw. u8g2/u8x8 und stm32
  •   * Hal-Driver im Einsatz
  •   ******************************************************************************
  • */
  • #include "u8g2.h"
  • #include "stm32f1xx_hal.h"
  • #include "u8x8_stm32_HAL.h"
  • uint8_t u8x8_stm32_gpio_and_delay_cb(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
  • {
  •   switch(msg)                                                        // there is no need for any delay
  •   {
  •     case U8X8_MSG_GPIO_AND_DELAY_INIT:        // called once during init phase of u8g2/u8x8 -> Make with HAL_init
  •       break;                                                        // can be used to setup pins
  •     case U8X8_MSG_DELAY_NANO:                        // delay arg_int * 1 nano second
  •       break;   
  •     case U8X8_MSG_DELAY_100NANO:                // delay arg_int * 100 nano seconds
  •      break;
  •     case U8X8_MSG_DELAY_10MICRO:                // delay arg_int * 10 micro seconds
  •      break;
  •     case U8X8_MSG_DELAY_MILLI:                        // delay arg_int * 1 milli second
  •      break;
  •     case U8X8_MSG_DELAY_I2C:                        // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
  •      break;                                                        // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
  •     case U8X8_MSG_GPIO_D0:                                // D0 or SPI clock pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D1:                                // D1 or SPI data pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D2:                                // D2 pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D3:                                // D3 pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D4:                                // D4 pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D5:                                // D5 pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D6:                                // D6 pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_D7:                                // D7 pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_E:                                // E/WR pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_CS:                                // CS (chip select) pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_DC:                                // DC (data/cmd, A0, register select) pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_RESET:                        // Reset pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_CS1:                                // CS1 (chip select) pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_CS2:                                // CS2 (chip select) pin: Output level in arg_int
  •       break;
  •     case U8X8_MSG_GPIO_I2C_CLOCK:                // arg_int=0: Output low at I2C clock pin
  •       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
  •       break;                                                        // arg_int=1: Input dir with pullup high for I2C data pin
  •   }
  •   return 1;
  • }
  • uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  • {
  •   uint8_t *ptr;
  •   static uint8_t buffer_count;
  •   static uint8_t buffer[DATA_BUFFER_SIZE+1];        //the size of buffer depends on how many pages are transfered at once
  •                                                                                                                         //e.g. one page are 128byte and one byte more for command
  •   switch(msg)
  •   {
  •     case U8X8_MSG_BYTE_SEND:                                        //collect
  •       {   ptr = arg_ptr;
  •               for (int i=1; i <= arg_int; i++)
  •               {          buffer[buffer_count] = *(ptr++);
  •                       buffer_count++;
  •               }
  •       }
  •       break;
  •     case U8X8_MSG_BYTE_INIT:
  •       break;
  •     case U8X8_MSG_BYTE_SET_DC:
  •       break;
  •     case U8X8_MSG_BYTE_START_TRANSFER:
  •             buffer_count = 0;                                                // start
  •       break;
  •     case U8X8_MSG_BYTE_END_TRANSFER:                        // send all at once
  •              HAL_I2C_Master_Transmit(&I2C_HANDLER, DEVICE_ADDRESS, (uint8_t *)buffer, buffer_count, I2C_TIMEOUT);
  •       break;
  •     default:
  •       return 0;
  •   }
  •   return 1;
  • }
  • 复制代码
    u8x8_stm32_HAL.h
    #ifndef _U8X8_STM32_HAL_H
  • #define _U8X8_STM32_HAL_H
  •    
  •    
  • #include "u8g2.h"
  • #include "stm32f1xx_hal.h"
  •    
  • #define DATA_BUFFER_SIZE 128         //the size of buffer depends on how many pages are transfered at once e.g. one page are 128byte
  • #define I2C_TIMEOUT 1000
  • #define DEVICE_ADDRESS 0x78         //device address is added
  • #define I2C_HANDLER hi2c1
  •    
  • extern I2C_HandleTypeDef hi2c1; // use your i2c handler
  •    
  •    
  • uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
  • uint8_t u8x8_stm32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
  •    
  • #endif  
  • 复制代码
    最后我们在main函数里添加初始化及示例代码。
    初始化代码.jpg
    代码1.jpg
    最后编译烧写程序,OLED屏幕即可顺利驱动。
    2345截图20191021211556.jpg
    PS:完整工程将在最后一节开源。

    【新UFUN试用体验】制作ufun开源小游戏机(一):LED指示灯
    【新UFUN试用体验】制作ufun开源小游戏机(二):移植u8g2图形库驱动OLED屏
    【新UFUN试用体验】制作ufun开源小游戏机(三):移植游戏,制作完成