STM32移植u8g2库(HAL库)(硬件SPI)(sh1106_128x64)

MCU型号为STM32F103RCT6,OLED屏为中景园电子1.3寸屏,驱动芯片为sh1106,分辨率为128x64,MDK版本为V5.34。

在移植过程中主要参考了以下三篇文章,对作者的分享表示感谢。

第一个

第二个

第三个

首先移植的基础是已经通过cubeMX生成了HAL库版本的硬件SPI和GPIO初始化等需要的代码,具体生成的过程不赘述。

下载u8g2库

github地址

在这里即可下载最新版的库文件。下载好之后需要将src文件夹复制到自己的工程中去。

elua stm32移植 stm32移植grbl_单片机

比如我就放在这里。

elua stm32移植 stm32移植grbl_单片机_02

之后需要在MDK中添加自己需要的文件,因为u8g2为了兼容性提供了许许多多的驱动芯片代码,而我们只需要把自己需要的添加进工程就好了。现有的驱动IC为sh1106,因此就只需要找到这个芯片和分辨率的初始化代码添加就好了。但是SH1106的初始化代码并没有单独列出来,被放在了1306的文件中。

u8x8文件添加了针对1306的文件,而u8g2文件基本都添加了。以下是添加文件的截图,实际上机验证过可以运行的,可以给读者一个参考。

elua stm32移植 stm32移植grbl_stm32_03

然后我们需要在自己的代码中添加两个头文件

#include "u8g2.h"
#include "u8x8.h"

然后就需要去找自己需要的初始化函数了,可以去u8g2.h文件中找。这些文件都是在u8g2_d_setup.c中定义的。

elua stm32移植 stm32移植grbl_elua stm32移植_04

下边声明了大量的初始化函数,找到自己需要的

elua stm32移植 stm32移植grbl_arm_05

至于几个相似的函数可以参考其他文章中的说法:

  • u8g2_Setup_sh1106_128x64_noname_1
  • u8g2_Setup_sh1106_128x64_noname_2
  • u8g2_Setup_sh1106_128x64_noname_f
    使用的缓存大小不一样,f是等大的缓存,如128*64就是1024Byte。那2就是一半

我用哪个都可以正常显示。

因为我们在导入文件的时候是有选择性导入的,而在u8g2_d_setup.c中有很多各种IC的函数,会因为缺少文件而报错,因此需要把没用的函数全注释掉,只剩下选择好的函数。

参考其他文章还需要注释u8g2_d_memory.c文件中的无关函数,但是我不注释也是可以的。

移植的关键是自己编写接下来的几个函数。

如果用软件iic就需要用下面相应的iic初始化函数。但是用硬件的话就需要自己写一个函数来发送数据。

uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,void *arg_ptr)
{
    switch (msg)
    {
        case U8X8_MSG_BYTE_SEND: /*通过SPI发送arg_int个字节数据*/
			HAL_SPI_Transmit(&hspi1,(uint8_t *)arg_ptr,arg_int,200);
            break;
        case U8X8_MSG_BYTE_INIT: /*初始化函数*/
            break;
        case U8X8_MSG_BYTE_SET_DC: /*设置DC引脚,表明发送的是数据还是命令*/
			HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,arg_int);
            break;
        case U8X8_MSG_BYTE_START_TRANSFER: 
            break;
        case U8X8_MSG_BYTE_END_TRANSFER: 
            break;
        default:
            return 0;
    }
    return 1;
}
uint8_t u8x8_stm32_gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8,
    U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int,
    U8X8_UNUSED void *arg_ptr) 
{
    switch (msg)
    {
        case U8X8_MSG_GPIO_AND_DELAY_INIT: /*delay和GPIO的初始化,在main中已经初始化完成了*/
            break;
        case U8X8_MSG_DELAY_MILLI: /*延时函数*/
            HAL_Delay(arg_int);
            break;
        case U8X8_MSG_GPIO_CS: /*片选信号*/
            break;
        case U8X8_MSG_GPIO_DC: /*设置DC引脚,表明发送的是数据还是命令*/
            HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,arg_int);
            break;
        case U8X8_MSG_GPIO_RESET:
            break;
    }
    return 1;
}uint8_t u8x8_stm32_gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8,
    U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int,
    U8X8_UNUSED void *arg_ptr) 
{
    switch (msg)
    {
        case U8X8_MSG_GPIO_AND_DELAY_INIT: /*delay和GPIO的初始化,在main中已经初始化完成了*/
            break;
        case U8X8_MSG_DELAY_MILLI: /*延时函数*/
            HAL_Delay(arg_int);
            break;
        case U8X8_MSG_GPIO_CS: /*片选信号*/
            break;
        case U8X8_MSG_GPIO_DC: /*设置DC引脚,表明发送的是数据还是命令*/
            HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,arg_int);
            break;
        case U8X8_MSG_GPIO_RESET:
            break;
    }
    return 1;
}

这两个函数写完了就已经基本完成了,在调用初始化函数时,初始化函数的两个参数需要替换成成上面的两个函数

void u8g2Init(u8g2_t *u8g2)
{
	/*U8G2_R0 :屏幕旋转/镜像
	U8G2_R0
	U8G2_R1
	U8G2_R2
	U8G2_R3
	U8G2_MIRROR   u8g2_Setup_sh1106_128x64_noname_1
	*/
	u8g2_Setup_sh1106_128x64_noname_2(u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8x8_stm32_gpio_and_delay);  // 初始化 u8g2 结构体
	u8g2_InitDisplay(u8g2); 
	u8g2_SetPowerSave(u8g2, 0); //开启显示
}

再附加一个绘制官方logo的程序

/*官方提供的Logo绘制demo*/
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中调用了,前面该初始化的都初始化好。

u8g2_t u8g2; // 它将包含一个显示器的所有数据


	OLED_RST_Set(); //复位拉高
	u8g2Init(&u8g2);
  while (1)
  {
    /* USER CODE END WHILE */
	u8g2_FirstPage(&u8g2);
       do
       {
   			draw(&u8g2);
       } while (u8g2_NextPage(&u8g2));
  }

最终结果:

elua stm32移植 stm32移植grbl_初始化_06

整个工程已上传。

工程文档