IIC接口引脚分配
SSD1306在I2C总线模式下的接口分配
数据/命令引脚 | |||
---|---|---|---|
[D7:D3] | D2 | D1 | D0 |
共阴 | SDA_OUT | SDA_IN | SCL |
控制引脚 | ||||
---|---|---|---|---|
E | R/W# | CS# | D/C# | RES# |
共阴 | 共阴 | 共阴 | SA0 | RES# |
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必须先识别从机地址。 设备将响应具有以下字节格式的字节:
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 0 | SA0 | R/W# |
”D/C#“作为SA0用于从地址选择。SA0位为从机地址提供扩展位。 “0111100”或“0111101”均可作为SSD1306的从机地址。
“R/W#”用于确定IIC总线接口的操作模式。 R/W#=1,为读取模式。 R/W#=0,为写入模式。
-
从机在每接收到一个命令字节或数据字节后都将产生应答信号。
-
当需要写入完成时,通过停止条件结束数据通信。停止条件是在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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通