导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页

    【XR806开发板试用】软件模拟IIC驱动OLED显示图片&&自己遇到的坑

    Wireless & Analog Series
    1
    1
    964
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • Z
      zicxr LV 2 最后由 编辑

      前言
      首先,非常感谢极术社区和全志举办此次开发板申请试用活动。由于自己水平太低,拿到板子后不知道要干点啥,偶然看见一个大佬写的I2C外设使用及控制OLED屏显示,文章中使用了硬件IIC控制OLED,正好我手里也有一块OLED,那就直接试试模拟IIC(虽然有硬件IIC,软件IIC显得比较鸡肋[狗头])。同时感谢群里的好兄弟们,在我遇到坑的时候帮我解决了很多问题,非常感谢。(由于我水平比较低,可能会存在错误,希望各位大佬可以批评指正)
      一、设备及其连接
      1、设备
      OLED:1.3寸四脚OLED(IIC)
      下载.jfif
      驱动板:XR806(废话[狗头])
      下载.png
      2、连接

      OLED            XR806
      VCC--------------3V3
      GND--------------GND
      SDA--------------PB07
      SCL--------------PB06
      

      二、文件结构及相关配置
      1、文件结构

         my_oled
         ├── BUILD.gn
         ├── i2c
         │   ├── i2c.c
         │   └── i2c.h
         ├── oled
         │   ├── oled.c
         │   ├── oledfont.h
         │   └── oled.h
         └── src
             └── main.c
      

      2、BUILD.gn修改
      (1)device/xradio/xr806/ohosdemo/BUILD.gn配置

      group("ohosdemo") {
          deps = [
      
              #"hello_demo:app_hello",
              #"iot_peripheral:app_peripheral",
              #"wlan_demo:app_WlanTest",
              #"led:app_led",  
              "my_oled:app_oled",
          ]
      }
      

      (2)device/xradio/xr806/ohosdemo/my_oled/BUILD.gn配置

      import("//device/xradio/xr806/liteos_m/config.gni")     #必须,config中定义了头文件>路径和关键宏定义
      
      
      static_library("app_oled") {                             #必须,所有应用工程必须是app_打头
         configs = []
      
         sources = [
            "src/main.c",
            "oled/oled.c",
            "i2c/i2c.c",
         ]
      
         cflags = board_cflags                                #必须,board_cflags是在config.gni中定义的关键宏定义
      
         include_dirs = board_include_dirs                    #必须,board_include_dirs是>在config.gni中定义的文件路径
         include_dirs += [
            "./i2c",
            "./oled",
            "//utils/native/lite/include",
            "//kernel/liteos_m/kernel/arch/include",
            "//base/iot_hardware/peripheral/interfaces/kits", #根据实际情况添加头文件路径
         ]
      }
      

      三、代码
      代码有点多,只能放出来一部分,完整的代码可以在下面的链接中下载QWQ.(代码有点乱,注释比较少,如果我写的不清楚,欢迎随时来问我嗷QWQ,文末有联系方式[狗头])
      链接:https://pan.baidu.com/s/1LaegCeUGTuxnlHhk2lN4cw
      提取码:1217
      1、模拟IIC
      (1)时序图
      aHR0cDovL2hpLmNzZG4ubmV0L2F0dGFjaG1lbnQvMjAxMDExLzI5LzBfMTI5MTAxNjA1M1I1cXUuZ2lm.gif
      (2)模拟IIC代码(部分)
      i2c.h

      #ifndef __I2C_H
      #define __I2C_H
      
      #include "driver/chip/hal_gpio.h"
      
      #define SDA_IN()  PB7_OUT_OR_IN_SELECT(2)    
      #define SDA_OUT() PB7_OUT_OR_IN_SELECT(1) 
      
      //IO操作函数
      #define   IIC_SCL_HIGH   HAL_GPIO_WritePin(GPIO_PORT_B, GPIO_PIN_6, GPIO_PIN_HIGH)   
      #define   IIC_SCL_LOW   HAL_GPIO_WritePin(GPIO_PORT_B, GPIO_PIN_6, GPIO_PIN_LOW)
      #define   IIC_SDA_HIGH   HAL_GPIO_WritePin(GPIO_PORT_B, GPIO_PIN_7, GPIO_PIN_HIGH)   
      #define   IIC_SDA_LOW   HAL_GPIO_WritePin(GPIO_PORT_B, GPIO_PIN_7, GPIO_PIN_LOW)
      #define   READ_SDA    HAL_GPIO_ReadPin(GPIO_PORT_B, GPIO_PIN_7)
      
      void i2c_init(void);
      void IIC_Start(void);                        //发送IIC开始信号
      void IIC_Stop(void);                         //发送IIC停止信号
      void IIC_Send_Byte(uint8_t txd);             //IIC发送一个字节
      uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
      uint8_t IIC_Wait_Ack(void);                  //IIC等待ACK信号
      void IIC_Ack(void);                          //IIC发送ACK信号
      void IIC_NAck(void);                        //IIC不发送ACK信号
      
      #endif
      

      i2c.c(部分)

      #include <stdio.h>
      #include "ohos_init.h"
      #include "kernel/os/os.h"
      #include "driver/chip/hal_gpio.h"
      #include "i2c.h"
      GPIO_InitParam param;
      void gpio_output_init(void)
      {
              param.driving = GPIO_DRIVING_LEVEL_1;
              param.mode = GPIOx_Pn_F1_OUTPUT;
              param.pull = GPIO_PULL_NONE;
              HAL_GPIO_Init(GPIO_PORT_B, GPIO_PIN_6, &param);
              HAL_GPIO_Init(GPIO_PORT_B, GPIO_PIN_7, &param);
      }
      void PB6_output_ctl(uint8_t level)
      {
              HAL_GPIO_WritePin(GPIO_PORT_B, GPIO_PIN_6, level ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
      }
      void PB7_output_ctl(uint8_t level)
      {
              HAL_GPIO_WritePin(GPIO_PORT_B, GPIO_PIN_7, level ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
      }
      void PB7_OUT_OR_IN_SELECT(uint8_t mode ) // 1输出2输入
      {
              if(mode == 1)
              {
                      param.mode = GPIOx_Pn_F1_OUTPUT;
                      HAL_GPIO_Init(GPIO_PORT_B, GPIO_PIN_7, &param);
              }
       else if(mode == 2)
              {
                      param.mode = GPIOx_Pn_F0_INPUT;
                      HAL_GPIO_Init(GPIO_PORT_B, GPIO_PIN_7, &param);
              }
      }
      void i2c_init()
      {
              gpio_output_init();
              PB6_output_ctl(1);  //输出高
              PB7_output_ctl(1);
      }
      //产生起始信号
      void IIC_Start(void)
      {
              SDA_OUT();     //sda线输出
              IIC_SDA_HIGH;
              IIC_SCL_HIGH;
              OS_MSleep(0.004);;
              IIC_SDA_LOW;
              OS_MSleep(0.004);
              IIC_SCL_LOW;//钳住I2C总线,准备发送或接收数据 
      }
      //产生IIC停止信号
      void IIC_Stop(void)
      {
              SDA_OUT();//sda线输出
              IIC_SCL_LOW;
              IIC_SDA_LOW;
              OS_MSleep(0.004);
              IIC_SCL_HIGH;
              IIC_SDA_HIGH;//发送I2C总线结束信号
              OS_MSleep(0.004);
      }
      ...
      

      2、OLED代码
      OLED部分是直接修改了一下我以前在stm32上用的代码。
      oled.h

      #ifndef __OLED_H
      #define __OLED_H
      #include "i2c.h"
      
      #define u8 unsigned char
      #define u32 unsigned int
      #define OLED_CMD  0     //写命令
      #define OLED_DATA 1     //写数据
      
      void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
      void OLED_Clear(void);
      void OLED_Init(void);
      void OLED_Refresh_Gram(void);
      void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size);
      void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
      void OLED_ShowChinese(u8 x,u8 y,u8 chr,u8 len,u8 size,u8 mode);
      void OLED_Showpic(u8 x,u8 y,u8 chr,u8 size,u8 mode);
      #endif
      

      oledfont.h里是字库,还有图片
      oled.c(部分)

      void OLED_Init(void)
      {
          i2c_init();
          OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
          OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
          OLED_WR_Byte(80,OLED_CMD);   //[3:0],分频因子;[7:4],震荡频率
          OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
          OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) 
          OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
          OLED_WR_Byte(0X00,OLED_CMD); //默认为0
          OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
          OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
          OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
          OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
          OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
          OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
          OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
          OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
          OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
          OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
          OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
          OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
          OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
          OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
          OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
          OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
          OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示                                                     
          OLED_WR_Byte(0xAF,OLED_CMD); //开启显示  
          OLED_Clear();
      }
      /*********************************/
      void OLED_DrawPoint(u8 x,u8 y,u8 t)
      {
              u8 pos,bx,temp=0;
              if(x>131||y>63)return;//超出范围了.
              pos=7-y/8;
              bx=y%8;
              temp=1<<(7-bx);
              if(t)OLED_GRAM[x][pos]|=temp;
              else OLED_GRAM[x][pos]&=~temp;
      }
      /********* 在指定位置显示一个字符,包括部分字符节  *************/
      //x:0~127
      //y:0~63
      //mode:0,反白显示;1,正常显示                             
      //size:选择字体 12/16/24
      void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
      {
              u8 temp,t,t1;
              u8 y0=y;
              u8 csize=(size/8+((size%8)?1:0))*(size/2);              //得到字体一个字符对应点阵集所占的字节数
              chr=chr-' ';//得到偏移后的值             
          for(t=0;t<csize;t++)
          {
             if(size==12)temp=asc2_1206[chr][t];             //调用1206字体
             else if(size==16)temp=asc2_1608[chr][t];        //调用1608字体
              else if(size==24)temp=asc2_2412[chr][t];        //调用2412字体
              else return;                                                            //没有的字库
          for(t1=0;t1<8;t1++)
                      {
                          if(temp&0x80)OLED_DrawPoint(x,y,mode);
                          else OLED_DrawPoint(x,y,!mode);
                          temp<<=1;
                          y++;
                           if((y-y0)==size)
                              {
                                      y=y0;
                                       x++;
                                      break;
                              }
                      }
          }
      }
      

      3、主函数代码
      main.c

      #include <stdio.h>
      #include "ohos_init.h"                                                          //(7)
      #include "kernel/os/os.h"
      #include "iot_gpio.h"                                                           //(8)
      #include "i2c.h"
      #include "oled.h"
      static OS_Thread_t g_main_thread;
      #define GPIO_ID_PA21 21
      static void MainThread(void *arg)
      {
        printf("delay test start\r\n");
        IoTGpioInit(GPIO_ID_PA21);                                                    //(3)
        IoTGpioSetDir(GPIO_ID_PA21, IOT_GPIO_DIR_OUT);                                //(4)
        OLED_Init();
        OLED_Showpic(1,1,0,60,1);
      OLED_Refresh_Gram();
        while (1) {
          IoTGpioSetOutputVal(GPIO_ID_PA21, 1);                                      //(5)
          OS_MSleep(500);
          IoTGpioSetOutputVal(GPIO_ID_PA21, 0);                                      //(6)
          OS_MSleep(500);
        }
      }
      void LEDMain(void)                                                              //(2)
      {
        printf("i2c Test Start\n");
        if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL,
      OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
          printf("[ERR] Create MainThread Failed\n");
        }
      }
      SYS_RUN(LEDMain);
      

      四、运行结果
      编译下载后运行如图:
      微信图片_20220116171816.jpg
      原图是这个恐龙QIQ。
      下载.jpg
      虽然最后显示的有点恐怖,但也算成功了,哈哈哈哈。
      五、踩过的坑
      说起来配置环境那直接痛苦面具,我遇到了很多错误,但当时就想着赶快配置好,大部分都没记录来(抱头痛哭T_T)。但下面的印象非常深刻。
      make menuconfig错误
      我当时的错误是这样的:
      微信图片_20220116191024.png
      后来查了一下是因为少装了点啥。
      解决:
      微信图片_20220116191119.png
      (如果你装了当我没说...)

      hb build -f 时报错
      我当时的错误是这样的:
      微信图片_20220116192031.png
      解决:
      1642332284(1).jpg

      xshell串口格式乱
      解决:文件 - 属性 - 终端 - 高级 - 用CR-LF接受LF(R)
      六、结语
      最后,再次感谢极术社区和全志平台,感谢各位群友给我的帮助,这也是我第一次写关于技术的文章,写的不好,希望大佬多多批评指正。如果有错误可以联系我嗷QQ:2403057219(24小时在线[狗头])

      1 条回复 最后回复 回复 引用 分享 1
      • 1 / 1
      • First post
        Last post

      Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

      行为准则 | 用户协议 | 隐私权政策