IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> U8g2 软件i2c移植到stm32 -> 正文阅读

[嵌入式]U8g2 软件i2c移植到stm32

U8g2 软件i2c移植到stm32


使用stm32f407,软件i2c驱动oled屏幕
屏幕为 128*64,0.96寸 单色oled屏,驱动芯片ssd1306
开发环境: VSCODE+EIDE
开发语言: C/C++混编

第一步:准备资料

U8g2源码https://github.com/olikraus/u8g2下载
下载解压以后的目录
u8g2-master
我们主要是要 csrc 文件夹中的内容
1.将该文件夹添加到你的工程目录中,随便改名,我这里改名叫U8g2_drv
2.不要忘了在将文件夹添加到包含目录
在这里插入图片描述
图片不完整,还有很多,有几点注意以下:
1.mui开头的文件不用添加
2.u8x8_d_*****.c等是驱动文件,选择我们要的,u8x8_d_ssd1306_128x64_noname.c,其它可以添加也可以不添加
3.除上述不添加的,添加其它.c文件
其中my_u8g2.c是用来存放我们自己写的代码,主要是驱动内容

第二步写驱动:

目标: PE0-SCL PE1-SDA 软件IIC


my_u8g2.c文件

#include "my_u8g2.h"

//宏定义,方便改值
#define SCL_Pin GPIO_PIN_0
#define SDA_Pin GPIO_PIN_1
#define I2C_GPIO GPIOE

void I2C_init(void)
{
    GPIO_RCC_ENABLE(I2C_GPIO);//其它地方定义的函数,具体作用是开启传进来的时钟,就不放出来了
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = SCL_Pin|SDA_Pin;//使能对应引脚
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(I2C_GPIO, &GPIO_InitStruct);
}

//构建u8g2需要的回调函数
uint8_t STM32_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 seconds
  HAL_Delay(10);
  break;
  case U8X8_MSG_DELAY_MILLI:			// delay arg_int * 1 milli second
  HAL_Delay(1);
  break;
  case U8X8_MSG_DELAY_I2C:		    // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
    HAL_Delay_us(5);						// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
  case U8X8_MSG_GPIO_I2C_CLOCK:		// arg_int=0: Output low at I2C clock pin
  if(arg_int == 1) 
  {
  HAL_GPIO_WritePin(I2C_GPIO, SCL_Pin, GPIO_PIN_SET);
  }
  else if(arg_int == 0)
  {
  HAL_GPIO_WritePin(I2C_GPIO, SCL_Pin, GPIO_PIN_RESET);  
  }          
  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
  if(arg_int == 1) 
  {
  HAL_GPIO_WritePin(I2C_GPIO, SDA_Pin, GPIO_PIN_SET);
  }
  else if(arg_int == 0)
  {
  HAL_GPIO_WritePin(I2C_GPIO, SDA_Pin, GPIO_PIN_RESET);  
  }         
  break;							// arg_int=1: Input dir with pullup high for I2C data pin
  default:
  u8x8_SetGPIOResult(u8x8, 1);		// default return value
  break;
  }
  return 1;
}

my_u8g2.h文件

#ifndef _MY_U8G2_H__
#define _MY_U8G2_H__

#include "my_sys.h"
#include "u8g2.h"

void I2C_init(void);
uint8_t STM32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

#endif

第三步:修改u8g2源文件

1.修改u8g2_d_setup.c

注释所有函数,
保留以下两个函数,其它不需要做更改

/* ssd1306 */
/* ssd1306 1 *///GXT
void u8g2_Setup_ssd1306_i2c_128x64_noname_1(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_1(&tile_buf_height);
  u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}

/* ssd1306 f *///GXT
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);
}

2.修改u8g2_d_memory.c

注释所有函数,然后编译,查找报错信息,看缺少什么函数,找到他并相应取消注释即可
当然现在对于我这个芯片已经是找到了,直接拿给你,如果你的屏幕不一样,就要用你自己缺的
同样也是两个函数

uint8_t *u8g2_m_16_8_1(uint8_t *page_cnt)
{
  #ifdef U8G2_USE_DYNAMIC_ALLOC
  *page_cnt = 1;
  return 0;
  #else
  static uint8_t buf[128];
  *page_cnt = 1;
  return buf;
  #endif
}

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
}

至此修改工作已经完成,已经完成一大半了,剩下就比较简单了

第四步:开始写main.cpp

为什么是main.cpp呢,因为我的环境是C/C++混编,对于你们就是main.c就行了,区别会讲明

1.C++引入C文件需要像这样,否则会报错提示找不到函数/信息丢失等

//C++版本这样写
extern "C" //C++文件调用c文件
{
	#include "u8g2.h"
	#include "my_u8g2.h"//这个文件就是我们自己写的文件
}

//C版本这样写
#include "u8g2.h"
#include "my_u8g2.h"//这个文件就是我们自己写的文件

2.主函数添加代码

int main(void)
{
	.....//系统初始化
	I2C_init();//初始化I2C引脚,我们自己的函数
	u8g2_t u8g2;//定义结构体
	u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, STM32_gpio_and_delay);  // init u8g2 structure
	//注意上一句STM32_gpio_and_delay是我们自己定义的那个函数
	u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
	u8g2_SetPowerSave(&u8g2, 0); // wake up display
	//********初始化完成***********//
	//*******测试代码开始*******//
	u8g2_ClearBuffer(&u8g2);
	u8g2_SendBuffer(&u8g2);//清屏
	u8g2_SetFont(&u8g2,u8g2_font_DigitalDiscoThin_tf);
	u8g2_DrawStr(&u8g2,30,50,"Test_code");
	u8g2_SendBuffer(&u8g2);
	u8g2_DrawCircle(&u8g2,64,32,10,U8G2_DRAW_ALL);//在屏幕中间画个圆
	u8g2_SendBuffer(&u8g2);
}

接着就可以编译下载了


效果图片

请添加图片描述

!!!可能存在的报错(必看)

1.C++类兼容错误(使用C忽略)

1.可能是头文件引用等错误
2.可能是–cpp11 --c99 等错误
VSCODE中EIDE解决方法:

##########################################################################################
#                        Append Compiler Options For Source Files
#
# syntax:
#   <your matcher expr>: <your compiler command>
#
# examples:
#   'main.cpp':           --cpp11 -Og ...
#   'src/*.c':            -gnu -O2 ...
#   'src/lib/**/*.cpp':   --cpp11 -Os ...
#   '!Application/*.c':   -O0
#   '**/*.c':             -O2 -gnu ...
#
# For more syntax, please refer to: https://www.npmjs.com/package/micromatch
#
##########################################################################################

version: '1.0'

#
# for source files with filesystem paths
#
files:
#   './test/**/*.c': --c99
     './MY-DRIVERS/**/*.c': --cpp11
     './MY-DRIVERS/**/*.cpp': --cpp11
     './Core/**/*.c': --cpp11
     './Core/**/*.cpp': --cpp11
#
# for source files with virtual paths
#
virtualPathFiles:
#   'virtual_folder/**/*.c': --c99

2.报内存超出错误 No space in execution regions


先排查原因,首先注释上文main.c中的
u8g2_SetFont(&u8g2,u8g2_font_DigitalDiscoThin_tf);
u8g2_DrawStr(&u8g2,30,50,“Test_code”);
u8g2_SendBuffer(&u8g2);
等三句话,主要是u8g2_SetFont函数


如果还报错,需要更改代码优化等级

keil版

在keil中实测改到level 1就可以了
优化等级改高了可能会出现意料之外的优化结果,特别是使用系统等(非裸机)
在这里插入图片描述

EIDE版

1.打开构建器选项
2.选择C/C++编译器
选择更换代码优化级别,经实测可以改成level 1或者-Ospace(for code size)
我最终还是选择了-Ospace(for code size)

在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-01-04 13:36:08  更:2022-01-04 13:38:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 12:50:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码