全彩OLED(SSD1351)程序设计与应用(2)显示优化:显存的设计与实现

    xiaoxiao2025-03-13  44

    本文开发环境:

    MCU型号:STM32F103ZEIDE环境: MDK 5.27显示模块:1.27寸全彩OLED(SSD1351)驱动

    本文内容:

    OLED 显示简介全彩 OLED 显存的设计与实现

    Note:为提高传输速度,本文把spi速度由上文工程的9Mpbs调至18Mpbs。这部分与OLED编程无关,故正文不做提及


    OLED 系列博客索引 :

    全彩OLED(SSD1351)程序设计与应用(1)驱动的移植全彩OLED(SSD1351)程序设计与应用(2)显存优化:显存的设计与实现全彩OLED(SSD1351)程序设计与应用(3)字符,字符串以及位图的生成与显示

    文章目录

    一、SSD1351 显示原理简介1. OLED 绘图原理 二、显示的优化:建立显存数组三、说明

    一、SSD1351 显示原理简介

    关于SSD1351显示的原理,可以参考技新科技的教程:SSD1351 设计指南,这里不再赘述,只简单介绍一下,与编程相关的知识点。

    1. OLED 绘图原理

    在上一小节中,我们已经完成了全屏画一个纯色的函数,其定义如下所示:

    void Fill_RAM(unsigned char a, unsigned char b) { unsigned char i,j; Set_Column_Address(0x00,0x7F); //设置列的范围 0 ~ 127 (共128列) Set_Row_Address(0x00,0x7F); //设置行的范围 0 ~ 127 (共127行) Set_Write_RAM(); //设置写RAM模式,即开始写入像素数据 for(i=0;i<128;i++) { for(j=0;j<128;j++) { Write_Data(a); //写入颜色高字节 Write_Data(b); //写入颜色低字节 } } }

    在SSD1351中,首先根据我们设置的行列地址,作为起始的坐标,启用RAM后,就开始按顺序一行一行填充颜色,这2两个for()循环语句,正好循环128x128次,保证了每一个像素点都被填充一次,每一次程序都发送了2个字节,这是颜色的数据。SSD1351采用RGB565颜色模式,两个字节16比特,其中每个bit比特含义为:RRRRRGGGGGGBBBBB。可以通过修改Fill_RAM()两个参数的值,来协助自己理解颜色与字节对应的关系。需要特别注意,本文使用的 oled 为1.27寸,其分辨率并非128x128,而是128x96,所以OLED最顶的一行,其行地址是 0x20 ,如果你写一个绘制点的函数,就可以很好的发现这一点——你在(50,50)绘制一个像素点,会发现它距离OLED的边框并不是一样的距离。(注:这是由于初始化造成的,实际上,128x96中,前文OLED_Init() 函数中 **Set_Multiplex_Ratio(0x7F)**参数应该为0x5F,0x7F为128x128驱动的设置,如果你改正此处,坐标值可以正确对应)

    二、显示的优化:建立显存数组

    在上一节中,我们可以明显的看到颜色刷新的时间,这是由于HAL库函数中 **HAL_SPI_Transmit()**函数代码量较大,而不是直接的控制寄存器,导致需要较长的时间,这个函数调用128x128x2写的时间不低于200ms,导致我们刷新一次屏幕的时候,需要200多毫秒,所以需要HAL_SPI_Transmit()一次性传输128x128x2的数据,而非每次传输1个,传128x128x2次。这就要求我们建立一个大的数组,其大小为 128x128x2 个字节,然后调用库函数,一次性传输。具体操作如下(oled.c 中)所示:

    在 oled.c 中建立一个显存数组: #define OLED_RAM_SIZE (128*128*2) //定义显存大小 static uint8_t oled_ram[OLED_RAM_SIZE] = {0}; //建立显存 使用显存方式刷新 oled /*FILE: oled.c*/ ... ... #include "spi.h" //包含 spi.h 头文件,程序需要使用到spi句柄 void OLED_Refresh(uint8_t *pRAM) { Set_Column_Address(0x00,0x7F); //设置列地址 Set_Row_Address(0x00,0x7F); //设置行地址 Set_Write_RAM(); //开始写RAM OLED_DC_Clr(); uDelay(1); OLED_DC_Set(); //写数据模式 uDelay(1); HAL_SPI_Transmit(&hspi1,oled_ram,OLED_RAM_SIZE,200); //发送显存数组 OLED_DC_Set(); } 测试程序 当我们实现新的刷屏方法以后,就可以编写程序测试效果,(直接修改OLED_Test()函数): ... ... # include "string.h" //需要使用menset来设置显存函数 ... ... void OLED_Test(void) { static uint8_t color = 0x0B; memset(oled_ram,color,OLED_RAM_SIZE); //填充显存颜色 OLED_Refresh(oled_ram); //使用新的方式刷新oled color += 0x0A; //改变显存颜色 HAL_Delay(500); }

    当我们运行完该程序以后,就可以发现屏幕的刷新是瞬间完成的,不在看到OLED刷新图片的过程,在以后的工程中,将以填充显存,刷新OLED的方式来显示,避免OLED刷新慢的问题。

    oled.c 完整代码: #include "ssd1351.h" #include "oled.h" #include "spi.h" #include "string.h" #define OLED_RAM_SIZE (128*128*2) static uint8_t oled_ram[OLED_RAM_SIZE] = {0}; void OLED_Refresh(uint8_t *pRAM) { Set_Column_Address(0x00,0x7F); Set_Row_Address(0x00,0x7F); Set_Write_RAM(); OLED_DC_Clr(); uDelay(1); OLED_DC_Set(); uDelay(1); HAL_SPI_Transmit(&hspi1,oled_ram,OLED_RAM_SIZE,200); OLED_DC_Set(); } void Fill_RAM(unsigned char a, unsigned char b) { unsigned char i,j; Set_Column_Address(0x00,0x7F); Set_Row_Address(0x00,0x7F); Set_Write_RAM(); for(i=0;i<128;i++) { for(j=0;j<128;j++) { Write_Data(a); Write_Data(b); } } } void OLED_Init(void) { OLED_RSE_Clr(); Delay(1); OLED_RSE_Set(); Set_Command_Lock(0x12); // Unlock Driver IC (0x12/0x16/0xB0/0xB1) Set_Command_Lock(0xB1); // Unlock All Commands (0x12/0x16/0xB0/0xB1) Set_Display_On_Off(0x00); // Display Off (0x00/0x01) Set_Display_Clock(0xF1); // Set Clock as 90 Frames/Sec Set_Multiplex_Ratio(0x7F); // 1/128 Duty (0x0F~0x7F) Set_Display_Offset(0x00); // Shift Mapping RAM Counter (0x00~0x7F) Set_Start_Line(0x00); // Set Mapping RAM Display Start Line (0x00~0x7F) Set_Remap_Format(0x74); // Set Horizontal Address Increment // Column Address 0 Mapped to SEG0 // Color Sequence D[15:0]=[RRRRR:GGGGGG:BBBBB] // Scan from COM127 to COM0 // Enable COM Split Odd Even // 65,536 Colors Mode (0x74) // * 262,144 Colors Mode (0xB4) Set_GPIO(0x00); // Disable GPIO Pins Input Set_Function_Selection(0x01); // Enable Internal VDD Regulator // Select 8-bit Parallel Interface Set_VSL(0xA0); // Enable External VSL Set_Contrast_Color(0xC8,0x80,0xC8); // Set Contrast of Color A (Red) // Set Contrast of Color B (Green) // Set Contrast of Color C (Blue) Set_Master_Current(Brightness); // Set Scale Factor of Segment Output Current Control Set_Gray_Scale_Table(); // Set Pulse Width for Gray Scale Table Set_Phase_Length(0x32); // Set Phase 1 as 5 Clocks & Phase 2 as 3 Clocks Set_Precharge_Voltage(0x17); // Set Pre-Charge Voltage Level as 0.50*VCC Set_Display_Enhancement(0xA4); // Enhance Display Performance Set_Precharge_Period(0x01); // Set Second Pre-Charge Period as 1 Clock Set_VCOMH(0x05); // Set Common Pins Deselect Voltage Level as 0.82*VCC Set_Display_Mode(0x02); // Normal Display Mode (0x00/0x01/0x02/0x03) Fill_RAM(0x00,0x00); // Clear Screen Set_Display_On_Off(0x01); // Display On (0x00/0x01) } void OLED_Test(void) { static uint8_t color = 0x0B; memset(oled_ram,color,OLED_RAM_SIZE); OLED_Refresh(oled_ram); color += 0x0A; HAL_Delay(500); }

    三、说明

    由于本次改动只是在上一个工程中修改了oled.c文件,所以只需要复制以上完整代码覆盖上一个工程的 oled.c 文件即可测试,这里不再上传工程,注意上文工程为的SPI速度为9M,本文测试环境为18M。

    最新回复(0)