硬件:STM32F103ZET6最小系统板,0.96寸OLED(4针IIC接口),
软件:keil5
注意:本例默认具有一定的开发经验,不介绍如何创建keil模板项目,请自备好可用的项目!!!
实在不会的可以参考一下鄙人的这篇文章:STM32单片机项目模板(基于Keil5,以STM32F10x为例)_stm32f10xfwlib-优快云博客
也可以在我分享的网盘里直接下载模板(来自正点原子例程模板)
1. 获取U8G2库文件并解压:
1. u8g2图形库Github链接:
https://github.com/olikraus/u8g2.git
2. 笔者分享的百度网盘链接:
链接:https://pan.baidu.com/s/1tk85bqkTAX51dfXhZMPCqg?pwd=3cko
提取码:3cko
3. 笔者分享的阿里云盘链接:(阿里云盘不支持压缩包,大家用其他链接获取吧)
分享
https://www.alipan.com/s/VbVV1EuARkw
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。
4. 笔者分享的夸克网盘链接:
「教程资料」,复制整段内容,打开最新版「夸克APP」即可获取。
畅享原画,免费5倍速播放,支持AI字幕和投屏,更有网盘TV版。
/!95d4330ubQ!:/
链接:https://pan.quark.cn/s/566f5303e7ce
解压出来就是这一个u8g2-master(忽略其他文件,是我自己的文件,与本例无关,只需要关注这个即可)
2. 开始移植
1. 创建U8G2文件夹
在STM32的Keil项目中创建U8G2文件夹,用来存放U8G2库文件:
2. 移植库文件
1. 打开U8G2库文件->csrc:
2. 将文件按名称排序,复制以下文件到刚刚创建的U8G2文件夹:
-
第一部分:前34个文件,也就是u8x8_d_开头的文件之前的文件,如图:
-
第二部分:本例是0.96寸OLED,128*64的分辨率,所以选择这个文件:
u8x8_d_ssd1306_128x64_noname.c
-
第三部分:以下文件,也就是所有u8x8_d_开头的文件之后的文件,如图:
3. 打开keil项目
1. 将文件夹里的文件和路径添加到项目,这一步默认大家会,就不教了(实在不会的话,又不嫌弃咱的话,可以看看鄙人的这一篇介绍如何创建keil项目模板的文章),添加后效果,如图:
2. 找到u8g2_setup_d.c打开,其他函数注释掉或者删掉,只保留头文件和下面的这个函数:
void u8g2_Setup_ssd1306_i2c_128x64_noname_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_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, 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);
}
3. 找到u8g2_d_memory.c打开,其他函数注释掉或者删掉,只保留头文件和下面的这个函数:
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
}
4. 在项目目录下,创建一个专门放自己写的驱动代码的文件夹,然后再创建一个放具体驱动的文件夹,例如这里是OLED驱动,准确的说是模拟IIC的函数,你取名叫OLED.C或者IIC.C都可以,看你意愿,这里我取名OLED.C和OLED.H:
5. 然后依照惯例,将两个文件和这个文件夹的路径添加到keil项目里,这里不详说前面教过:
6. oled.c里添加以下代码:(里面的delay相关函数来自正点原子例程源码的delay.c和delay.h)
#include "stm32f10x.h"
#include "u8g2.h"
#include "oled.h"
#include "delay.h"
static void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB6:CLK, PB7:SDA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
}
uint8_t u8x8_gpio_and_delay_stm32l0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch(msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT:
/* only support for software I2C*/
OLED_Init();
break;
case U8X8_MSG_DELAY_NANO:
/* not required for SW I2C */
break;
case U8X8_MSG_DELAY_10MICRO:
/* not used at the moment */
break;
case U8X8_MSG_DELAY_100NANO:
/* not used at the moment */
break;
case U8X8_MSG_DELAY_MILLI:
delay_ms(arg_int);
break;
case U8X8_MSG_DELAY_I2C:
/* arg_int is 1 or 4: 100KHz (5us) or 400KHz (1.25us) */
delay_us(arg_int<=2?5:1);
break;
case U8X8_MSG_GPIO_I2C_CLOCK:
if ( arg_int == 0 )
{
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
}
else
{
GPIO_SetBits(GPIOB, GPIO_Pin_6);
}
break;
case U8X8_MSG_GPIO_I2C_DATA:
if ( arg_int == 0 )
{
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
}
else
{
GPIO_SetBits(GPIOB, GPIO_Pin_7);
}
break;
/*
case U8X8_MSG_GPIO_MENU_SELECT:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_SELECT_PORT, KEY_SELECT_PIN));
break;
case U8X8_MSG_GPIO_MENU_NEXT:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_NEXT_PORT, KEY_NEXT_PIN));
break;
case U8X8_MSG_GPIO_MENU_PREV:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_PREV_PORT, KEY_PREV_PIN));
break;
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_HOME_PORT, KEY_HOME_PIN));
break;
*/
default:
u8x8_SetGPIOResult(u8x8, 1);
break;
}
return 1;
}
void u8g2_Init(u8g2_t *u8g2)
{
u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_stm32l0);
u8g2_InitDisplay(u8g2);
u8g2_SetPowerSave(u8g2, 0);
u8g2_ClearBuffer(u8g2);
}
7. oled.h里要添加的文件,大家都很熟悉,如下:
#ifndef _OLED__H_
#define _OLED__H_
#include "u8g2.h"
void u8g2_Init(u8g2_t *u8g2);
#endif
8. main函数,测试移植结果:(懒得写注释了,一看就懂的代码,另外,u8g2各个函数的作用,自行学习,不介绍,因为我也还在学)
#include "stm32f10x.h"
#include "delay.h"
#include "u8g2.h"
#include "oled.h"
u8g2_t u8g2;
void Delay(u32 count)
{
u32 i=0;
for(;i<count;i++);
}
int main(void)
{
/* LED */
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE); //ʹÄÜPB,PE¶Ë¿ÚʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 ¶Ë¿ÚÅäÖÃ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO¿ÚËÙ¶ÈΪ50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //³õʼ»¯GPIOB.5
GPIO_SetBits(GPIOB, GPIO_Pin_5); //PB.5 Êä³ö¸ß
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5ÍÆÍìÊä³ö
GPIO_Init(GPIOE, &GPIO_InitStructure); //³õʼ»¯GPIO
GPIO_SetBits(GPIOE, GPIO_Pin_5); //PE.5 Êä³ö¸ß
/* Init */
delay_init();
u8g2_Init(&u8g2);
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
Delay(3000000);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
Delay(3000000);
u8g2_FirstPage(&u8g2);
do
{
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_inb24_mf);
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, 32, 12);
u8g2_SetFont(&u8g2, u8g2_font_5x7_tf);
u8g2_DrawStr(&u8g2, 1, 54, "github.com/olikraus/u8g2");
} while(u8g2_NextPage(&u8g2));
}
}