1、前言

关于0.96吋OLED的详细操作,可查看一文彻底了解SSD1306驱动0.96寸OLED,本文移植u8g2图形库来驱动0.96吋OLED。

2、关于u8g2

u8g2是单色显示库的第二个版本。支持lcd和oled,支持众多驱动芯片,比如SSD1305, SSD1306, SSD1309, SSD1312, SSD1316, SSD1320, SSD1322, SSD1325, SSD1327, SSD1329, SSD1606, SSD1607, SH1106, SH1107, SH1108, SH1122, T6963, RA8835, LC7981, PCD8544, PCF8812, HX1230, UC1601, UC1604, UC1608, UC1610, UC1611, UC1617, UC1638, UC1701, ST7511, ST7528, ST7565, ST7567, ST7571, ST7586, ST7588, ST75256, ST75320, NT7534, ST7920, IST3020, IST7920, LD7032, KS0108, KS0713, HD44102, T7932, SED1520, SBN1661, IL3820, MAX7219等。
另外,u8g2是开源的,可直接下载代码移植:https://github.com/olikraus/u8g2。

3、移植

(1)直接从github下载代码,u8g2支持c/c++ ,cppsrc是c++的,csrc文件夹下面是c的源码,在单片机上移植就只需关注csrc里面的文件:

(2)u8g2里面支持多种驱动芯片,以u8x8_d_xxx.c命名的就是驱动文件,本文使用的是0.96吋oled,芯片是ssd1306,因此只需将u8x8_d_ssd1312_128x64_noname.c这个驱动文件添加到工程中:

(3)修改"u8g2_d_setup.c"这个文件,里面有各种驱动芯片的初始化函数,删除其他函数,只留下与使用的驱动芯片相关的函数。
本文使用的ssd1306,但是与ssd1306相关的有多个函数,例如:
u8g2_Setup_ssd1306_128x64_noname_1
u8g2_Setup_ssd1306_128x64_noname_2
u8g2_Setup_ssd1306_128x64_noname_f
这些都是spi接口的;
u8g2_Setup_ssd1306_i2c_128x64_noname_1
u8g2_Setup_ssd1306_i2c_128x64_noname_2
u8g2_Setup_ssd1306_i2c_128x64_noname_f
这些都是i2c接口的;
后缀1、2、f代表缓冲区大小的不同:
1代表128字节,
2代表256字节,
f代表1024字节;
根据单片机空间的大小选择合适的接口,缓冲区小的,刷新lcd/oled的时候就比较耗时,反之。
本文使用u8g2_Setup_ssd1306_i2c_128x64_noname_f这个接口:

(4)修改“u8g2_d_memory.c”文件,这个文件里面其实就是“u8g2_d_setup.c”文件对应的缓冲区,同上面一样,屏蔽掉没用到的,留下用到的:

(5)关于字库
u8g2_fonts.c”文件中定义了各种字库,这些字库比较占用空间,根据使用情况屏蔽掉没有使用的。

(6)两个回调函数
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)

参数byte_cbgpio_and_delay_cb是需要编写的两个回调函数。

byte_cb:是通信相关的函数,比如i2c写数据,
gpio_and_delay_cb:是延时相关的函数。
关于回调函数的写法,官方也给出了参考例子:https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform
通信函数分为硬件接口和软件模拟方式,软件模拟方式官方基本写好了,只需要简单的指定io口即可。
(7)软件模拟i2c接口
通信函数:直接使用官方的这个u8x8_byte_sw_i2c

uint8_t u8x8_byte_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{uint8_t *data;switch(msg){case U8X8_MSG_BYTE_SEND:data = (uint8_t *)arg_ptr;while( arg_int > 0 ){i2c_write_byte(u8x8, *data);data++;arg_int--;}break;case U8X8_MSG_BYTE_INIT:i2c_init(u8x8);break;case U8X8_MSG_BYTE_SET_DC:break;case U8X8_MSG_BYTE_START_TRANSFER:i2c_start(u8x8);i2c_write_byte(u8x8, u8x8_GetI2CAddress(u8x8));//i2c_write_byte(u8x8, 0x078);break;case U8X8_MSG_BYTE_END_TRANSFER:i2c_stop(u8x8);break;default:return 0;}return 1;
}

延时函数:在这个函数里面,根据传递的参数,拉低或者拉高SCL以及SDA。

uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{switch (msg){case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds__NOP();break;case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro secondsfor (uint16_t n = 0; n < 320; n++){__NOP();}break;case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli seconddelay_ms(1);break;case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHzdelay_us(5);break;                    // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25uscase U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pinif(arg_int == 1) {gpio_bits_set(SCL_PORT,SCL_PIN);//SCL=1}else if(arg_int == 0){gpio_bits_reset(SCL_PORT,SCL_PIN);//SCL=0}  break;                    // arg_int=1: Input dir with pullup high for I2C clock pincase U8X8_MSG_GPIO_I2C_DATA:  // arg_int=0: Output low at I2C data pinif(arg_int == 1) {gpio_bits_set(SDA_PORT,SDA_PIN);  //SDA=1}else if(arg_int == 0){gpio_bits_reset(SDA_PORT,SDA_PIN);  //SDA=0} break;                    // arg_int=1: Input dir with pullup high for I2C data pincase U8X8_MSG_GPIO_MENU_SELECT:u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);break;case U8X8_MSG_GPIO_MENU_NEXT:u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);break;case U8X8_MSG_GPIO_MENU_PREV:u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);break;case U8X8_MSG_GPIO_MENU_HOME:u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);break;default:u8x8_SetGPIOResult(u8x8, 1); // default return valuebreak;}return 1;
}

(8)硬件i2c接口
通讯函数:

uint8_t u8x8_byte_at32f425_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{static uint8_t buffer[32];      /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */static uint8_t buf_idx;uint8_t *data;switch(msg){case U8X8_MSG_BYTE_SEND:data = (uint8_t *)arg_ptr;      while( arg_int > 0 ){buffer[buf_idx++] = *data;data++;arg_int--;}      break;case U8X8_MSG_BYTE_INIT:/* add your custom code to init i2c subsystem */break;case U8X8_MSG_BYTE_START_TRANSFER:buf_idx = 0;break;case U8X8_MSG_BYTE_END_TRANSFER:HW_I2cWrite(buffer,buf_idx);break;default:return 0;}return 1;
}

这里面主要的函数接口是HW_I2cWrite,具体实现如下:
i2c写一个缓存区数据,缓冲区为buf,数据长度为len

void HW_I2cWrite(uint8_t *buf,uint8_t len)
{if(len<=0)return ;/* wait for the busy falg to be reset */while(i2c_flag_get(I2C1, I2C_BUSYF_FLAG) );/* start transfer */i2c_transmit_set(I2C1, I2C_SLAVE_ADDRESS7, len, I2C_SOFT_STOP_MODE, I2C_GEN_START_WRITE);i2c_start_generate(I2C1);while(i2c_flag_get(I2C1, I2C_ADDRF_FLAG) );for(uint8_t i=0;i<len;i++){while(!i2c_flag_get(I2C1, I2C_TDIS_FLAG) );i2c_data_send(I2C1, buf[i]);}i2c_stop_generate(I2C1);while(!i2c_flag_get(I2C1, I2C_STOPF_FLAG) );i2c_flag_clear(I2C1, I2C_STOPF_FLAG);
}

延时函数:

uint8_t u8g2_gpio_and_delay_at32f425(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:break;case U8X8_MSG_DELAY_MILLI:delay_ms(arg_int);break;case U8X8_MSG_GPIO_I2C_CLOCK:       break;                            case U8X8_MSG_GPIO_I2C_DATA:         break;default: return 0;}return 1; // command processed successfully.
}

4、代码测试

代码中使用了两种方式来测试,可选择软件或硬件i2c方式。

static u8g2_t u8g2;void U8g2Init(void)
{
#if 0SW_I2cInit();u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2,U8G2_R0,u8x8_byte_sw_i2c,u8x8_gpio_and_delay);
#elseHW_I2cInit();u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2,U8G2_R0,u8x8_byte_at32f425_hw_i2c,u8g2_gpio_and_delay_at32f425);
#endifu8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,u8g2_SetPowerSave(&u8g2, 0); // wake up displayu8g2_ClearBuffer(&u8g2);DrawLogo(&u8g2);delay_ms(500);delay_ms(500);
}
void U8g2Test(void)
{DrawProcess(&u8g2);DrawPoint(&u8g2);DrawLine(&u8g2);DrawBox(&u8g2);DrawCircle(&u8g2);DrawEllipse(&u8g2);
}

5、现象


测试视频:

u8g2移植测试

工程源码:https://download.csdn.net/download/freemote/85232359

【开源】硬件/软件i2c两种方式移植u8g2单色图形库驱动0.96吋OLED相关推荐

  1. 基于STM32F1自写移植代码分享系列之0.96寸OLED模块

    基于STM32F1自写移植代码分享系列之0.96寸OLED模块 文章目录 基于STM32F1自写移植代码分享系列之0.96寸OLED模块 文件获取 文件使用方法 参数配置 引脚配置 函数介绍 函数说明 ...

  2. STM32配合cubeMX硬件I2C驱动0.96寸OLED

    目录 一.简单介绍 1.1   OLED 1.2   I2C协议 二.实战 2.1 工程配置 2.2 测试工程 2.3 波形分析 三.驱动OLED 3.1 初始化代码 3.2 清屏函数 3.3 设置坐 ...

  3. STM32F103移植STEMWIN并驱动0.96寸OLED实现弹球界面效果

    现在很多带显示屏的电子产品,在待机状态下都有一个待机界面,最为经典的当属弹球界面了,当弹球碰到屏幕边界之后则反弹,先上效果图: 由于是移植了STEMWIN,所以只有STM系列单片机才可以正常跑该程序. ...

  4. 基于Stm32f103软件iic利用SH1106驱动0.96寸OLED

    第一次尝试写OLED的驱动,并自己利用取模软件造了基本的字库,再根据字库写了不同的显示函数. 打开OLED屏的数据手册我们可以看到一个完整的驱动流程 接下来我们只需要根据流程发送这些指令就可以点亮OL ...

  5. STM32 I2C驱动0.96寸OLED屏

    本文以STM32F103C8T6最小系统板为例               OLED屏为128*64像素  驱动芯片SSD1306 本文讲解标准库  硬件IIC和软件IIC 驱动OLED 硬件IIC ...

  6. HAL库使用硬件SPI驱动0.96寸OLED stm32F401

    找一个可以使用SPI接口的OLED驱动程序,一般买OLED会提供,或者自己网上找,这里用的是中景园的例程. 由于我使用的开发板是STM32F401ccu6,所以我先移植到我的开发板上,主要改的 打开M ...

  7. 【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结

    目录 SPI版 OLED SPI 端口定义 七针OLED引脚定义 六针OLED引脚定义 软件SPI 硬件SPI 启用DMA 帧率测试 I2C 版 软件I2C 硬件I2C DMA STM32F103VE ...

  8. STM32 7针0.96寸OLED显示屏(硬件SPI+DMA)无需内核响应 超高刷新率!

    芯片:STM32f103c8t6 f103型号大同小异,其他芯片请根据情况修改接口和配置 使用的是7针的0.96寸OLED屏幕,黑白两色显示 以下是实物图 一.原理: 首先你要了解STM32上的AFI ...

  9. MAX31855电路和程序,实现SPI和软件模拟时序两种方式读取数据

    1. 概述 MAX31855为热电偶至数字输出转换器,内置14位模/数转换器(ADC).器件带有冷端补偿检测和修正.数字控制器.SPI兼容接口,以及相关的控制逻辑,在温度控制器.过程控制或监测系统中设 ...

最新文章

  1. 《强化学习周刊》第7期:强化学习应用之游戏
  2. 塔勒布: 2019-nCoV的系统风险:一份笔记
  3. android density 和款高度,Android Density(密度)
  4. 苹果将放弃PowerPC支持 全面Intel化
  5. python面对对象汉诺塔_如何使用python实现的汉诺塔的小程序
  6. 程序运行依赖的重要文件版本不对_Deno核心模块:灵活依赖amp;安全沙箱
  7. 用Javascript实现interface的类似功能
  8. python从csv中读取数据打印到屏幕上-从Python中的CSV文件读取数据
  9. 我是如何解决jobtracker.info could only be replicated to 0 nodes, instead of 1这个问题的
  10. **【校招速递】入职鹅厂,算法大赛优秀选手开启职场新生活**
  11. airtestide 下载后打不开_惠普打印机驱动怎么下载 惠普打印机驱动安装方法【步骤】...
  12. 开源项目的所有者去世了怎么办?
  13. 进入android数据可视化,Android中的实时数据可视化
  14. 斯维尔密码狗使用方法(附安装资源)
  15. arduino中u8g2汉字显示总结
  16. Linux互斥锁详细解读,看这一篇就够了
  17. C语言中lwr是谁的缩写,C语言中关于字符串的操作(转)
  18. R语言并行计算beta-NTI值
  19. 聚看点{青龙面板可跑项目之一}保姆教程
  20. 百度云不限速详细教程

热门文章

  1. 经典Linux面试题
  2. 虚拟摄像头之 十二 v4l2loopback虚拟机摄像头移植实战(完结篇)
  3. c语言如何采集plc上的数据处理,PLC数据采集的方法小结
  4. 设计模式--桥接模式(Bridge)
  5. 【应用安全】微软的安全开发生命周期(SDL)
  6. 自然语言处理(一)句法分析, 乔姆斯基范式CYK+PCFG的短语结构
  7. python 处理Excel表格绘图方法
  8. 计算机学院辩论队,金秋风采 | 计算机学院辩论队
  9. matlab在轴向放大倍数,基于MATLAB的数控车床进给系统的建模与仿真[1]
  10. 计算机毕业设计 SSM疫情防控志愿者管理系统 志愿者服务信息系统 大学志愿者管理系统Java Vue MySQL数据库 远程调试 代码讲解