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

前言

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

一、设备及其连接

1、设备

OLED:1.3寸四脚OLED(IIC)

在这里插入图片描述

驱动板:XR806(废话[狗头])

在这里插入图片描述

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)时序图

在这里插入图片描述

根据时序图控制SDA和SCL的高低,实现IIC通讯协议。

(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);

四、运行结果

编译下载后运行如图:
在这里插入图片描述

原图是这个恐龙QIQ。
在这里插入图片描述

虽然最后显示的有点恐怖,但也算成功了,哈哈哈哈。

五、踩过的坑

说起来配置环境那直接痛苦面具,我遇到了很多错误,但当时就想着赶快配置好,大部分都没记录来(抱头痛哭T_T)。但下面的印象非常深刻。

make menuconfig错误

我当时的错误是这样的:
在这里插入图片描述

后来查了一下是因为少装了点啥。
解决:
在这里插入图片描述

(如果你装了当我没说…)

hb build -f 时报错

我当时的错误是这样的:
在这里插入图片描述

解决:
当时我问了群里的一个兄弟,昵称:家星。再次万分感谢。
后来我发现在官方配置里也提到过:

在这里插入图片描述

xshell串口格式乱

解决:文件 - 属性 - 终端 - 高级 - 用CR-LF接受LF®

六、结语

最后,再次感谢极术社区和全志平台,感谢各位群友给我的帮助,这也是我第一次写关于技术的文章,写的不好,希望大佬多多批评指正。如果有错误可以联系我嗷QQ:2403057219(24小时在线[狗头])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/548098.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ElasticSearch】安装

1.官网寻找合适版本下载 这里我选择的是8.11.1 2.解压并启动 然后在浏览器输入http://localhost:9200/&#xff0c;判断是否启动成功 如下所示&#xff0c;则表示启动成功 安装过程中遇到过几个bug&#xff0c;记录在这篇文章中 【ElasticSearch】安装&#xff08;bug篇&am…

MySQL——基础

SQL 全称 Structured Query Language&#xff0c;结构化查询语言。操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 。 SQL 通用语法 SQL语句可以单行或多行书写&#xff0c;以分号结尾。SQL语句可以使用空格/缩进来增强语句的可读性。MySQL数据库…

mysql使用逗号分隔的一行数据转多行数据

文章目录 学习链接准备建表插入数据 方法MySQL逗号拼接的列拆分为多行&#xff08;不使用mysql.help_topic&#xff09;遇到字段以逗号分隔符分号分隔符存放多个值&#xff0c;需要一行转化多行&#xff0c;以用来关联&#xff08;使用mysql.help_topic&#xff09;改为LEFT JO…

git 上传代码到 github

准备工作 git Git LFS&#xff08;大文件>100Mb&#xff09; git 参考手册 github 建立仓库&#xff1a;New repository git 指令 git add . 用于将当前目录下的所有文件添加到 Git 仓库的暂存区中。 git add . 命令会将当前目录下的所有文件添加到 Git 仓库的暂存区中…

五、流程控制之循环

目录 5.1 步进循环语句for 5.1.1 带列表的for循环语句 5.1.2 不带列表的for循环语句 5.1.3 类C风格的for循环语句 5.2 while循环语句 5.2.1 while循环读取文件 5.2.2 while循环语句示例 5.3 until循环语句 5.4 select循环语句 5.5 嵌套循环 5.1 步进循环语句for for…

如何使用ArcGIS Pro进行路径分析

路径分析是一种空间分析技术&#xff0c;用于确定两个或多个地点之间最佳路径或最短路径&#xff0c;这里为大家介绍一下在ArcGIS Pro中如何进行路径分析&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的道路数据&#xff0c;除了道路数据&a…

大厂面试:获取字符串的全排列

一、概念 现有一个字符串&#xff0c;要打印出该字符串中字符的全排列。例如输入字符串abc&#xff0c;则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。 可以基于回溯法来解决这个问题。 二、代码 public class Permutation {//输出字符串str的全…

【自媒体创作利器】AI白日梦+ChatGPT 三分钟生成爆款短视频

AI白日梦https://brmgo.com/signup?codey5no6idev 引言 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI在各个领域都展现出了强大的应用潜力。其中&#xff0c;自然语言处理技术的进步使得智能对话系统得以实现&#xff0c;而ChatGPT作为其中的代表之一…

【Linux】磁盘阵列RAID技术

目录 一、RAID介绍 1.1 什么是RAID技术&#xff1f; 1.2 为什么要使用RAID技术&#xff1f; 二、RAID级别 2.1 常见的RAID级别 2.2 常见RAID介绍 三、RAID特性对比 一、RAID介绍 1.1 什么是RAID技术&#xff1f; 把多块独立的物理磁盘按不同的方式组合起来形成一个硬盘…

人工智能讲师大模型培训老师叶梓:基于大型语言模型的自主智能体:架构设计与应用前景

在人工智能的快速发展中&#xff0c;大型语言模型&#xff08;LLM&#xff09;已成为推动技术进步的关键力量。LLM的出现不仅改变了我们与机器的交互方式&#xff0c;也为构建具有高级认知能力的自主智能体&#xff08;AI Agent&#xff09;提供了新的可能性。本文旨在探讨基于…

(非技术) 基因遗传相关知识学习笔记

目录 一、基因遗传名词解释 二、什么叫显性遗传和隐性遗传&#xff1f; 三、如何确定遗传性质呢&#xff1f;是显性还是隐性&#xff1f; 四、常规例子1&#xff1a; 五、常规例子2&#xff1a; 六、实际案例&#xff1a; 七、思考题&#xff1a; 八、参考&#xff1a; …

云计算: OVN 集群 部署分布式交换机

目录 一、实验 1.环境 2.OVN 集群 部署云主机 3.中心端添加DVS分布式大二层交换机 二、问题 1.南向控制器查看主机名只显示localhost 2.中心端如何添加DVR分布式⼤三层路由器 一、实验 1.环境 (1) 主机 表1 宿主机 主机架构软件主要服务IP备注ovn_central中心端 ovn…

【Linux】基础I/O>文件系统软硬链接动静态库详解

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;Linux_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.C语言文件接口 1.1 hello.c写文件 1.2 hello.c读文件 1.3 输出信息到显示器 1.4 stdin & stdout & stderr 1.5 总结打…

Android Framework学习笔记(3)----Binder

什么是Binder&#xff1f; Binder是linux IPC机制的其中一种。它贯穿于应用层&#xff0c;framework层&#xff0c;以及linux Core层。 什么是IPC? 跨进程通信&#xff0c; InterProcess Communication. IPC机制都有哪些&#xff1f; 通道信号量消息队列BinderSocket共享内…

从IPv4到IPv6:解密网络通信的新时代

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 从IPv4到IPv6&#xff1a;解密网络通信的新时代 前言ipv4介绍ipv6介绍IPv4与IPv6的区别IPv4地址枯竭问题和IPv6的解决方案 ipv6的优势IPv6在新兴技术领域的应用 ipv4向ipv6的过渡挑战解决方案IPv6部署…

NVIDIA全系列GPU技术路线演进分析

NVIDIA GPU 架构梳理 近期深入研究并行计算,需探究底层硬件精髓。高性能计算界,英伟达显卡稳居霸主地位。本文旨在梳理NVIDIA GPU架构之演进历程,助您洞悉其技术脉络,把握未来计算趋势。 目录: NVIDIA GPU架构历经数次革新:从Tesla架构奠定基石,到Fermi架构提升性能,再…

【JAVA基础篇教学】第十五篇:Java中Spring详解说明

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第十五篇&#xff1a;Java中Spring详解说明。 Spring 框架是一个广泛应用于 Java 开发的轻量级、全栈式的企业应用开发框架&#xff0c;它提供了众多功能强大的模块&#xff0c;用于简化企业级应用程序的开发。下面详细说…

MySQL慢查询日志配置指南:发现性能瓶颈,提升数据库效率

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 MySQL慢查询日志配置指南&#xff1a;发现性能瓶颈&#xff0c;提升数据库效率 前言慢查询日志介绍配置慢查询日志配置慢查询日志失效日志格式与记录内容高级配置与注意事项配置过程中的注意事项&…

【python】flask操作数据库工具SQLAlchemy,详细用法和应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

EasyRecovery激活秘钥2024最好用的电脑数据恢复软件下载

EasyRecovery数据恢复软件是一款专业且功能强大的数据恢复工具&#xff0c;它旨在帮助用户从各种存储设备中恢复由于各种原因&#xff08;如误删除、格式化、病毒攻击、系统崩溃等&#xff09;导致丢失的数据。这款软件支持多种存储介质&#xff0c;包括但不限于硬盘驱动器、U盘…