STM32+OLED屏(软件IIC+位带+帧缓冲区)刷新速率优化(四) 您所在的位置:网站首页 中兴axon20屏幕刷新率 STM32+OLED屏(软件IIC+位带+帧缓冲区)刷新速率优化(四)

STM32+OLED屏(软件IIC+位带+帧缓冲区)刷新速率优化(四)

2024-07-09 13:53| 来源: 网络整理| 查看: 265

       1.1   STM32+OLED屏初始化(一) 

       1.2  STM32+OLED屏显示字符串、汉字、图片(二)

       1.3  STM32+OLED屏多级菜单显示(三)

 1.优化刷新速率

        前三篇几乎已经完成了OLED屏显示的全部内容,当然,还缺少一些精致的图形,这方面可以自己动手做一些喜欢的图形,也可以移植一下大佬们图形库,并不是很复杂所有就不多赘述了。这一篇主要是优化屏幕的刷新速率,让OLED的刷新率尽可能的快一些,也就是经常说的高帧,优化刷新速率分为两篇,分别用软件IIC和硬件IIC,这一篇是软件IIC。

        之前的屏幕刷新主要是对屏幕的某一页的一个区间读写,如果一个屏幕要写两个或者两个以上的字符时,就要调用多次寻址操作,但是如果在我们在单片机中构建一个和SSD1306芯片的GRAM等大的SRAM内存,直接在单片机的SRAM数组上写,最后再SRAM数组的数据一次性写到SSD1306中,就只用调用一次写函数,可以大大提高芯片的读写操作。 

        构建帧缓冲区后,再优化软件IIC,使用stm32位带操作,直接操作GPIO管脚的高低电平,更快速简洁,位带是一种在单片机中使用的技术,它可以将单个位(bit)与一个特定的内存地址关联起来。 

2.帧缓冲区

        就如先前所说, 屏幕刷新主要是对屏幕的某一页的一个区间读写,但是每写一个字符就必须要寻址一次,当要写十个字符就必须要寻址十次,不仅效率不高还非常麻烦,为了解决这一麻烦提高工作效率,可以在单片机内部构建一个和OLED屏幕SSD1306芯片的GRAM等大的SRAM缓冲区(在单片机内部构建缓冲区数组),因为是为刷新帧率而存在的数组也称为帧缓冲区或显存。有了这片缓冲区就不用频繁的寻址了,如果要写十个字符就直接在帧缓冲区中操作,等这十个字符写好后再一次性把缓冲区的数据写入屏幕的GRAM中,这种操作只需要一次寻址,大大提高工作效率。按照正点原子的说法:

        单片机有无构建帧缓冲区示意图: 

  

2.1 构建帧缓冲区与画点函数

        构建一个缓冲数组OLED_GRAM[8][128](实际上是SRAM)为帧缓冲区,之后所有的显示操作都放在这个帧缓冲区中,修改完成图形数据后,再一次性将单片机内部的OLED_GRAM写入SSD1306的GRAM中。

//构建OLED帧缓冲区 uint8_t OLED_GRAM[64/8][128];

         构建帧缓冲区后,就面临两个问题,1、如何在帧缓冲区写数据?2如何将帧缓冲区的数据写入OLED屏幕上?在帧缓冲区中写数据可以使用画点函数,把帧缓冲区的数据写入SSD1306的GRAM中使用IIC通信。

        先说在帧缓冲区写数据,编写画点函数,对帧缓冲区写入数据。保存当前要写入的页面中八个点,再修改其中要修改的点,最后把修改好的八个点写入帧缓冲区,就修改了其中一个点了。画点函数对每次对帧缓冲区的一个点进行写0和1,需要那个点亮起就对该点写1,需要那个点灭掉就对该点写0,但是如果把该写1的地方写0,把该写0的地方写1,那么就会出现截然相反的效果,这就是帧缓冲区反显操作,这种操作并不需要对模块写入反显命令就可以实现。

/** * @brief OLED帧缓冲画点函数 * @param x 行位置 * @param y 列位置 * @param mode 显示模式:1--正显 0--反显 * @retval 无 * @explain 在帧缓冲区任意位置正/反显示一个点 */ void OLED_Framebuffer_Drawpoint(uint8_t x, uint8_t y, uint8_t mode) { uint8_t page, line, temp = 0; if(x>128 || y>64) return;//超出屏幕范围保护 page = y/8; // y方向8个字节 8Byte*8Bit = 64Bit y坐标除以8得要操作的Byte位 line = y%8; // y方向8个字节 8Byte*8Bit = 64Bit y坐标取余8得要操作的Bit位 temp = OLED_GRAM[page][x]; if(mode) temp |= 1>j & 0x01) ? 0:1); } } break; } } } } 2.3 在帧缓冲区绘制一串字符

        写入字符串可以照搬,和没有显存之前相差无异,只是在后面加上一个mode表示正/反显。

/** * @brief OLED在帧缓冲绘制字符串 * @param x 行位置 * @param y 列位置 * @param Fontsize 字体大小 * @param String 显示字符串, * @param mode 显示模式:1--正显 0--反显 * @retval 无 */ #include void OLED_Framebuffer_DrawString(uint8_t x, uint8_t y, uint16_t Fontsize, const char* String, uint8_t mode) { uint8_t i, len; len = strlen(String); for(i=0; ij & 0x01) ? 0:1); } } } } 2.5 在帧缓冲区绘制一张图片

        图片也一样,照猫画虎,直接写入。

/** * @brief OLED显示图片 * @param mode 显示模式:1--正显 0--反显 * @retval 无 * @explain 无 */ void OLED_Framebuffer_DrawImageBMG(uint8_t mode) { uint8_t i, j, k; uint8_t temp; for(k=0; k>j & 0x01) ? 0:1); } } } }  2.6 在帧缓冲区绘制一条直线

        再加一个画直线函数,此函数做了简化处理,只绘制水平线和垂直线,没有正/反显。

/** * @brief OLED在帧缓冲区绘制直线 * @param x1,y1 起点坐标 * @param x2,y2 终点坐标 * @retval 此函数做了简化处理,只绘制水平线和垂直线 */ void OLED_Framebuffer_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { uint16_t delta_x, delta_y, direction, a; //1、计算坐标增量 delta_x = x2 - x1; delta_y = y2 - y1; //2、判断是否满足绘制条件(水平线、垂直线) if(delta_x && delta_y) return;//表示两个自增都不为0 else if(!(delta_x || delta_y)) return;//表示两个自增都为0 //当delta_y=0时,表示水平线;当delta_x=0时,表示垂直线 if(delta_y == 0) { direction = delta_x; a = x1; } else if(delta_x == 0) { direction = delta_y; a = y1; } //3、开始绘制 for(int i=a; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有