STM32 软件IIC 控制OLED 显示屏

news2025/1/15 12:49:01

1. 硬件IIC 实在是太难用了,各种卡死,各种发不出来数据,没那么多时间折腾了,还是用软件IIC 先吧,初始化

void OLED_Software_IIC_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_AHBPeriphClockCmd(OLED_SOFTWARE_IIC_PORT_B | OLED_SOFTWARE_IIC_AF_CLOCK, ENABLE);

    GPIO_InitStruct.GPIO_Pin = OLED_IIC_SDA_PIN_B11 | OLED_IIC_SCL_PIN_B10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct); // PB11 - SDA, PB10 - SCL

    GPIO_SetBits(GPIOB, OLED_IIC_SDA_PIN_B11 | OLED_IIC_SCL_PIN_B10);

    OLED_IIC_Stop();
}

2. 一些宏定义,带FreeRTOS 实时操作系统,系统节拍设置为1ms,系统主频设置为32Mhz

#define OLED_USE_SOFTWARE_IIC

#define OLED_SOFTWARE_IIC_PORT_B    RCC_AHBPeriph_GPIOB // SCL - PB10, SDA -PB11
#define OLED_SOFTWARE_IIC_AF_CLOCK    RCC_APB1Periph_I2C2

#define IIC_TIMEOUT_COUNTER    0x2000 // iic transmit timeout

#define OLED_IIC_SCL_PIN_B10    GPIO_Pin_10
#define OLED_IIC_SDA_PIN_B11    GPIO_Pin_11
#define OLED_SCL_H()    GPIO_SetBits(GPIOB, OLED_IIC_SCL_PIN_B10)
#define OLED_SCL_L()    GPIO_ResetBits(GPIOB, OLED_IIC_SCL_PIN_B10)

#define OLED_ADDRESS    0x78 // 0x78: device address + write, 0x79 - device address + read
#define IIC_CMD_LEN    2

#define OLED_SDA_H()    GPIO_SetBits(GPIOB, OLED_IIC_SDA_PIN_B11)
#define OLED_SDA_L()    GPIO_ResetBits(GPIOB, OLED_IIC_SDA_PIN_B11)

#define OLED_SDA_READ()    GPIO_ReadInputDataBit(GPIOB, OLED_IIC_SDA_PIN_B11)

3. 延时函数,CPU 阻塞,空转

static void IIC_Delay(void)
{
   uint8_t temp;

   for (temp = 0; temp < 10; temp++)
   {
       // do nothing
   }
}

4. 起始信号

static void OLED_IIC_Start(void)
{
    OLED_SDA_H();
    OLED_SCL_H();

    IIC_Delay();
    OLED_SDA_L();
    IIC_Delay();
    OLED_SCL_L();
    IIC_Delay();
}

5. 停止信号

static void OLED_IIC_Stop(void)
{
   OLED_SDA_L();
   OLED_SCL_H();
   IIC_Delay();
   OLED_SDA_H();
   IIC_Delay();
}

6. 发送一个字节的数据

static void OLED_IIC_SendByte(uint8_t data)
{
   uint8_t index;
   GPIO_InitTypeDef GPIO_InitStruct;

   for (index = 0; index < 8; index++) // send one byte data, first send MSB (bit[7]), send LSB at the last (bit[0])
   {
       if (data & 0x80)
       {
           OLED_SDA_H(); // send 1
       }
       else
       {
           OLED_SDA_L(); // send 0
       }
       IIC_Delay();
       OLED_SCL_H();
       IIC_Delay();
       OLED_SCL_L();
       data <<= 1; // send next bit (MSB -> LSB)
       IIC_Delay();
   }
//    OLED_SDA_H();
   GPIO_InitStruct.GPIO_Pin = OLED_IIC_SDA_PIN_B11;
   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
   GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;

   GPIO_Init(GPIOB, &GPIO_InitStruct);

   IIC_Delay();
}

7. 发送一个字节数据后等待从机回复一个ACK 信号

uint8_t OLED_IIC_WaitAck(void)
{
   uint8_t ret;

   OLED_SCL_H();
   if (OLED_SDA_READ())
   {
       ret = 1; // not received ACK signal, wait fail
   }
   else
   {
       ret = 0; // received ACK signal, wait success
   }
   IIC_Delay();
   OLED_SCL_L();
   IIC_Delay();

   return ret;
}

8. GPIO 重新初始化

static void OLED_SoftwareIIC_SDA_Resume(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = OLED_IIC_SDA_PIN_B11;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct); // PB11 - SDA
}

9. 模仿HAL库写的一个自己的函数,实现功能,发送设备地址+读写控制,再发送0x00,表示发的是命令,再发一个字节数据,具体的内容,数据,共发了三个字节的数据,加了超时退出机制

/*
 * imitate the stm32 HAL library, achieve myself's software i2c send function
 * deviceAddr: 0x78 - device address and write operation, 0x79 - device address and read operation
 */
static void HAL_I2C_Master_Transmit(I2C_TypeDef *I2Cx, uint8_t deviceAddr, uint8_t buff[], uint16_t buffLen, uint32_t timeout)
{
    uint32_t temp;
    uint16_t index;

    temp = timeout;

    OLED_IIC_Start();

    IIC_Delay();
    OLED_IIC_SendByte(deviceAddr); // device address and write bit

    while (OLED_IIC_WaitAck())
    {
        temp--;
        if (0 == temp)
        {
            return;
        }
        IIC_Delay();
    }

    OLED_SoftwareIIC_SDA_Resume();
    for (index = 0; index < buffLen; index++)
    {
        OLED_IIC_SendByte(buff[index]);
        IIC_Delay();
        while (OLED_IIC_WaitAck())
        {
            temp--;
            if (0 == temp)
            {
                return;
            }
            IIC_Delay();
        }
        OLED_SoftwareIIC_SDA_Resume();
        IIC_Delay();
    }

    OLED_IIC_Stop();
}

10. 向OLED 发送指令函数

static void OLED_SendCmd(uint8_t cmd)
{
    uint8_t sendBuff[2];

    sendBuff[0] = 0x00;
    sendBuff[1] = cmd;

    HAL_I2C_Master_Transmit(I2C2, OLED_ADDRESS, sendBuff, IIC_CMD_LEN, IIC_TIMEOUT_COUNTER);
}

11. OLED 初始化函数,OLED 用的龙科显示公式的产品,控制IC 用的是CH1116G,他们给我发是资料却是SH1106的

void OLED_Init(void)
{
    delay_xms(200); // oled startup slowly than stm32l151c8t6
    INFO_LOG("[OLED_Init] init start\r\n");

    OLED_SendCmd(0xAE); // display off

    OLED_SendCmd(0x02); // set colum start address, low 4-bits
    OLED_SendCmd(0x10); // set colum end address, high 4-bits

    OLED_SendCmd(0x40); // set start line (first row)
    OLED_SendCmd(0xB0); // set page address

    delay_xms(5);
    OLED_SendCmd(0x81); // set contrast ratio (对比度)
    delay_xms(5);
    OLED_SendCmd(0xCF); // 128
    delay_xms(5);

    OLED_SendCmd(0xA1); // set segment remapping, from right to left

    OLED_SendCmd(0xA6); // forward display, normal or reverse

    OLED_SendCmd(0xA8); // multiple reuse rate, multiple ratio (多路复用率)
    OLED_SendCmd(0x3F); // duty = 1 / 64

    OLED_SendCmd(0xAD); // set charge pump enable
    OLED_SendCmd(0x8B); // enable DC-DC

    OLED_SendCmd(0x33); // set VPP = 10V

    OLED_SendCmd(0xC8); // set output scan direction, COM[N - 1] to COM[0], COM scan direction

    OLED_SendCmd(0xD3); // set display offset
    OLED_SendCmd(0x00); // 0x00

    OLED_SendCmd(0xD5); // set internal clock frequence, set osc frequency
    OLED_SendCmd(0xC0);

    OLED_SendCmd(0xD9); // set pre-charge period
    OLED_SendCmd(0x1F); // 0x22

    OLED_SendCmd(0xDA); // set COM pins, pin layout
    OLED_SendCmd(0x12);

    OLED_SendCmd(0xDB); // set electrical level, set VCOMH
    OLED_SendCmd(0x40);

    OLED_SendCmd(0xAF); // enable display, display on

    INFO_LOG("[OLED_Init][alfred01] init complete\r\n");
    INFO_LOG("[OLED_Init] init complete\r\n");
}

12. OLED 测试函数

void OLED_Test(void)
{
    OLED_SendCmd(0xB0); // page 0
    OLED_SendCmd(0x02); // colume 0, low 4-bits
    OLED_SendCmd(0x10); // colume 0, high 4-bits

    uint8_t sendBuff[] = {0x40, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
    HAL_I2C_Master_Transmit(I2C2, OLED_ADDRESS, sendBuff, sizeof(sendBuff), IIC_TIMEOUT_COUNTER);
}

13. OLED 初步显示效果,表示控制驱动是OK的了,其它的就是慢慢细调了

在这里插入图片描述

14. OLED 规格书,控制芯片用的CH1116G,这是硬件发给我,和厂家给的不一致,厂家说是兼容的,那我就直接上手调了

在这里插入图片描述

15. 看这三个引脚接的是高电平还是低电平,怎么组合的,就知道用的什么接口,需要看原理图了

在这里插入图片描述
需要看原理图了
在这里插入图片描述
在这里插入图片描述

16. 逻分仪抓的OLED 初始化时序图

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式锁java程序怎么处理 zk与redis

curator 基于zk实现实现了一套高级功能&#xff0c;比如有分布式锁 当第二客户端加锁时&#xff0c;会先判断它前面有没有第一个节点&#xff0c;如果有就加锁失败&#xff0c;同时就对它上一个节 点加一个watcher监听器&#xff0c;当第一个节点释放或客户端A宕机时&#xff…

Redis从基础到进阶篇(四)----性能调优、分布式锁与缓存问题

目录 一、Redis 集群演变 1.1 ReplicationSentinel*高可用 1.2 ProxyReplicationSentinel(仅仅了解) 1.3 Redis Cluster 集群 (重点&#xff09; 1.3.1 Redis-cluster架构图 1.3.2 工作原理 1.3.3 主从切换 1.3.4 副本漂移 1.3.5 分片漂移 二、Redis版本历史&#xf…

flink学习之广播流与合流操作demo

广播流是什么&#xff1f; 将一条数据广播到所有的节点。使用 dataStream.broadCast() 广播流使用场景&#xff1f; 一般用于动态加载配置项。比如lol&#xff0c;每天不断有人再投诉举报&#xff0c;客服根本忙不过来&#xff0c;腾讯内部做了一个判断&#xff0c;只有vip3…

Android开发-Mac Android开发环境搭建(Android Studio Mac环境详细安装教程,适合新手)...

1.进入Android Studio官网 https://developer.android.google.cn/studio 2.点击下载Android Studio. 3.将说明拉到最下方,选择Mac With Apple Chip.苹果芯片选择Apple Chip,如果是Intel芯片可以选择Intel. 4.下载完成后,双击进入Android Studio. 点击打开. 5.如果是第一次安装,…

【枚举子序列+组合数学+推式子】Cf Edu11 E

https://codeforces.com/contest/660/problem/E 题意&#xff1a; 思路&#xff1a; 重点在于枚举子序列&#xff0c;一般是先枚举子序列长度&#xff0c;然后枚举别的 算是经典套路 Code&#xff1a; #include <bits/stdc.h>#define int long longusing i64 long lo…

使用 WebGL 为 HTML5 游戏创建逼真的地形

推荐&#xff1a;使用 NSDT场景编辑器快速搭建3D应用场景 建 模 和 3D 地形 大多数 3D 对象是 使用建模工具创建&#xff0c;这是有充分理由的。创建复杂对象 &#xff08;如飞机甚至建筑物&#xff09;很难在代码中完成。建模工具 几乎总是有意义的&#xff0c;但也有例外&am…

如何正确的写出第一个java程序:hello java

1 前言 最近公司由于项目需要&#xff0c;开始撸java代码了。学习一门新的编程语言&#xff0c;刚开始总是要踩很多坑&#xff0c;所以记录一下学习过程&#xff0c;也希望对java初学者有所帮助。 2 hello java 2.1 程序源码 程序内容十分简单&#xff0c;这里就不再过多赘…

ICCV 2023 | MoCoDAD:一种基于人体骨架的运动条件扩散模型,实现高效视频异常检测

论文链接&#xff1a; https://arxiv.org/abs/2307.07205 视频异常检测&#xff08;Video Anomaly Detection&#xff0c;VAD&#xff09;扩展自经典的异常检测任务&#xff0c;由于异常情况样本非常少见&#xff0c;因此经典的异常检测通常被定义为一类分类问题&#xff08;On…

记录--CSS 滚动驱动动画 scroll()

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 CSS 滚动驱动动画 scroll() animation-timeline 通过 scroll() 指定可滚动元素与滚动轴来为容器动画提供一个匿名的 scroll progress timeline. 通过元素在顶部和底部(或左边和右边)的滚动推进 scroll…

界面控件DevExpress WPF(v23.2)下半年发展路线图

本文主要概述了DevExpress官方在下半年&#xff08;v23.2&#xff09;中一些与DevExpress WPF相关的开发计划。 通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 DevExpress …

如何让 Llama2、通义千问开源大语言模型快速跑在函数计算上?

:::info 本文是“在Serverless平台上构建AIGC应用”系列文章的第一篇文章。 ::: 前言 随着ChatGPT 以及 Stable Diffusion,Midjourney 这些新生代 AIGC 应用的兴起&#xff0c;围绕AIGC应用的相关开发变得越来越广泛&#xff0c;有呈井喷之势&#xff0c;从长远看这波应用的爆…

算法基础-数学知识-高斯消元、求组合数

高斯消元、求组合数 高斯消元883. 高斯消元解线性方程组 组合数AcWing 885. 求组合数 IAcWing 886. 求组合数 IIAcWing 887. 求组合数 IIIAcWing 888. 求组合数 IV 高斯消元 找到当前列绝对值最大的数 所在的行将改行的该列的系数变成1&#xff0c;其他列也要跟着变将这行和最…

使用GPT-4生成训练数据微调GPT-3.5 RAG管道

OpenAI在2023年8月22日宣布&#xff0c;现在可以对GPT-3.5 Turbo进行微调了。也就是说&#xff0c;我们可以自定义自己的模型了。然后LlamaIndex就发布了0.8.7版本&#xff0c;集成了微调OpenAI gpt-3.5 turbo的功能 也就是说&#xff0c;我们现在可以使用GPT-4生成训练数据&a…

taro vue3 ts nut-ui 项目

# 使用 npm 安装 CLI $ npm install -g tarojs/cli 查看 Taro 全部版本信息​ 可以使用 npm info 查看 Taro 版本信息&#xff0c;在这里你可以看到当前最新版本 npm info tarojs/cli 项目初始化​ 使用命令创建模板项目&#xff1a; taro init 项目名 taro init myApp …

《TCP/IP网络编程》阅读笔记--基于UDP的服务器端/客户端

目录 1--TCP和UDP的主要区别 2--基于 UDP 的数据 I/O 函数 3--基于 UDP 的回声服务器端/客户端 4--UDP客户端Socket的地址分配 5--UDP存在数据边界 6--UDP已连接与未连接的设置 1--TCP和UDP的主要区别 ① TCP 提供的是可靠数据传输服务&#xff0c;而 UDP 提供的是不可靠…

使用Java分析器优化代码性能,解决OOM问题

有的时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 背景 最近我一直在做性能优化&#xff0c;对一个单机应用做性能优化。主要是涉及到解析和导入导出相关的业务。 大致说一下这个单机应用…

算法 数据结构 递归插入排序 java插入排序 递归求解插入排序算法 如何用递归写插入排序 插入排序动图 插入排序优化 数据结构(十)

1. 插入排序&#xff08;insertion-sort&#xff09;&#xff1a; 是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入 算法稳定性: 对于两个相同的数&#xff0c;经过…

Matlab进阶绘图第28期—带回归趋势线的密度散点图

在之前的文章中&#xff0c;分享了Matlab密度散点图的绘制方法&#xff1a; 进一步&#xff0c;假如我们需要计算、添加散点的拟合线&#xff0c;该怎么操作呢&#xff1f; 本期就来分享一下带回归趋势线的密度散点图的绘制方法&#xff0c;先来看一下成品效果&#xff1a; 特…

iOS开发Swift-10-位置授权, cocoapods,API,天气获取,城市获取-和风天气App首页代码

1.获取用户当前所在的位置 在infi中点击加号,选择权限:当用户使用app的时候获取位置权限. 填写使用位置权限的目的. 2.获取用户的经纬度. ViewController: import UIKit import CoreLocationclass ViewController: UIViewController, CLLocationManagerDelegate { //遵循CLL…

C#进阶 多个泛型约束

using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine;public class A02_Generic : MonoBehaviour {[ContextMenu("测试Start")]// Start is called before the first frame updatevoid Start(){Person…