i2c介绍(I2C通信实例-OLED显示)
i2c介绍(I2C通信实例-OLED显示)汉字是全角字符,需要单独处理。16×16的点阵字整好占两行,因此逐行发送即可。ASCII码中包含所有的数字,因此没有必要编写*ShowNumber。显示数字时用sprintf函数把数字打印到一个字符串中,然后调用*ShowString就可以了。//Power on OLED void OLED_Display_PowOn(void) { u8 cmdlist[] = {SET_CHARGE_PUMP charGE_PUMP_ON DISPALY_AWAKE}; OLED_Write_CMD(cmdlist sizeof(cmdlist)); } //Power off OLED void OLED_Display_PowOff(void) { u8 cmdlist[] = {SET_CHARGE_PUMP CHARGE_PUMP_OFF DISPLAY_SLEEP};
前文回顾:- I2C通信实例 - OLED显示 01
 - I2C通信实例 - OLED显示 02
 
书接前文,接下来开始编写管理OLED显示的功能函数。
OLED初始化OLED首次点亮前要做一些初始化工作。比如设置复用路数,偏移量,对比度,显示模式等等。如果默认不满足要求的,可以再次一并设置。可以参考SSD1306手册中推荐的初始化流程图进行初始化。
void OLED_Init(void) {
  u8 cmdlist[] = {
    DISPLAY_SLEEP  //DISPlay OFF
    SET_MUX  0x1F  //Multiplex ratio. No. of row to drive.
    SET_DISP_OFFSET  0x00  	//No vertical shift
    RAM_START_LINE 0U  //Start line
    SEG_REMAP_OFF 	//Remap COL0 to SEG127 R<->L
    SET_COM_PIN  0x02  	//No Remap.
    COM_SCAN_INCR  //COM scan direction: from COM0 to COM(N-1)
    SET_CONTRAST  0x0F  //contrast
    DISPLAY_ENTIRE_RAM  //Disable entire display ON
    DISPLAY_NORMAL  //Set display mode
    SET_OSC_FRE  0x80 	//FOCS1111  DCLK=Fosc/1
    SET_PRE_CHARGE  0x22  	//Phase 1 and 2 all 2 DCLK
    SET_VCOMH_LEVEL  0x30  // 0.83Vcc
    };
  OLED_Write_CMD(cmdlist  sizeof(cmdlist));
  OLED_Display_PowOn();
  OLED_Clear();
}
    
cmdlist数组中的指令没有严格的顺序。双参数或多参数的指令可以放到同一行,提高程序的可读性。最后通过OLED_Write_CMD函数一次性发送给OLED控制器。最后两个函数是上电和清屏。
OLED显示控制开启OLED的顺序是先开启电荷泵,然后开启屏幕显示;关闭是要先关掉电荷泵,然后关闭屏幕显示。常用的显示控制函数示例如下:
//Power on OLED
void OLED_Display_PowOn(void) {
  u8 cmdlist[] = {SET_CHARGE_PUMP  charGE_PUMP_ON  DISPALY_AWAKE};
  OLED_Write_CMD(cmdlist  sizeof(cmdlist));
}
//Power off OLED
void OLED_Display_PowOff(void) {
  u8 cmdlist[] = {SET_CHARGE_PUMP  CHARGE_PUMP_OFF  DISPLAY_SLEEP};
  OLED_Write_CMD(cmdlist  sizeof(cmdlist));
}
//Set Contrast. ctrst=[20-255]
void OLDE_Set_Contrast(u16 ctrst){
  u8 cmdlist[2] = {0U};
  if (ctrst>255U) ctrst = 255U;
  if (ctrst<20U) 	ctrst = 20U;
  cmdlist[0] = SET_CONTRAST;
  cmdlist[1] = ctrst; //contrast
  OLED_Write_CMD(cmdlist  2U);
}
//Clear GDDRAM
void OLED_Clear(void) {
  u8 databuff[128] = {0U};
  u8 i;
  for (i = 0U; i<Max_Page; i  ) {
    OLED_Set_Pos(0U  i);	//Page i
    OLED_Write_DAT(databuff  128U);
  }
}
    
如果不关电荷泵,仅发送DISPLAY_SLEEP指令可以仅关闭屏幕,进入休眠。再次发送DISPALY_AWAKE指令可以恢复显示。但是如果关闭了电荷泵,DISPLAY_SLEEP后再发送DISPALY_AWAKE并不会恢复显示。OLDE_Set_Contrast函数用于设置对比度,0-255共256级,但太低意义不大,所以对范围进行了限制。OLED_Clear函数将显存逐页清零(清屏)。
OLED字符显示函数信息的显示是把点阵字符写入到显存中的指定位置。需要提前准备好字符库。
//Display character at (Col x  page y)
static void OLED_ShowChar(u8 x  u8 y  u8 chr  u8 Char_Hight) {
  u8 c = 0U  i = 0U;
  u8 hlfchr[8] = {0U};
  c = chr-' '; //Subtract first character in ASCII table
  if (x>Max_Col-1) { //Go to Next Page
    x = 0;
    y = y 2;
  }
  if (Char_Hight==16) {
    OLED_Set_Pos(x  y);			//upper page
    for (i = 0U; i<8U; i  )
      hlfchr[i] = ASCII8X16[c][i];
    OLED_Write_DAT(hlfchr  8U);
    OLED_Set_Pos(x  y 1);		//lower page
    for (i = 0U; i<8U; i  )
      hlfchr[i] = ASCII8X16[c][i 8U];
    OLED_Write_DAT(hlfchr  8U);
  } else {
    OLED_Set_Pos(x  y);			//single page
    for (i = 0U; i<6U; i  )
      hlfchr[i] = ASCII6x8[c][i];
    OLED_Write_DAT(hlfchr  6U);
  }
}
//Display a string specified like "string".
void OLED_ShowString(u8 x  u8 y  char *chr  u8 Char_Hight) {
  u8 j = 0;
  while (chr[j]!='\0') {
    OLED_ShowChar(x  y  chr[j]  Char_Hight);
    x  = 8;
    if (x>120) {
      x = 0;
      y  = 2;
    }
    j  ;
  }
}
    
高度为16个像素的字符占两页,需要分两次写入。注意这里虽然也有个循环,但只是把一行的前8列和后8列分别整理到缓存数组中,然后调用OLED_Write_DAT一次写入8个字节,异于通常的逐字节写入。原因前面已多次解释,不再赘述。按8个字节分页的原因是,英文字符是半角字符。*ShowString在*ShowChar的基础上,使我们可以一次写入任意多个字符。有了*ShowString,*ShowChar在.c文件外部完全可以不用,因此声明为Static。
ASCII码中包含所有的数字,因此没有必要编写*ShowNumber。显示数字时用sprintf函数把数字打印到一个字符串中,然后调用*ShowString就可以了。
汉字是全角字符,需要单独处理。16×16的点阵字整好占两行,因此逐行发送即可。
//Display Chinese Character
void OLED_ShowChinese(u8 x  u8 y  u8 no) {
  OLED_Set_Pos(x  y);		//upper page
  OLED_Write_DAT((u8*)&HZ16X16[2U*no] 16U);
  OLED_Set_Pos(x  y 1U);	//lower page
  OLED_Write_DAT((u8*)&HZ16X16[2U*no 1U] 16U);
}效果
    

图1. 显示效果图
图1所示为显示效果图。右侧紫色的模块就是是前文述及的SHT35温湿度传感器。OLED显示的正是传感器实时采集到的数据。
除了上述函数外,还可以按需添加屏幕滚动显示、休眠、扫描模式管理(默认是页扫描模式,还支持行扫描、列扫描)等功能函数。图2是一个简单的滚动效果图。So Cool!

图2. 滚动效果图
总结
- 向显存中写信息用HAL_I2C_Mem_Write函数;
 - 为提高效率,应将尽可能多的数据放入数组,一次性写入。
 




