电子产业一站式赋能平台

PCB联盟网

搜索
查看: 1151|回复: 0
收起左侧

【HarmonyOS HiSpark Wi-Fi IoT 套件试用连连载】我和鸿蒙的亲密接触----点亮OLED

[复制链接]

2607

主题

2607

帖子

7472

积分

高级会员

Rank: 5Rank: 5

积分
7472
发表于 2020-12-23 09:56:32 | 显示全部楼层 |阅读模式
【HarmonyOS HiSpark Wi-Fi IoT 套件试用连连载】我和鸿蒙的亲密接触----点亮OLED,   
本帖最后由 1073865331 于 2020-12-22 20:58 编辑





首先,科普一下OLED的知识:      OLED,即有机发光二极管 ( O r gan i c Ligh t - Em itti ng D i ode ) ,又称为有机电激光显示 ( O r gan i c El e c t r o l u mi ne s ence    D i sp l a y , O E L D ) 。 O L E D 由于同时具备自发光,不需背光源、对比度高、 厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。      LCD 都需要背光,而OLED 不需要,因为它是自发光的。这样同样的显示,OLED 效果要来得好一些。以目前的技术,OLED 的尺寸还难以大型化,但是分辨率确可以做到很高。在本章中,我们使用的是ALINETEK 的OLED 显示模块,该模块有以下特点: 1) 模块有单色和双色两种可选,单色为纯蓝色,而双色则为黄蓝双色。 2) 尺寸小,显示尺寸为 0.96 寸,而模块的尺寸仅为 27mm*26mm 大小。 3) 高分辨率,该模块的分辨率为 128*64。 4) 多种接口方式,该模块提供了总共 4 种接口包括:6800、8080 两种并行接口方式、4 线 SPI 接口方式以及 IIC 接口方式(只需要 2 根线就可以控制 OLED 了!)。      wifiiot套件上的显示模块使用的是IIC方式,通过SCL和SDA就可以跟MCU进行通信,进而显示信息到oled屏幕上。       在这里,我们先看一下原理图:

原理图.png (98.29 KB, 下载次数: 0)

下载附件  保存到相册  

昨天 20:15 上传 从原理可以获知 OLED模块使用的是GPIO13和GPIO14。 那么现在就要开始操作了。首先还是在app目录下新建一个文件夹oled_example,还有新建oled.c和BUILD.gn,具体如下:

目录结构.png (19.72 KB, 下载次数: 0)

下载附件  保存到相册  

昨天 20:22 上传 由于这里的端口是属于端口复用状态,所以需要修改原来的代码,将IIC属性复用到GPIO13和GPIO14。这里就是需要来到vendor\hisi\hi3861\hi3861\app\wifiiot_app\init\app_io_init.c 文件中,把初始化IIC引脚的代码修改如下:

  • #ifdef CONFIG_I2C_SUPPORT
      

  •   
  •     /* I2C IO复用也可以选择3/4; 9/10,根据产品设计选择 */
      

  •   
  •     hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
      

  •   
  •     hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);
      

  •   
  • #endif

复制代码 接下来还需要开启IIC功能,具体需要修改文件vendor\hisi\hi3861\hi3861\build\config\usr_config.mk 增加CONFIG_I2C_SUPPORT = y



通过以上的准备工作,就可以编写我们的函数了。

在这里是借鉴连志安老师的帖子和代码,在这里谢谢连老师。

其实我们最主要是调用海思写好的接口函数,所以这里把关键的函数列出来即可。



  • hi_u32 my_i2c_write(hi_i2c_idx id, hi_u16 device_addr, hi_u32 send_len)
      
  • {
      
  •     hi_u32 status;
      
  •     hi_i2c_data es8311_i2c_data = { 0 };
      

  •   
  •     es8311_i2c_data.send_buf = g_send_data;
      
  •     es8311_i2c_data.send_len = send_len;
      
  •     status = hi_i2c_write(id, device_addr, &es8311_i2c_data);
      
  •     if (status != HI_ERR_SUCCESS) {
      
  •         printf(“===== Error: I2C write status = 0x%x! =====\r\n“, status);
      
  •         return status;
      
  •     }
      

  •   
  •     return HI_ERR_SUCCESS;
      
  • }

复制代码 这里就是调用海思芯片的hi_i2c_write函数进行实现,我们只需要基于这个基础上进行打包方便我们调用即可了。

OLED模板需要写命令和写数据操作,所以这里我们需要分别定义这两个函数,函数如下:



  • **********************************************/

复制代码 便于兼容性,这里我们通过定义一个OLED_WR_Byte函数改变形参来选择写数据还是写命令,代码如下:



  • void OLED_WR_Byte(unsigned dat,unsigned cmd)
      
  • {
      
  •         if (cmd)
      
  •         {
      
  •         Write_IIC_Data(dat);
      
  •         }
      
  •         else {
      
  •         Write_IIC_Command(dat);
      
  •         }
      
  • }

复制代码 在这时,我们通过写命令来驱动OLED了。具体写什么命令,这得看数据手册了。我把OLED模块的数据手册放在附件中去,有兴趣的可以下载看看。这里直接列出:



  • void oled_init(void)
      
  • {
      
  •     OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
      
  •         OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
      
  •         OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
      
  •         OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM display Start Line (0x00~0x3F)
      
  •         OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
      
  •         OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
      
  •         OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
      
  •         OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
      
  •         OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
      
  •         OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
      
  •         OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
      
  •         OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset        Shift Mapping RAM Counter (0x00~0x3F)
      
  •         OLED_WR_Byte(0x00,OLED_CMD);//-not offset
      
  •         OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
      
  •         OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
      
  •         OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
      
  •         OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
      
  •         OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
      
  •         OLED_WR_Byte(0x12,OLED_CMD);
      
  •         OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
      
  •         OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
      
  •         OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
      
  •         OLED_WR_Byte(0x02,OLED_CMD);//
      
  •         OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
      
  •         OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
      
  •         OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
      
  •         OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
      
  •         OLED_WR_Byte(0xAF,OLED_CMD);
      
  • }

复制代码 跟着操作就好了,发送这些命令就相当于让OLED模块准备好了。下面你就得通过写命令和写数据的形式结合,编写功能函数,例如OLED的画点函数,这里的画点函数我们是通过一个BUF进行缓存的,每次都是通过把这个大数组进行写入实现页面刷新,具体如下:



  • u8 OLED_GRAM[144][8];

复制代码 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);
   }
}

//画点
//x:0~127
//y:0~63
void OLED_DrawPoint(u8 x,u8 y)
{
         u8 i,m,n;
         i=y/8;
         m=y%8;
         n=1<<m;
         OLED_GRAM[x]|=n;
}在这个画点函数的基础上,我们就可以干很多事情了。例如,显示字符函数OLED_ShowChar,先列出函数:


  

       
  • //在指定位置显示一个字符,包括部分字符
      
       
  • //x:0~127
      
       
  • //y:0~63
      
       
  • //size:选择字体 12/16/24
      
       
  • //取模方式 逐列式
      
       
  • void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
      
       
  • {
      
       
  •         u8 i,m,temp,size2,chr1;
      
       
  •         u8 y0=y;
      
       
  •         size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
      
       
  •         chr1=chr-\“ \“;  //计算偏移后的值
      
       
  •         for(i=0;i<size2;i++)
      
       
  •         {
      
       
  •                 //temp=asc2_1206[chr1];
      
       
  •                 if(size1==12)
      
       
  •         {temp=asc2_1206[chr1];} //调用1206字体
      
       
  •                 else if(size1==16)
      
       
  •         {temp=asc2_1608[chr1];} //调用1608字体
      
       
  •                 else return;
      
       

  •   
       
  •         for(m=0;m<8;m++)           //写入数据
      
       
  •         {
      
       
  •             if(temp&0x80)OLED_DrawPoint(x,y);
      
       
  •             else OLED_ClearPoint(x,y);
      
       
  •             temp<<=1;
      
       
  •             y++;
      
       
  •             if((y-y0)==size1)
      
       
  •             {
      
       
  •                 y=y0;
      
       
  •                 x++;
      
       
  •                 break;
      
       
  •             }
      
       
  •                 }
      
       
  •   }
      
       
  • }
      
复制代码 在这里就有一个汉字取模的知识,由于字符型数据已经是很常见的了,可以通过下载正点原子的OLED显示实验获得ASCII码表,但是这里也简单列一下如何得到?
这里我们介绍一个款很好的字符提取软件:
PCtoLCD2002 完美版。该软件可以提供各种字符,包括汉字 ( 字体和大小都可以自己设置 ) 阵 提取,且取模方式可以设置好几种,常用的取模方式,该软件都支持。该软件还支持图形模式, 也就是用户可以自己定义图片的大小,然后画图,根据所画的图形再生成点阵数据,这功能在 制作图标或图片的时候很有用。 该软件的界面如图 所示:

软件.png (41.67 KB, 下载次数: 0)
下载附件  保存到相册  
昨天 20:53 上传
PCtoLCD2002 软件界面
然后我们选择设置,在设置里面设置取模方式如图 所示:

取模.png (25.81 KB, 下载次数: 0)
下载附件  保存到相册  
昨天 20:54 上传
设置取模方式 上图设置的取模方式,在右上角的取模说明里面有,即:从第一列开始向下每取 8 个点作 为一 个 字 节 , 如 果 最 后 不 足 8 个 点 就补 满 8 位 。 取模 顺序 是 从 高 到 低 , 即 第 一个 点作 为 最 高 位。如*        取为 10000000 。 其实 就 是 按如 图 所 示的 这 种 方 式:

过程.png (14.46 KB, 下载次数: 0)
下载附件  保存到相册  
昨天 20:54 上传
取模方式图解 从上到下,从左到右,高位在前。我们按这样的取模方式,然后把 ASCII 字符集按 12*6 大小、16*8 和 24*12 大小取模出来 ( 对应汉字大小为 12*12 、16*16 和 24*24 ,字符的只有汉字 的一半大! ) ,保存在 oledfont.h 里面,每个 12*6 的字符占用 12 个字节,每个 16*8 的字符占用 16 个字节,每个 24*12 的字符占用 36 个字节。
以上操作需要自行完成。然后我们回到oled.c中

  

       
  • void my_oled_demo(void)
      
       
  • {
      
       
  •     //初始化
      
       
  •     hi_i2c_init(HI_I2C_IDX_0, 100000); /* baudrate: 100000 */
      
       

  •   
       
  • oled_init();
      
复制代码 接下来看一下同级目录下的BUILD.gn

  

       
  • static_library(“oled_demo“) {
      
       
  •     sources = [
      
       
  •         “oled.c“
      
       
  •     ]
      
       

  •   
       
  •     include_dirs = [
      
       
  •         “//utils/native/lite/include“,
      
       
  •         “//kernel/liteos_m/components/cmsis/2.0“,
      
       
  •     ]
      
       
  • }
      
复制代码 到这里就完成了。
编译烧录就不多说了。回看我的帖子。


回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表