打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  337 随笔 :: 0 文章 :: 2 评论 :: 70952 阅读

IIC接口引脚分配

SSD1306在I2C总线模式下的接口分配

数据/命令引脚
[D7:D3]D2D1D0
共阴SDA_OUTSDA_INSCL
控制引脚
ER/W#CS#D/C#RES#
共阴共阴共阴SA0RES#

IIC通信接口由总线的数据信号SDA(SDA_OUT和SDA_IN)和总线的时钟信号SCL组成。 数据和时钟信号必须连接上拉电阻。

SA0 为从机地址引脚,
RES#为设备的初始化引脚。

1.SDA 数据信号线

SDA是主机和从机间进行数据收发和应答的通道。需注意的是,SDA引脚的ITO 电阻和上拉电阻有一个潜在的分压,

结果就是,SDA线上的应答信号可能达不到有效的低电平。

SDAOUT和SDAIN连接在一起由数据信号线SDA引出,SDAIN引脚必须连接以充当SDA。SDAOUT引脚可能断开。

当SDAOUT引脚断开时,I2C总线中的应答信号将被忽略。

2.SCL 时钟信号线

信息在IIC总线中的传输遵循时钟信号SCL。 数据位的每次传输都是在SCL的单个时钟周期内进行的。

3.SA0 丛机地址位

在IIC总线发送或接收任何信息之前,SSD1306必须先识别从机地址。 设备将响应具有以下字节格式的字节:

bit7bit6bit5bit4bit3bit2bit1bit0
011110SA0R/W#

”D/C#“作为SA0用于从地址选择。SA0位为从机地址提供扩展位。 “0111100”或“0111101”均可作为SSD1306的从机地址。
“R/W#”用于确定IIC总线接口的操作模式。 R/W#=1,为读取模式。 R/W#=0,为写入模式。

  1. 从机在每接收到一个命令字节或数据字节后都将产生应答信号。

  2. 当需要写入完成时,通过停止条件结束数据通信。停止条件是在SCL保持高电平期间捕获到SDA的一个上升沿。

注意:
1.除了启动及停止的状况下,它要求数据位在每一个时钟周期的高电平期间保持稳定,不可以进行改变。
2.数据线和时钟线都需要接外接上拉电阻。

/********************************************************************************
* @file    oled_core.c
* @author  jianqiang.xue
* @Version V1.0.0
* @Date    2021-08-07
* @brief   参考:https://www.cnblogs.com/Gimiracle/p/13520991.html
* 笔记:
* 在得到应答后,发送一个控制字节,由Co位和D/C位及尾部000000组成。
* D7 D6   D5 D4 D3 D2 D1 D0
* Co D/C# 0  0  0  0  0  0
* a)Co位为0,则后续字节均为数据。D/C#位确定下一个数据字节作为命令或数据。
* b)D/C#位设置为“0”,后续数据字节定义为命令。 D/C#位设置为“1” ,后续数据字节定义为数据,并存储在GDDRAM上。
*   每次数据写入后,GDDRAM列地址指针将自动增加一个。
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "bsp_i2c.h"
/* Private includes ----------------------------------------------------------*/
#include "oled_core.h"
#include "SSD1306.h"
#include "os_api.h"
/* Private define ------------------------------------------------------------*/
#define FUNC_CMD  0x00
#define FUNC_DATA 0x40
/* Private typedef -----------------------------------------------------------*/
static const oled_cfg_t g_oled_info =
{
    .i2c_bus  = I2C_BUS0,
    .dev_addr = 0x78,
    .x_max    = 128,
    .y_max    = 64,
};
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static bool g_oled_state = false;

static const uint8_t g_cmd_oled_init_cfg[] = {
    FUNC_CMD, /*命令类*/
    0xAE, /*关闭oled面板*/
    0x00, /*设置低列地址*/
    0x10, /*设置高列地址*/
    0x40, /*设置起始行地址*/

    0x81, /*对比度设置,可设置亮度*/
    0XFF, /*对比度值0-255*/

    0XA1, /*设置分段/列映射     0xa0左右反置 0xa1正常*/
    0XC8, /*设置COM/行扫描方向   0xc0上下反置 0xc8正常*/
    0XA6, /*设置正常显示 0xa7逆显示*/

    0XA8, /*设置多路复用比率(1到64)*/
    0X3F, /*1/64负荷*/

    0XD3, /*设置显示偏移移位映射RAM计数器*/
    0x00, /*RAM计数器值:0x00~0x3F*/

    0XD5, /*设置显示分时比/振荡器频率*/
    0X80, /*设置分频比,将时钟设置为100帧/秒(默认值)*/

    0XD9, /*设置 预充电周期*/
    0XF1, /*预充电设为15时钟,放电设为1时钟*/

    0XDA, /*设置com引脚硬件配置*/
    0X12, /*默认值*/

    0XDB, /*设置 共通电位 (高)*/
    0X40, /*设置VCOM取消选择级别*/

    0X20, /*设置页面寻址模式(0x00/0x01/0x02)*/
    0X02, /*默认值*/

    0X8D, /*设置预充电 启用/禁用*/
    0X14, /*set(0x10) disable*/

    0XA4, /*A4h,X0 =0b:恢复 RAM内容的显示(RESET)*/
    0XA6, /*A6h, X[0]=0b:正常显示(RESET)*/
};

static const uint8_t g_cmd_oled_open_display[] = {
    FUNC_CMD, /*命令类*/
    0X8D, /*设置 共通电位 (高)*/
    0X14,
    0XAF  /*显示开,正常模式 */
};

static const uint8_t g_cmd_oled_close_display[] = {
    FUNC_CMD, /*命令类*/
    0X8D, /*设置 共通电位 (高)*/
    0X14,
    0XAE  /*显示关 (睡眠模式)*/
};

static const uint8_t g_cmd_oled_null[129] = {FUNC_DATA, 0};

static uint8_t g_oled_data_buff[128] = {0};
/* Public function prototypes -----------------------------------------------*/

/**
 * @brief  oled初始化
 * @note   由于单片机上电初始化比OLED快,所以必须加上延迟,等待OLED上复位完成,约100-200ms
 * @retval None
 */
uint8_t oled_init(void)
{
    return bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                               (uint8_t *)g_cmd_oled_init_cfg, sizeof(g_cmd_oled_init_cfg));
}

/**
 * @brief  得到当前状态
 * @note   NULL
 * @retval 0--空闲 1--忙
 */
bool oled_get_state(void)
{
    return g_oled_state;
}

uint8_t oled_get_x_max(void)
{
    return g_oled_info.x_max;
}

uint8_t oled_get_y_max(void)
{
    return g_oled_info.y_max;
}

void oled_cls(void)
{
    if (g_oled_state)
    {
        return;
    }
    g_oled_state = true;
    uint8_t data[] = {FUNC_CMD, 0xb0, 0x00, 0x10};
    for (uint8_t i = 0; i < g_oled_info.y_max / 8; i++)
    {
        data[1] = 0xb0 + i;
        bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                            data, sizeof(data));
        bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                            (uint8_t *)g_cmd_oled_null, sizeof(g_cmd_oled_null));
    }
    g_oled_state = false;
}

void oled_clear(uint8_t x, uint8_t y, uint8_t x1, uint8_t y1)
{
    if (g_oled_state)
    {
        return;
    }
    g_oled_state = true;
    uint8_t data[] = {FUNC_CMD, 0xb0, 0x00, 0x10};
    for (uint8_t i = y; i < y1; i++)
    {
        data[1] = 0xb0 + i;
        data[2] = (x & 0x0F);
        data[3] = ((x & 0xF0) >> 4) | 0x10;
        bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                            data, sizeof(data));
        bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                            (uint8_t *)g_cmd_oled_null, x1-x);
    }
    g_oled_state = false;
}

uint8_t oled_open_display(void)
{
    return bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                               (uint8_t *)g_cmd_oled_open_display, sizeof(g_cmd_oled_open_display));
}

uint8_t oled_close_display(void)
{
    return bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                               (uint8_t *)g_cmd_oled_close_display, sizeof(g_cmd_oled_close_display));
}

uint8_t oled_set_pos(uint8_t x, uint8_t y)
{
    uint8_t data[] = {FUNC_CMD, 0xb0, 0x00, 0x00};
    data[1] += y;
    data[2] = ((x & 0xF0) >> 4) | 0x10;
    data[3] = (x & 0x0F);
    return bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                               data, sizeof(data));
}

uint8_t oled_write_data(uint8_t *data, uint16_t len)
{
    if (g_oled_state)
    {
        return OS_EVENT_TIMEOUT;
    }
    g_oled_state = false;

    memset(g_oled_data_buff, 0, len + 1);
    g_oled_data_buff[0] = FUNC_DATA;
    memcpy(g_oled_data_buff + 1, data, len);
    return bsp_i2c_write_nbyte(g_oled_info.i2c_bus, g_oled_info.dev_addr,
                               g_oled_data_buff, len+1);
}

/* Private function prototypes -----------------------------------------------*/


#ifndef __OLED_CORE_H
#define __OLED_CORE_H

#include <stdint.h>
#include <stdbool.h>
#include "bsp_i2c.h"

typedef struct
{
    bsp_i2c_bus_t i2c_bus;
    uint8_t dev_addr;      // 8bit addr
    uint8_t x_max;
    uint8_t y_max;
}oled_cfg_t;

uint8_t oled_init(void);
uint8_t oled_uninit(void);

bool oled_get_state(void);
uint8_t oled_get_x_max(void);
uint8_t oled_get_y_max(void);

uint8_t oled_open_display(void);
uint8_t oled_close_display(void);

void oled_cls(void);
void oled_clear(uint8_t x, uint8_t y, uint8_t x1, uint8_t y1);

uint8_t oled_set_pos(uint8_t x, uint8_t y);
uint8_t oled_write_data(uint8_t *data, uint16_t len);

#endif

posted on   xuejianqiang  阅读(426)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033
点击右上角即可分享
微信分享提示