注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
lugl4313820的个人空间 http://home.eeworld.com.cn/space-uid-1269709.html [收藏] [复制] [分享] [RSS]
日志

[ ST NUCLEO-U575ZI-Q 测评] 优化OLED显示

已有 1695 次阅读2023-1-11 12:18

[ ST NUCLEO-U575ZI-Q 测评] HAL移植U8G2 - stm32/stm8 - 电子工程世界-论坛 (eeworld.com.cn)

[ ST NUCLEO-U575ZI-Q 测评] 时钟——U8g2 - stm32/stm8 - 电子工程世界-论坛 (eeworld.com.cn)

上面的帖子是用u8g2实现OLED的显示,为了更进一步的熟悉ssd1306的使用,以及对hal库i2c的数据发送,这段时间又继续研究了ssd1306的数据发送。

STM32U575的HAL_I2C库的输出操作函数有两种模式,一种是阻塞模式,另一种是非阻塞模式。

阻塞模式:在轮询模式下执行通信。所有数据处理的状态由同一函数返回完成转移后。

无阻塞模式:使用中断进行通信或DMA。这些函数返回传输启动的状态。数据处理的结束将通过

 

阻塞模式功能发送有:

HAL_I2C_Master_Transmit()

HAL_I2C_Slave_Transmit()

HAL_I2C_Mem_Write()

带中断的无阻塞模式发送有:

HAL_I2C_Master_Transmit_IT()

HAL_I2C_Slave_Transmit_IT()

HAL_I2C_Mem_Write_IT()

DMA无阻塞模式功能:

HAL_I2C_Master_Transmit_DMA()

HAL_I2C_Slave_Transmit_DMA()

HAL_I2C_Mem_Write_DMA()

因为ssd1306的驱动没有做读取函数,所以只需要用到发送即可。

1、首先创建一个ssd1306的缓存,屏幕总共有128*8 = 1024字节,所以建立一个u8 OLED_GRAM[8][128];的缓存,用于存放显存数据。

2、把缓存数据发送给ssd1306的第一版函数:

//更新显存到OLED	
void OLED_Refresh(void)
{
	u8 i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
		OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
		OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
		for(n=0;n<128;n++)
		{
			OLED_WR_Byte(OLED_GRAM[n],OLED_DATA);
		}

  }
}

这样的话,总共要执行设置行起始地址、设置低列起始地址、设置高列起始地址8次,执行写入从机地址、数据位、位数8*128次。等待超时时间8*3+8*128次。

3、优化为发送数据128位时用一个函数来发送:

//更新显存到OLED	
void OLED_Refresh(void)
{
	u8 i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
		OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
		OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
		//for(n=0;n<128;n++)
		//{
		//	OLED_WR_Byte(OLED_GRAM[n],OLED_DATA);
		//}
        修改为一次发送128数据,减少了127个发送从机地址、命令位的时间。
        HAL_I2C_Mem_Write(&hi2c1, oled_addr, 0x00,1, &OLED_GRAM[n], 128, 100);

  }
}

这样的话就优化到少了8*127次发送从机地址+数据位命令的时间。

4、优化页写入命令,将所有数据做一次发送:

//在OLED初始化中修改页面寻址方式
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
//OLED_WR_Byte(0x02,OLED_CMD);//把页地址修改为水平方式(页地址0x02,水平0x00,垂直0x01)
OLED_WR_Byte(0x00,OLED_CMD);//
//更新显存到OLED	
void OLED_Refresh(void)
{
   /*
	u8 i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
		OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
		OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
		//for(n=0;n<128;n++)
		//{
		//	OLED_WR_Byte(OLED_GRAM[n],OLED_DATA);
		//}
        修改为一次发送128数据,减少了127个发送从机地址、命令位的时间。
        HAL_I2C_Mem_Write(&hi2c1, oled_addr, 0x00,1, &OLED_GRAM[n], 128, 100);

  }
  */
  //修改为一次发送1024数据。减少了8*4个地址位发送时间+8*4个数据位令发送时间。
  HAL_I2C_Mem_Write(&hi2c1, oled_addr, 0x00,1, &OLED_GRAM[n], 128, 100);
}

这样的话更进一步少了发送时间。

5、上面为阻塞式发送数据,下面修改为中断发送,首先在stm32cubeMax下配置为中断事件。

 然后修改发送函数为:

//更新显存到OLED	
void OLED_Refresh(void)
{
	HAL_I2C_Mem_Write_IT(&hi2c1, oled_addr, 0x40,1, &OLED_GRAM[0][0], 1024);
}

6、更换为DMA发送模式:

 配置好后修改发送函数为:

//更新显存到OLED	
void OLED_Refresh(void)
{
	HAL_I2C_Mem_Write_DMA(&hi2c1, oled_addr, 0x40,1, &OLED_GRAM[0][0], 1024);
}

【总结】经过以上的估化,刷新速度明显提高,而且代码量也变得少了。

 

 

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册