【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

这篇具有很好参考价值的文章主要介绍了【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)


前言

本篇博客涉及以下内容

  • IIC通讯原理讲解、代码编写
  • SSD1306驱动芯片datasheet讲解、驱动代码编写、0.96oled模块原理图说明
  • STM32CubeMX配置IIC

使用硬件:STM32F103C8T6
使用软件:STM32CubeMX、keil5(MDK)、VSCode(搭载keil assistant插件)


提示:以下是本篇文章正文内容

一、IIC通讯

  在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设。STM32HAL 库则是在寄存器与用户代码之间的软件层。
  对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。

1.IIC物理层

  IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器以及其外围设备。它是由数据线 SDA 和时钟线 SCL 构成的串行总线,可发送和接收数据,在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送。

  SDA(Serial data)是数据线,D代表Data也就是数据,Send Data 也就是用来传输数据的

  SCL(Serial clock line)是时钟线,C代表Clock 也就是时钟 也就是控制数据发送的时序的

  IIC作为一种低数半双工总线,通信速率比SPI低,常见的半双工还有485,SPI和USART都是全双工。

  全双工:同一时间可以双向通信,即可以同时接收,发送数据。
  半双工:同一时间只能单向通信,即同一时间只能接收或者发送数据。

  常见的IIC通讯接线方式如下图:
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
IIC设备分为主设备和从设备,基本上谁控制时钟线(即控制SCL的电平高低变换)谁就是主设备

它的物理层有如下特点:

(1) 它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 IIC 通讯设备,支持多个通讯主机及多个通讯从机。

  主机从机概念:
  主机就是负责整个系统的任务协调与分配.发布主要命令的称为主机。
  从机一般是通过接收主机的指令从而完成某些特定的任务,主机和从机之间通过总线连接,进行数据通讯。

(2) 一个 IIC 总线只使用两条总线线路,一条双向串行数据线 (SDA) ,一条串行时钟线 (SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

(3) 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

(4) 总线通过上拉电阻接到电源。当 IIC 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

(5) 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

(6) 具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达 3.4Mbit/s,但目前大多 IIC 设备尚不支持高速模式。

(7) 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制。

2.IIC协议层

 学习IIC协议之前,我们先看一下它的总线时序图
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
 IIC 的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

  • ① 起始信号
      当 SCL 为高电平期间,SDA 由高到低的跳变。起始信号是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在起始信号产生后,总线就处于被占用状态,准备数据传输。

代码如下:

void iic_start(void)
{
    IIC_SDA(1);     /* SDA置高 */
    IIC_SCL(1);     /* SCL置高 */
    iic_delay();
    IIC_SDA(0);     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    iic_delay();
    IIC_SCL(0);     /* 钳住I2C总线,准备发送或接收数据 */
    iic_delay();
}
  • ② 停止信号
      当 SCL 为高电平期间,SDA 由低到高的跳变。停止信号也是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在停止信号发出后,总线就处于空闲状态。

代码如下:

void iic_stop(void)
{
    IIC_SDA(0);     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);     /* 发送I2C总线结束信号 */
    iic_delay();
}
  • ③ 数据传输
      在 I2C 总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行时钟的配合下,在 SDA 上逐位地串行传送每一位数据。数据位的传输是边沿触发。

  • 数据有效性
      IIC 使用 SDA 信号线来传输数据,使用 SCL 信号线进行数据同步。IIC 总线进行数据传送时,SCL 为高电平的时候 SDA 表示的数据有效,即此时的 SDA 为高电平时表示数据“1”,为低电平时表示数据“0”。当 SCL 为低电平时,SDA 的数据无效,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化.数据在 SCL 的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定。
    【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
      每次数据传输都以字节为单位,每次传输的字节数不受限制。

  • ⑤ 应答信号
      发送方每发送一个字节(一个字节8位),由接收方反馈一个应答信号(在第9个时钟信号期间),包括“应答 (ACK)”和“非应答 (NACK)”两种信号。应答信号为低电平时,规定为有效应答位(ACK 简称应答位),表示接收方已经成功地接收了该字节,发送方会继续发送下一个数据;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功,发送方接收到该信号后会产生一个停止信号,结束信号传输。
    【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
      传输时主机产生时钟,在第 9 个时钟时,数据发送端会释放 SDA 的控制权,由数据接收端控制SDA,若 SDA 为高电平,表示非应答信号 (NACK),低电平表示应答信号 (ACK)。

代码如下:

void iic_ack(void)
{
    IIC_SDA(0);     /* SCL 0 -> 1 时 SDA = 0,表示应答 */
    iic_delay();
    IIC_SCL(1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(1);     /* 释放SDA线 */
    iic_delay();
}
  • ⑥ 空闲状态
      IIC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

  • ⑦ 读写通讯过程
      I2C 总线上的每个设备都有自己的独立地址,主机发起通讯时,通过 SDA 信号线发送设备地址(SLAVE_ADDRESS) 来查找从机。I2C 协议规定设备地址可以是 7 位或 10 位,实际中 7 位的地址应用比较广泛。紧跟设备地址的一个数据位用来表示数据传输方向,它是数据方向位 (R/w),第 8位或第 11 位。数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据。
    【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
      IIC 的基本的读写通讯过程,包括主机写数据到从机即写操作,主机到从机读取数据即读操作。下面先看一下写操作通讯过程图
    【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
      主机首先在 IIC 总线上发送起始信号,那么这时总线上的从机都会等待接收由主机发出的
    数据。主机接着发送从机地址+0(写操作)组成的 8/11bit 数据,所有从机接收到该 8/11bit 数据后,自行检验是否是自己的设备的地址,假如是自己的设备地址,那么从机就会发出应答信号。主机在总线上接收到有应答信号后,才能继续向从机发送数据。
      注意:IIC 总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。

   写数据
  若配置的方向传输位为“写数据”方向。如下图:广播完地址,接收到应答信号后,主机开始正式向从机传输数据 (DATA),数据包的大小为 8 位,主机每发送完一个字节数据,都要等待从机的应答信号 (ACK),重复这个过程,可以向从机传输 N 个数据,这个 N 没有大小限制。当数据传输结束时,主机向从机发送一个停止传输信号 §,表示不再传输数据。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
代码如下:

uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */
    {
        receive <<= 1;  /* 高位先输出,所以先收到的数据位要左移 */
        IIC_SCL(1);
        iic_delay();

        if (IIC_READ_SDA)/* 接收到高电平‘1’ */
        {
            receive++;
        }
        
        IIC_SCL(0);
        iic_delay();
    }

    if (!ack)
    {
        iic_noack();     /* 发送nACK */
    }
    else
    {
        iic_ack();      /* 发送ACK */
    }

    return receive;
}

   读数据
  若配置的方向传输位为“读数据”方向。如下图:广播完地址,接收到应答信号后,从机开始向主机返回数据 (DATA),数据包大小也为 8 位,从机每发送完一个数据,都会等待主机的应答信号 (ACK),重复这个过程,可以返回 N 个数据,这个 N 也没有大小限制。当主机希望停止接收数据时,就向从机返回一个非应答信号 (NACK),则从机自动停止数据传输。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)


void iic_send_byte(uint8_t data)
{
    uint8_t t;
    
    for (t = 0; t < 8; t++)/* 一个字节8位,发送一个字节需要八个时钟周期 */
    {
        IIC_SDA((data & 0x80) >> 7);    /* 高位先发送 */
        iic_delay();
        IIC_SCL(1);
        iic_delay();
        IIC_SCL(0);
        data <<= 1;     /* 左移1位,用于下一次发送 */
    }
    IIC_SDA(1);         /* 发送完成, 主机释放SDA线,检测接收端应答信号 */
}

   读写数据
  除了基本的读写,I2C 通讯更常用的是复合格式。如下图该传输过程有两次起始信号 (S)。一般在第一次传输中,主机通过 SLAVE_ADDRESS 寻找到从设备后,发送一段“数据”,这段数据通常用于表示从设备内部的寄存器或存储器地址 (注意区分它与 SLAVE_ADDRESS 的区别);在第二次的传输中,对该地址的内容进行读或写。也就是说,第一次通讯是告诉从机读写地址,第二次则是读写的实际内容。以上通讯流程中包含的各个信号分解如下:
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

3.STM32的 II 特性及架构

3.1 软件IIC

  如果我们直接控制 STM32 的两个 GPIO 引脚,分别用作 SCL 及 SDA,按照上述信号的时序要求,直接像控制 LED 灯那样控制引脚的输出 (若是接收数据时则读取 SDA 电平),就可以实现 I2C 通讯。由于直接控制 GPIO 引脚电平产生通讯时序时,需要由 CPU 控制每个时刻的引脚状态,所以称之为“软件模拟协议”方式。优点就是不管是 ST 生产的控制器还是 ATMEL 生产的存储器,都能按通讯标准交互。

3.2 硬件IIC

STM32 的 I2C 片上外设专门负责实现 I2C 通讯协议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU 只要检测该外设的状态和访问数据寄存器,就能完成数据收发,称之为“硬件协议”方式。优点就是由硬件外设处理 I2C 协议的方式减轻了CPU 的工作,且使软件设计更加简单。

4.软件IIC代码

  本代码适用于HAL库与标准库,两者切换仅需更改iic_init()与头文件。
  软件IIC代码的编写应当具有高度可移植性,方便用于不同款的MCU,上出已近列写部分代码,此处仅列出STM2初始化GPIO代码和.h文件代码。完整代码链接在文章末。

4.1 IIC.c

void iic_init(void)
{
/******************************************************************************************/
    /*HAL库版本*/
    GPIO_InitTypeDef gpio_init_struct;

    IIC_SCL_GPIO_CLK_ENABLE();  /* SCL引脚时钟使能 */
    IIC_SDA_GPIO_CLK_ENABLE();  /* SDA引脚时钟使能 */

    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;        /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 快速 */
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);/* SCL */

    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;        /* 开漏输出 */
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);/* SDA */

    /* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */

/******************************************************************************************/
    /*标准库版本*/
/*
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//ʹÄÜGPIOBʱÖÓ

    //GPIOB7,B8初始化
    GPIO_InitStructure.GPIO_Pin = IIC_SCL_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;       //输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
    GPIO_Init(IIC_SCL_GPIO_PORT, &GPIO_InitStructure);  //SCL

    GPIO_InitStructure.GPIO_Pin = IIC_SDA_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;       //输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;      //开漏输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
    GPIO_Init(IIC_SDA_GPIO_PORT, &GPIO_InitStructure);  //SDA
*/
/******************************************************************************************/

    IIC_SCL(1);     /* 总线空闲状态 */
    IIC_SDA(1);
}

4.2 IIC.h

/*
 ****************************************************************************************************
 * @file        IIC.h
 * @author      橙子太
 * @version     V1.0
 * @date        2023-1-8
 * @brief       软件IIC 驱动代码
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:STM32F103C8T6
 *
 * 修改说明
 * V1.0 2023-1-8
 * 第一次编写
 *
 * 本代码仅用于个人学习使用
 * 
 ****************************************************************************************************
 *@引脚接线
 * PB6---->SCL
 * PB7---->SDL
 * 
 ****************************************************************************************************
 */

#ifndef __IIC_H
#define __IIC_H

#include "stm32f1xx_hal.h"
//#include "stm32f1xx.h" 
/******************************************************************************************/

#ifndef uint32_t
typedef unsigned           char uint8_t;
typedef unsigned short     int  uint16_t;
typedef unsigned           int  uint32_t;
#endif

/******************************************************************************************/
/* 引脚 定义 */

#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_6
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_7
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

/******************************************************************************************/

/* IO操作 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SCL */

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SDA */

#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */
/*
IIC_SCL(1);     SCL置高
IIC_SCL(0);     SCL置低
IIC_SDA(1);     SDA置高
IIC_SDA(0);     SDA置低
*/
#endif

二、SSD1306

  在此我们简单学习一下SSD1306这款芯片,通过查看datasheet,了解SSD1306的指令、引脚定义、寻址方式、0.96Oled的原理图,学习如何驱动SSD1306。

2.1 通讯协议选择

【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
  由图可知SSD1306适用于多种通讯协议,IIC,6800,8080,SPI(三线,四线)都可,由BS0;BS1;BS2三位引脚决定。本篇我们只讨论IIC驱动SSD1306。

2.2 引脚定义

  SSD1306的引脚非常多,这里我们仅介绍重要引脚,电气特征引脚不做介绍,详细引脚请看数据手册。

  • RES#
     &emsp;此引脚是复位信号输入。当引脚被拉时,执行芯片的初始化。在正常操作期间保持此引脚较高(即连接到VDD)。
  • CS#
     &emsp;这个引脚是芯片的选择输入.保持低电平即可
  • D/C#
     &emsp;这是数据/命令控制引脚。当它被拉动HIGH(即连接到VDD)时,D[7:0]处的数据被视为数据。当它被LOW时,D[7:0]的数据将被传输到命令寄存器。在II C模式下,该引脚作为从属地址选择的SA0。当选择三线串行接口时,该引脚必须连接到VSS。
    【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
      DC=0,IIC下地址为0x78;DC=1;IIC下地址为0x7A,下面会介绍
  • R/W#(WR#)
      这是连接到MCU接口的读/写控制输入引脚。1为读,0为写。
  • D[7:0]
      8位双向数据总线。当选择串行接口模式时,D0为串行时钟输入:SCLK;D1为串行数据输入:SDA,SDIN和D2应保持NC。当选择IIC模式时,D2、D1应该绑定在一起,作为SDA。

2.3 0.96oled屏幕模块

  0.96寸oled显示模块电路图如下,此处使用的模块为IIC通信
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

2.4 SSD1306下的IIC

2.4.1 从机地址

  IIC设备在数据传输之前都必须识别从机地址。SSD1306的从机地址有 0111100b 和 0111101b 两种,通过将SA0(D/C#)脚上拉到高电平可以设置从机地址第七位为 1,将SA0(D/C#)脚下拉到低电平可以设置从机地址第七位为 0。通过SA0(D/C#)脚的上拉和下拉来设置从机地址,从而令总线上可以存在最多2个SSD1306驱动器。由于显示模块只用来写数据,R/W为0,所以从机地址只有01111000 和 01111010 两种
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

2.4.2数据读/写

【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

2.4.3 写入顺序及格式

【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
  在传输完从属地址后,控制字节或数据字节都可以通过SDA发送。一个控制字节主要由Co和D/C#位组成,后面有六个 “0”。
  如果Co位被设置为逻辑 “0”,则以下信息的传输将只包含数据字节。D/C#位决定了下一个数据字节是作为命令还是数据。
  如果D/C#位被设置为逻辑"0",它定义下一个数据字节为命令。
  如果D/C#位被设置为逻辑"1",则定义下一个数据字节为数据,将被存储在GDDRAM中。

2.5 GDDRAM

  GDDRAM是一个保持要显示的位模式的位映射静态RAM。RAM的大小为128 x 64位,RAM分为8页,从PAGE0到PAGE7,用于单色128 x 64点矩阵显示,就是我们常说的像素点为128x64(横坐标有 128 个像素格,纵坐标有 64 个像素格)。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

  当一个数据字节被写入GDDRAM时,当前列同一页的所有行图像数据都被填充(即列地址指针指向的整个列(8位)被填充)。数据位D0写入上行,数据位D7写入下行。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
  当一个数据字节被写入GDDRAM时,当前列同一页的所有行图像数据都被填充(即列地址指针指向的整个列(8位)被填充)。数据位D0写入上行,数据位D7写入下行。

  简而言之,该显示模块一共64行,可以分为8页(Page0 ~ Page7),每页8行(COM0 ~ COM7,COM8 ~ COM15,…),一共128列(SEG0~SEG127),每次显示时一次性至少显示8位,即一页中的一列,上面的为低位(LSB),下面的为高位(MSB),且低4位为列低地址,高4位为列高地址。一般一个中文字体占 16×16 个像素格,字母以及符号占 8×16或者6x8 个像素格。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

2.6 寻址方式

  通过设置指令,OLED模块可以配置为三种显示模式:页地址模式、水平地址模式、垂直地址模式,其实差别在于显示完本位置后,下一位要在哪显示的问题。

页面寻址模式(A[1:0]=10xb)
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
  在页面寻址模式下,读写显示RAM后,列地址指针自动增加1。如果列地址指针到达列结束地址,则列地址指针将被重置为列起始地址,而页面地址指针将不被更改。用户必须设置新的页面和列地址,才能访问下一页的RAM内容。
页面寻址模式设置下低列开始地址(00h~0Fh),页面寻址模式设置高列开始地址(10h~1Fh)

水平地址模式(A[1:0]=00b)
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

  在水平寻址模式下,读写显示RAM后,列地址指针自动增加1。如果列地址指针到达列结束地址,则将列地址指针重置为列起始地址,页地址指针增加1。当列和页面地址指针都到达结束地址时,指针将重置为列起始地址和页面起始地址。

垂直地址模式(A[1:0]=01b)
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
  在垂直寻址模式下,读写显示RAM后,页面地址指针自动增加1。如果页面地址指针到达页面结束地址,则页面地址指针重置为页面起始地址,列地址指针增加1。当列和页面地址指针都到达结束地址时,指针将重置为列起始地址和页面起始地址。

  需要注意的是,OLED上电复位时的默认状态为页地址模式,而且这种也是最为常用的显示模式,因此可以看到很多OLED的代码中初始化时都没有配置这一项。

2.7 基础指令

  SSD1306的指令非常多,这里我们只介绍几个基础指令,详细说明请看DataSheet。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

2.8 驱动代码编写

2.8.1写数据/指令

  由上文的IIC数据格式可知,当控制字节发送为0x00,代表下一个字节为命令,当控制字节发送为0x40,代表下一个字节为数据,此处我们采用软件IIC方式写入字节,如需使用硬件IIC仅需要在 _Oled_write_Byte()函数中调用STM32硬件IIC函数即可。此处我们从机地址为0x78,这里使用宏定义来设定从机地址,便于阅读和后续修改。

/**
  * @brief  向OLED写入命令
  * @param  iic_command:写入命令
  * @retval 无
*/
void _Oled_Write_Cmd(uint8_t iic_command)
{
    _Oled_Write_Byte(0x00,iic_command);// 0000 0000 ,代表传输的是指令
}

/**
  * @brief  向OLED写入数据
  * @param  iic_data: 写入数据
  * @retval 无
*/
void _Oled_Write_Data(uint8_t iic_data)
{
    _Oled_Write_Byte(0x40,iic_data);// 0100 0000,代表传输的是数据

}

/**
  * @brief  向OLED写入一字节
  * @param  addr:控制字节
  *         data:写入的数据
  * @retval 无
*/
void _Oled_Write_Byte(uint8_t addr,uint8_t data)
{
    _IIc_Start();               //起始信号
    _IIc_Send_Byte(ADDRESS);    //发送从机地址
    _IIc_Wait_Ack();            //等待应答信号
    _IIc_Send_Byte(addr);       //发送控制字节
    _IIc_Wait_Ack();            //等待应答信号
    _IIc_Send_Byte(data);       //发送一个字节
    _IIc_Wait_Ack();            //等待应答
    _IIc_Stop();                //停止信号

}

2.8.2 Oled初始化

  SSD1306指令过多,可以参照下面图发送初始化指令,也可以根据DataSheet自行修改。
【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)
  附上我的初始化代码

uint8_t command[]={
0xAE, 0x20, 0x10, 0xb0, 0xc8, 0x00, 0x10, 0x40, 0x81, 0xff, 0xA1,

0xA6, 0xA8, 0x3F, 0xA4, 0xD3, 0x00, 0xD0, 0xF0, 0xD9, 0x22, 0xDA,

0x12, 0xDB, 0x20, 0x8D, 0x14, 0xAF};

/**
  * @brief  写入初始化指令
  * @param  无
  * @retval 无
*/
void _Oled_Init()
{
    uint8_t i=0;
    HAL_Delay(200);//延时200MS,很重要必须得有
    for(i=0;i<28;i++)
    _Oled_Write_Cmd(command[i]);
    _Oled_Clear();
}

2.8.3功能函数

  成功对Oled屏幕写入字节之后,就可以通过写入指令和数据实现一些简单的功能,比如显示字符,字符串,汉字,图片,绘制点,线、也可以通过发送指令实现滚动显示,屏幕旋转,正反显示等。复杂一点的还可以写OLED菜单;具体实现不过多复述,附上本人的打包文件,代码,文件,教程,数据手册已经打包好了。

  • 字符通常占据6x8、8x16个像素点。
  • 一个汉字大小通常占据16x16个像素点。
  • 显示图片的大小不能超过128x64。

  可以通过pctolcd2002对汉字和图片取模,对于像素过大的图片可以使用imageled缩小。
  具体教程请搜索网络,点击查看imageled教程

2.8.4 演示效果

【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)

3 cubeMX配置硬件IIC

写累了,抽空再写文章来源地址https://www.toymoban.com/news/detail-420601.html

到了这里,关于【STM32CubeMX】教程二_IIC驱动0.96oled屏幕(SSD1306)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32配合CubeMX硬件SPI驱动0.96寸OLED

    目录 一、简单介绍 1.1 OLED 1.2 SPI协议 接口 优点 缺点 数据传输 二、实战 2.1 工程配置 2.2 测试工程 2.3 波形分析 三、驱动OLED 3.1 初始化代码 3.2 清屏函数 3.3 设置坐标函数 3.4 显示字符函数 3.5 显示字符串函数 3.6 显示图片函数 附录 驱动代码文件 oled.c oled.h f6x8.h 1.1 OLED 有机发

    2024年02月02日
    浏览(16)
  • STM32配合cubeMX硬件I2C驱动0.96寸OLED

    目录 一、简单介绍 1.1   OLED 1.2   I2C协议 二、实战 2.1 工程配置 2.2 测试工程 2.3 波形分析 三、驱动OLED 3.1 初始化代码 3.2 清屏函数 3.3 设置坐标函数 3.4 显示字符函数 3.5 显示字符串函数 3.6 显示图片函数 附录 驱动代码文件 oled.c oled.h f6x8.h 有机发光二极管 (英语:Organic

    2024年02月08日
    浏览(17)
  • 一个简单的HAL库STM32使用DMA+硬件IIC驱动0.96寸OLED的方法

    自己在刚入坑嵌入式的时候,加入学校科协的一道免试题是开发一个简易的示波器,当时萌新不会做,中间又在准备比赛没时间,最近帮女朋友做课设需要做一个简易的交流电压表,而且终于有空做一下自己感兴趣的项目了,就想到了之前想做有没得做的一个简易示波器。

    2024年02月19日
    浏览(18)
  • STM32初学入门笔记(5):使用STM32CubeMX通过SPI,IIC驱动OLED屏幕

    随着时代的进步,OLED显示屏成为了继LCD显示屏之后的新一代显示屏技术,OLED具有可视角高,功耗低,厚度薄,耐冲击、振动能力强,像素响应时间低等优点,在嵌入式开发中,OLED显示器也是一个主要的部分,制作OLED显示模块的驱动也是学习STM32路上的重要一部分,本篇将从

    2024年02月04日
    浏览(18)
  • stm32使用模拟IIC控制四针0.96寸OLED

    STM32系列模拟IIC控制0.96寸OLED方法 首先说为什么要采用模拟IIC来控制OLED,采用STM32系列单片机硬件IIC时有可能出现程序死掉的情况,我遇到的情况是与程序while的使用有关(听说原因很随机)。这个时候我们可以采用两个GPIO来模拟IIC通信控制OLED屏幕。顺带说一下OLED的使用原理

    2024年02月14日
    浏览(33)
  • 0.96OLED 4针IIC STM32-HAL库版本(附源码)

    OLED源码放在文章末,有需要自己下滑取用即可。关于如何移植到自己定义的引脚上也做了说明。 另外,本人在代码中封装了一个OLED显示的接口,方便开发者对字符显示位置的快速定位,以及像C语言printf()函数一样在屏幕上进行int,float,char等变量的格式化输出。非常方便实用

    2023年04月26日
    浏览(66)
  • STM32--7针0.96寸OLED屏幕显示(4线SPI)

    本文介绍基于STM32F103C8T6+0.96寸OLED(7针)的显示(完整程序代码见文末链接) 一、简介 OLED,即有机发光二极管( Organic Light Emitting Diode)。 OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较

    2024年01月16日
    浏览(24)
  • 0.96寸OLED(SSD1306)屏幕显示(二)——超长文字水平滚动

    (一)基础功能介绍 (二)超长文字水平滚动 (三)屏幕垂直水平滚动 文章目录 前言 一、内置水平滚动方法 二、自定义水平滚动方法 总结 最近,我突发奇想去翻阅了一些我本科期间所做的一些小项目,发现都挺有意思的!当年做这些项目的时候可走了很多弯路,所以想

    2023年04月08日
    浏览(16)
  • STM32F103硬件IIC控制4针0.96寸OLED显示屏

    OLED使用的0.96寸四针屏幕,以下直接看实际操作。 使用PCtoLCD2002软件提取OLED字模。 注意红色方框的选项内容,不要选错了,选错会导致烧录程序后无法显示。 此为硬件IIC,如果使用过我的模拟IIC控制程序可直接看 void OLED_Write_Command(unsigned char IIC_Command); void OLED_Write_Data(unsig

    2024年02月02日
    浏览(22)
  • STM32F103模拟IIC控制4针0.96寸OLED显示屏

    OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为

    2023年04月24日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包