U8G2是一个开源的单色图形显示库,除了在arduino框架下使用外,U8G2还在GitHub上上传了所有的源码,方便我们移植到其他平台(源码地址)我手上的lcd屏幕为st7567驱动,目前该驱动的移植资料较少,所以发出来供大家参考。
文章目录
一、提示
移植st7567驱动的lcd的方法与ssd1306驱动芯片的OLED的移植方法大体相同,具体可看这篇文章文章地址,本文仅指出不同点。
二、去掉无用的驱动文件
下载源码后,我们仅需要留下st7567的驱动文件并导入即可。
三、修改u8g2_d_setup.c
根据我的尝试,发现只有使用SPI通信协议的初始化函数可用,所以我们保留使用SPI的初始化函数,如下,其他可删除
void u8g2_Setup_st7567_jlx12864_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{
uint8_t tile_buf_height;
uint8_t *buf;
u8g2_SetupDisplay(u8g2, u8x8_d_st7567_jlx12864, u8x8_cad_001, byte_cb, gpio_and_delay_cb);
buf = u8g2_m_16_8_f(&tile_buf_height);
u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}
三、修改u8g2_d_memory.c
u8g2_d_memory.c中的程序不能全部保留,否则单片机会内存爆炸,所以我们仅需要保留u8g2_Setup_st7567_jlx12864_f()函数中使用到的u8g2_m_16_8_f()函数
uint8_t *u8g2_m_16_8_f(uint8_t *page_cnt)
{
#ifdef U8G2_USE_DYNAMIC_ALLOC
*page_cnt = 8;
return 0;
#else
static uint8_t buf[1024];
*page_cnt = 8;
return buf;
#endif
}
四、提供接口函数
我们这里只需要编写u8g2_Setup_st7567_jlx12864_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)中的u8x8_msg_cb gpio_and_delay_cb函数
官方也提供了移植帮助文档(帮助文档地址)
1.初始化GPIO
首先我们先把所有的驱动引脚配置为推挽输出或者上拉输出模式
宏定义:
/* 宏定义 --------------------------------------------------------------------*/
#define PORT_LCD_LED GPIOA
#define PIN_LCD_LED GPIO_Pin_0
#define PORT_LCD_MOSI GPIOA
#define PIN_LCD_MOSI GPIO_Pin_1
#define PORT_LCD_SCK GPIOA
#define PIN_LCD_SCK GPIO_Pin_2
#define PORT_LCD_RST GPIOA
#define PIN_LCD_RST GPIO_Pin_11
#define PORT_LCD_RS GPIOA
#define PIN_LCD_RS GPIO_Pin_12
#define PORT_LCD_CS GPIOA
#define PIN_LCD_CS GPIO_Pin_15
初始化:
void GPIO_Basic_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = PIN_LCD_LED; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率(50M)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出类型(推挽式输出)
GPIO_Init(PORT_LCD_LED, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = PIN_LCD_CS; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率(50M)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出类型(推挽式输出)
GPIO_Init(PORT_LCD_CS, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = PIN_LCD_SCK; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率(50M)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出类型(推挽式输出)
GPIO_Init(PORT_LCD_SCK, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = PIN_LCD_MOSI; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率(50M)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出类型(推挽式输出)
GPIO_Init(PORT_LCD_MOSI, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = PIN_LCD_RS; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率(50M)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输入类型(上拉输出)
GPIO_Init(PORT_LCD_RS, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = PIN_LCD_RST; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率(50M)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输入类型(上拉输出)
GPIO_Init(PORT_LCD_RST, &GPIO_InitStructure);
GPIO_SetBits(PORT_LCD_RST, PIN_LCD_RST);
}
2.编写u8x8_msg_cb gpio_and_delay_cb
这里我将这个函数命名为u8g2_gpio_and_delay_stm32,我们在这个函数中需要提供延时函数接口以及spi和GPIO驱动的函数接口,注意这里使用的是spi通信协议,与iic的代码不同
uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
switch(msg)
{
//Initialize SPI peripheral
case U8X8_MSG_GPIO_AND_DELAY_INIT:
s_spi_init(&lcd_s_spi,PORT_LCD_CS,PIN_LCD_CS,
PORT_LCD_SCK,
PIN_LCD_SCK,
PORT_LCD_MOSI,
PIN_LCD_MOSI,
NULL,
NULL);
break;
//Function which implements a delay, arg_int contains the amount of ms
case U8X8_MSG_DELAY_MILLI:
delay_ms(arg_int);
break;
//Function which delays 10us
case U8X8_MSG_DELAY_10MICRO:
delay_us(arg_int);
break;
//Function which delays 100ns
case U8X8_MSG_DELAY_100NANO:
__NOP();;
break;
//Function to define the logic level of the clockline
case U8X8_MSG_GPIO_SPI_CLOCK:
if(arg_int) GPIO_SetBits(PORT_LCD_SCK, PIN_LCD_SCK);
else GPIO_ResetBits(PORT_LCD_SCK, PIN_LCD_SCK);
break;
//Function to define the logic level of the data line to the display
case U8X8_MSG_GPIO_SPI_DATA:
if(arg_int) GPIO_SetBits(PORT_LCD_MOSI, PIN_LCD_MOSI);
else GPIO_ResetBits(PORT_LCD_MOSI, PIN_LCD_MOSI);
break;
// Function to define the logic level of the CS line
case U8X8_MSG_GPIO_CS:
if(arg_int) GPIO_SetBits(PORT_LCD_CS ,PIN_LCD_CS);
else GPIO_ResetBits(PORT_LCD_CS, PIN_LCD_CS);
break;
//Function to define the logic level of the Data/ Command line
case U8X8_MSG_GPIO_DC:
if(arg_int) GPIO_SetBits(PORT_LCD_RS,PIN_LCD_RS);
else GPIO_ResetBits(PORT_LCD_RS,PIN_LCD_RS);
break;
//Function to define the logic level of the RESET line
case U8X8_MSG_GPIO_RESET:
if(arg_int) GPIO_SetBits(PORT_LCD_RST,PIN_LCD_RST);
else GPIO_ResetBits(PORT_LCD_RST,PIN_LCD_RST);
break;
default:
return 0; //A message was received which is not implemented, return 0 to indicate an error
}
return 1; // command processed successfully.
}
五、U8G2初始化
到了这一步,移植的函数编写已经完成,我们只需要在主函数中添加初始化代码即可完成移植工作
u8g2_Setup_st7567_jlx12864_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8g2_gpio_and_delay_stm32); // 初始化 u8g2 结构体
u8g2_InitDisplay(&u8g2);// 根据所选的芯片进行初始化工作,初始化完成后,显示器处于关闭状态
u8g2_SetPowerSave(&u8g2, 0); // 唤醒显示器
u8g2_SetContrast(&u8g2, 100);//设置对比度
u8g2_ClearBuffer(u8g2);//清除显示缓存