[低端局][cx32L003] 移植U8G2

news2024/10/6 20:33:30

文章目录

  • 一、简介
    • (1)U8g2
    • (2)U8x8
  • 二、配置要求
  • 三、移植步骤
    • (1)文件准备和添加
    • (2)实现回调接口(I2C的读写函数)
      • ①软件I2C
      • ②硬件I2C
    • (3)功能裁剪
      • ① u8g2_d_setup.c
      • ② u8g2_d_memory.c
      • ③ 关于字库

在低端芯片上使用U8G2

一、简介

U8g2:单色显示库,版本2

U8g2是一个用于嵌入式设备的单色图形库。U8g2支持单色oled和lcd,其中包括以下控制器:Ssd1305、ssd1306、ssd1309、ssd1312、ssd1316、ssd1318、ssd1320、ssd1322、ssd1325、ssd1327、ssd1327、ssd1327、ssd1327、ssd1327、ssd1327、ssd1106、sh1107、sh1108、ssd1607、hx1230、uc1601、uc1604、uc1608、pcd8544、pcf8812、hx1230、uc1601、uc1611、uc1617、uc1638、uc1701、st7511、st7528、st7565、st7567、st7586、st7588、st75160、st75256、st75320、nt7534、st7920、ist3020、ist3088、ist7920、ld7032、ks0108、ks0713、hd44102、t7932、sed1520、sbn1661、il3820、max7219、gp1287、gp1247、GU800(查看完整列表)。

Arduino库U8g2可以从Arduino IDE的库管理器中安装。U8g2还包括U8x8库:

(1)U8g2

  1. 包括所有图形程序(线/框/圆绘制)。

  2. 支持多种字体。(几乎)对字体高度没有限制。

  3. 在微控制器中需要一些内存来呈现显示。

(2)U8x8

  1. 仅文本输出(字符)设备。

  2. 只允许适合8x8像素网格的字体。

  3. 直接写入显示。在微控制器中不需要缓冲区。

二、配置要求

最少要求:
ROM:122+354+12+56+304+723+312+72+134+280+12+28+502+412+288+101+192+10+72=3986byte
RAM:0x80+0x01=0x81=129byte

在这里插入图片描述

在这里插入图片描述

RAM范围[128,1024],越大刷新越快。

Demo工程整体大小:NOS+IIC+GPIO+U8G2

  • Total RO Size (Code + RO Data) 9472 ( 9.25kB)
  • Total RW Size (RW Data + ZI Data) 880 ( 0.86kB)
  • Total ROM Size (Code + RO Data + RW Data) 9492 ( 9.27kB)

三、移植步骤

(1)文件准备和添加

  1. 下载文件(Gitee)
  2. 解压csrc到工程根目录在这里插入图片描述
  3. keil添加目录文件
    在这里插入图片描述

注意:带_d_是用户自定义文件,可以移动到工程中修改。

  1. keil添加头文件 [csrc的目录]
    在这里插入图片描述
  2. 添加驱动文件
    u8g2里面支持多种驱动芯片,以u8x8_d_xxx.c命名的就是驱动文件,本文使用的是0.96吋oled,芯片是ssd1306,因此只需将u8x8_d_ssd1312_128x64_noname.c这个驱动文件添加到工程中:
    在这里插入图片描述

(2)实现回调接口(I2C的读写函数)

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)

byte_cb:是通信相关的函数,比如i2c写数据,
gpio_and_delay_cb:是延时相关的函数。

①软件I2C

u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, gpio_and_delay); // init u8g2 structure

  1. u8x8_byte_sw_i2c官方已经实现 <–u8x8_byte.c
  2. 我们需要实现gpio_and_delay函数
uint8_t gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
  //printf("%s:msg = %d,arg_int = %d\r\n",__FUNCTION__,msg,arg_int);
  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
 	    for (uint16_t n = 0; n < 320; n++) {
         __NOP();
      }     
      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
          //delay 5us
          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(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);
      } else if(arg_int == 0) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 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
      //  printf("U8X8_MSG_GPIO_I2C_DATA:%d\r\n",arg_int);
      if(arg_int == 1)  {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
      } else if(arg_int == 0) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);  
      }         
      break;							// arg_int=1: Input dir with pullup high for I2C data pin
    case 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 value
      break;
  }
  return 1;
}

②硬件I2C

跟软件实现方式类似

u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, gpio_and_delay); // init u8g2 structure

#define I2C_SPEED_RATE	100   //uint khz
I2C_HandleTypeDef i2c_test = {0};
FlagStatus i2c_int = RESET;

main:
{
	__HAL_RCC_I2C_CLK_ENABLE();
	gpioi2c.Pin    = GPIO_PIN_5;
	gpioi2c.Mode = GPIO_MODE_AF; // GPIO端口复用功能 
	gpioi2c.Alternate = GPIO_AF4_I2C_SDA;
	gpioi2c.OpenDrain = GPIO_OPENDRAIN; // 开漏输出
	gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE; // 禁止输入去抖动
	gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH; // 电压转换速率
	gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH; // 驱动强度
	gpioi2c.Pull = GPIO_PULLUP;			// 上拉
	HAL_GPIO_Init(GPIOB, &gpioi2c);
	
	
	gpioi2c.Pin = GPIO_PIN_4;
	gpioi2c.Mode = GPIO_MODE_AF;
	gpioi2c.Alternate = GPIO_AF4_I2C_SCL;
	gpioi2c.OpenDrain = GPIO_OPENDRAIN; 
	gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
	gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH;
	gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
	gpioi2c.Pull = GPIO_PULLUP;	
	HAL_GPIO_Init(GPIOB, &gpioi2c);
	
	i2c_test.Instance = I2C;
	i2c_test.Init.master = I2C_MASTER_MODE_ENABLE; // 主机模式使能
	i2c_test.Init.slave = I2C_SLAVE_MODE_DISABLE; // 从机模式禁止
	i2c_test.Mode = HAL_I2C_MODE_MASTER; // 主机模式
	
	i2c_test.Init.broadack = I2C_BROAD_ACK_DISABLE; // 广播地址应答禁止
	i2c_test.Init.speedclock = I2C_SPEED_RATE; // I2C传输速率  
	i2c_test.State = HAL_I2C_STATE_RESET; //
	
	HAL_I2C_Init(&i2c_test);
}

uint8_t u8x8_byte_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:
		HAL_I2C_Master_Transmit(&i2c_test, buffer[0], &buffer[1], buf_idx - 1);
		break;
			
		default:
		  return 0;
	}
	return 1;
}

uint8_t 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:
			break;
			
		case U8X8_MSG_DELAY_MILLI:
			HAL_Delay(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.
}

到此,移植完毕,但是编译失败,空间不足!

(3)功能裁剪

① u8g2_d_setup.c

  1. 注释全部函数
  2. 找到u8g2_Setup_ssd1306_i2c_128x64_noname_1函数,解除注释。
    在这里插入图片描述
    注:用缓存128举例。有条件的可以使用256,1024.
    u8g2_Setup_ssd1306_i2c_128x64_noname_1() --缓存128byte
    u8g2_Setup_ssd1306_i2c_128x64_noname_2() --缓存256byte
    u8g2_Setup_ssd1306_i2c_128x64_noname_f() --缓存1024byte

② u8g2_d_memory.c

  1. 注释全部函数
  2. 找到u8g2_m_16_8_1函数,解除注释。
    在这里插入图片描述

注:用缓存128举例。有条件的可以使用256,1024.
u8g2_Setup_ssd1306_i2c_128x64_noname_1() --缓存128byte
u8g2_Setup_ssd1306_i2c_128x64_noname_2() --缓存256byte
u8g2_Setup_ssd1306_i2c_128x64_noname_f() --缓存1024byte

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_fonts.c”文件中定义了各种字库,这些字库比较占用空间,根据使用情况屏蔽掉没有使用的。

demo工程gitee

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/859737.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构链表——单链表

数据结构链表——单链表 概念及结构单链表的实现结构体类型的定义和头文件接口函数打印链表创建新节点尾插头插尾删头删查找任意插入指定位置之前插入指定位置之后插入 指定位置删除指定位置后删除单链表空间的销毁 概念及结构 概念&#xff1a;链表是一种物理存储结构上非连续…

PHP 使用ThinkPHP实现电子邮件发送示例

文章目录 首先我们需要设置我们的邮箱客户端授权&#xff0c;获取到授权码找到我们的邮箱设置去账号中找到这一堆服务&#xff0c;找到后开启smtp服务开启服务后管理服务 接下来需要去下载相应的第三方类库(我这里使用的是PHPMailer)在thinkPHP中封装一下邮件服务类实际调用效果…

Java 常用编辑器 IntelliJ IDEA

文章目录 IDEA 概述IDEA 下载和安装IDEA 中的第一个代码IDEA 的项目和模块操作&#xff08;一&#xff09;类的操作&#xff08;二&#xff09;模块的操作&#xff08;三&#xff09;项目的操作 IDEA 概述 IntelliJ IDEA是一款由JetBrains开发的集成开发环境&#xff08;IDE&am…

Android T 窗口层级其二 —— 层级结构树的构建(更新中)

如何通过dump中的内容找到对应的代码&#xff1f; 我们dump窗口层级发现会有很多信息&#xff0c;adb shell dumpsys activity containers 这里我们以其中的DefaultTaskDisplayArea为例 在源码的framework目录下查找该字符串&#xff0c;找到对应的代码就可以通过打印堆栈或者…

计算机的构造和原理

本资料转载于B站up主芯片超人-花 仅用于学习和讨论&#xff0c;如有侵权请联系 计算机工作原理之3D动画揭秘&#xff1a;计算机内部如何工作_哔哩哔哩_bilibili 1.CPU的部分 1.1 CPU放大看 1.2 一个芯片中&#xff0c;有80亿至100亿晶体管 1.3 放大磁道 1.4 共享3级缓存 1.5 …

kafka是有序的吗?如何保证有序?

首先&#xff0c;Kafka无法保证消息的全局有序性&#xff0c;这是因为Kafka的设计中允许多个生产者并行地向同一个主题写入消息。而且&#xff0c;一个主题可能会被划分为多个分区&#xff0c;每个分区都可以在独立的生产者和消费者之间进行并行处理。因此&#xff0c;生产者将…

C字符串与C++ string 类:用法万字详解(下)

目录 引言 一、string类对象的修改操作 1.1 push_back() 1.2 append() 1.3 operator() 1.4 c_str() 1.5 substr() 1.6 find() 1.7 rfind() 二、string类非成员函数 2.1 operator() 2.2 operator<<() 2.3 operator>>() 2.4 getline() 2.5 relational …

TFRecords详解

内容目录 TFRecords 是什么序列化(Serialization)tf.data 图像序列化&#xff08;Serializing Images)tf.Example函数封装 小结 TFRecords 是什么 TPU拥有八个核心&#xff0c;充当八个独立的工作单元。我们可以通过将数据集分成多个文件或分片&#xff08;shards&#xff09;…

phpstorm添加vue 标签属性绑定提示和提示vue的方法提示

v-text v-html v-once v-if v-show v-else v-for v-on v-bind v-model v-ref v-el v-pre v-cloak v-on:click v-on:keyup.enter v-on:keyup click change input number debounce transition :is :class把上面这些文字粘贴到点击右下角放大按钮 后的文本框里&#xff0c;然后保存…

混合云环境中 Kubernetes 可观测性的 6 个有效策略...

2023 年&#xff0c;原生云应用程序和平台将快速增长。组织不断努力最大限度地发挥其应用程序的潜力&#xff0c;确保无缝的用户体验并推动业务增长。 混合云环境的兴起以及 Kubernetes 等容器化技术的采用彻底改变了现代应用程序的开发、部署和扩展方式。 在这个数字领域&am…

Redis 搭建分片集群

文章目录 0.10.2 散列插槽0.3 集群伸缩0.3.1 需求分析0.3.1 创建新的 Redis 实例0.3.3 添加新节点到 Redis0.3.4 转移插槽 0.4 故障转移0.4.1 自动故障转移0.4.2 生动故障转移 0.5 RedisTemplate访问分片集群 1. 集群架构2. 准备实例和配置3. 启动4. 创建集群5. 测试 0.1 主从…

刷新缓冲区(标准IO)

标准IO是带缓冲的&#xff0c;输入和输出函数属于行缓冲&#xff0c;stdin、stdin、printf、scanf 1.换行符刷新 2.缓冲区满刷新 3.fflush函数强制刷新 4.程序正常结束

绩效考核,职场人的痛!

绩效&#xff0c;已经成为职场人不能跳过的话题。 绩效作为提高员工和企业效率的有效手段&#xff0c;已经被越来越公司采用&#xff0c;现在&#xff0c;公司里几乎任何一个岗位都会被考核&#xff0c;特别是互联网公司。今天我们以产品经理为例&#xff0c;看看这个岗位的绩效…

苍穹外卖day11笔记

今日首先介绍前端技术Apache ECharts&#xff0c;说明后端需要准备的数据&#xff0c;然后讲解具体统计功能的实现&#xff0c;包括营业额统计、用户统计、订单统计、销量排名。 一、ECharts 是什么 ECharts是一款基于 Javascript 的数据可视化图表库。我们用它来展示图表数…

leetcode每日一练-第121题-买卖股票的最佳时机

一、思路 动态规划 二、解题方法 维护两个变量&#xff1a;一个表示当前最低的股票价格 minPrice&#xff0c;另一个表示当前最大的利润 maxProfit。 遍历数组中的每个价格&#xff0c;对于每个价格&#xff0c;更新 minPrice 和 maxProfit。具体做法是&#xff0c;如果当前…

【Linux】TCP协议——传输层

目录 TCP协议 谈谈可靠性 TCP协议格式 序号与确认序号 窗口大小 六个标志位 确认应答机制&#xff08;ACK&#xff09; 超时重传机制 连接管理机制 三次握手 四次挥手 流量控制 滑动窗口 拥塞控制 延迟应答 捎带应答 面向字节流 粘包问题 TCP异常情况 TC…

【RTT驱动框架分析06】-pwn驱动框架分析+pwm驱动实现

pwm pwm应用程序开发 访问 PWM 设备API 应用程序通过 RT-Thread 提供的 PWM 设备管理接口来访问 PWM 设备硬件&#xff0c;相关接口如下所示&#xff1a; 函数描述rt_device_find()根据 PWM 设备名称查找设备获取设备句柄rt_pwm_set()设置 PWM 周期和脉冲宽度rt_pwm_enable…

橙河网络:2023年,我看谁还在做实体行业?

大家好&#xff0c;我是橙河老师&#xff0c;今天讲一讲实体行业。 现在实体行业还好干吗&#xff1f; 肯定是不好干了。 别的不扯&#xff0c;这几年很多大佬&#xff0c;能把老百姓干的事儿都干了。 一天收入上百万的演员&#xff0c;在直播间卖着九块九的东西&#xff0…

学习笔记-JVM-工具包(JVM分析工具)

常用工具 JDK工具 ① jps: JVM Process status tool&#xff1a;JVM进程状态工具&#xff0c;查看进程基本信息 ② jstat: JVM statistics monitoring tool &#xff1a; JVM统计监控工具&#xff0c;查看堆&#xff0c;GC详细信息 ③ jinfo&#xff1a;Java Configuration I…

MATLAB实现两组数据的延时对齐效果

博主在某次实验中&#xff0c;相同的实验条件下分别采集了两组数据&#xff0c;发现两组数据存在一个延时&#xff0c;如下图所示&#xff1a; 本文记录消除这个延时&#xff0c;实现相同数据状态的对齐效果&#xff0c;采用MATLAB自带的xcorr函数实现&#xff0c;具体步骤如下…