IIC简介
IIC(Inter-Integrated Circuit,又称为I2C或I²C)是一种简单而灵活的串行通信协议,用于连接微控制器和外部设备,例如传感器、存储器、显示器等。
基本原理
-
双线制: I2C使用两根线来进行通信:串行数据线(SDA)和串行时钟线(SCL)。SDA线上的数据在SCL线的时钟信号下进行同步传输。
-
主从结构: I2C通信中,设备分为主设备(通常是微控制器)和从设备(例如传感器或存储器)。主设备负责发起通信和控制通信的时序,而从设备响应主设备的指令。
-
地址寻址: 每个I2C设备都有一个唯一的7位或10位地址,主设备通过发送目标设备的地址来选择通信对象。
通信过程
-
启动条件(Start): 主设备发出一个启动信号,即SDA线从高电平转为低电平,而SCL线保持高电平状态。
-
发送地址和读写位: 主设备发送目标设备的地址,并指定是读取数据还是写入数据。
-
地址确认(ACK): 从设备接收到地址后会发送应答信号(ACK),表示准备好与主设备通信。
-
数据传输: 主设备或从设备在SCL时钟信号的边缘上发送或接收数据位。
-
停止条件(Stop): 主设备发送一个停止信号,即SDA线从低电平转为高电平,而SCL线保持高电平状态。
优点
-
双向通信(半双工): I2C支持主设备向从设备发送数据,并且支持从设备向主设备发送数据,具有双向通信能力。
-
多设备连接: I2C总线支持多个设备连接到同一条总线上,可以通过设备地址进行选择通信对象。
应用领域
-
传感器接口: 许多传感器(如温度传感器、湿度传感器、加速度传感器等)使用I2C接口与微控制器进行通信。
-
存储器接口: EEPROM、实时时钟(RTC)等存储器设备也常使用I2C接口。
-
显示器接口: 一些OLED和LCD显示器使用I2C接口来传输图像数据和控制命令。
IIC物理层
双线制: I2C通信协议使用两根线进行通信,分别是串行数据线(SDA)和串行时钟线(SCL)。这两根线构成了I2C总线,在总线上连接了所有的I2C设备。(数据线即用来表示数据,时钟线用于数据收发同步)
开漏输出: I2C总线上的信号是开漏输出的,这意味着每个I2C设备的输出引脚都是一个开漏输出,可以通过外部上拉电阻拉高。这种设计允许多个设备共享同一根总线,而不会出现信号冲突和短路。(当I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。)
数据传输: 数据传输是以字节为单位进行的,每个字节都包括8个数据位和1个ACK位。传输的起始和停止由特定的序列来定义,包括起始条件(Start)和停止条件(Stop)。
时钟同步: I2C通信是通过主设备发送的时钟信号来同步的。主设备负责产生时钟信号,并且所有的数据传输都是在时钟信号的边沿上进行的。
地址寻址: 每个I2C设备都有一个唯一的7位或10位地址,主设备通过发送目标设备的地址来选择通信对象。地址的长度取决于设备的规格和协议版本。
数据速率: I2C总线的数据传输速率通常可以选择为100kHz、400kHz或1MHz等不同的速率。速率的选择取决于系统要求和设备的兼容性。
总线仲裁: 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
IIC协议层
I2C总线在传送数据过程中共有三种类型信号, 它们分别是:起始信号、停止信号和应答信号。其基本读写过程如图:
代码编写
-
GPIO口软件模拟IIC时序,实现IIC通讯
-
跟OLED屏幕通讯
iic.h
//iic.h
#ifndef __IIC_H
#define __IIC_H
#include "public.h"
//选择PE3和PE4 做为通讯引脚 PE3:SCL PE4:SDA
#define RCC_IIC_SCL RCC_AHB1Periph_GPIOE //端口时钟
#define IIC_SCL_PORT GPIOE //端口号
#define IIC_SCL GPIO_Pin_3 //引脚
#define RCC_IIC_SDA RCC_AHB1Periph_GPIOE
#define IIC_SDA_PORT GPIOE
#define IIC_SDA GPIO_Pin_4
//io操作
#define IIC_SCL_H GPIO_SetBits(IIC_SCL_PORT,IIC_SCL); //SCL置1
#define IIC_SCL_L GPIO_ResetBits(IIC_SCL_PORT,IIC_SCL);//SCL置0
#define IIC_SDA_H GPIO_SetBits(IIC_SDA_PORT,IIC_SDA); //SDA置1
#define IIC_SDA_L GPIO_ResetBits(IIC_SDA_PORT,IIC_SDA);//SDA置0
#define READ_SDA GPIO_ReadInputDataBit(IIC_SDA_PORT,IIC_SDA)//读取SDA输入引脚电平
void IICx_GPIO_Init(void);
void IIC_SDA_OUT(void);
void IIC_SDA_IN(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_ACK(void);
void IIC_NACK(void);
void IIC_SendByte(uint8_t data);
uint8_t IIC_ReadByte(uint8_t ack);
uint8_t IIC_WaitACK(void);
uint16_t BH1750_ReadData(void);
#endif
//iic.c
#include "public.h"
void GPIO_IIC(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_OType=GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//flag = 1 读 flag = 0 写
void change_GPIO_mode(flag)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed; //引脚响应速度
if(flag == 1)
{
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN; //读
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
}
if else(flag == 0)
{
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT; //写
GPIO_InitStructure.GPIO_Otype=GPIO_OType_OD; // 开漏模式
}
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//SCL保持高电平,SDA先出现下降沿,SCL后出现下降沿
void IIC_start(void)
{
change_GPIO_mode(WRITE);
SCL_H;
SDA_H;
Delay_us(4);
SDA_L;
Delay_us(4);
SCL_L; //SCL,SDA都为低电平,钳住电路等待数据传输
}
//SCL保持高电平,SDA出现上升沿
void IIC_stop(void)
{
change_GPIO_mode(WRITE);
SCL_H;
SDA_L;
Delay_us(4);
SDA_H;
}
//主机应答
void IIC_ack(void)
{
change_GPIO_mode(WRITE);
SCL_L;//先把时钟电平值拉低,处于空闲状态时才能切换SDA。否则产生起始终止信号
SDA_L;//主机SDA始终为低电平,产生应答
Delay_us(1);
SCL_H;
Delay_us(1);
SCL_L;
}
//主机非应答
void IIC_nack(void)
{
change_GPIO_mode(WRITE);
SCL_L;//先把时钟电平值拉低,处于空闲状态时才能切换SDA。否则产生起始终止信号
SDA_H;//主机SDA始终为高电平,非应答
Delay_us(1);
SCL_H;
Delay_us(1);
SCL_L;
}
//IIC发送一个字节
void IIC_send_byte(uint8_t data)
{
change_GPIO_mode(WRITE);
SCL_L;
int i;
for(i = 0;i < 8;i++)
{
if((data&0x80) > 0) //判断最高位是否为1
{
SDA_H;
}
else
{
SDA_L;
}
//Delay_us(1);
SCL_H:
Delay_us(1);
SCL_L;
Delay_us(1);
data <<= 1;
}
}
//IIC读取一个字节
uint8_t IIC_receive_byte(uint8_t ack)
{
change_GPIO_mode(READ);
int i;
uint8_t receive = 0;
for(i = 0;i < 8;i++)
{
SCL_L;
Delay_us(1);
SCL_H;
receive <<= 1;
if(SDA_READ == 1)
{
receive++;
}
Delay_us(1);
}
//确认帧
if(ack)
IIC_ack();
elde
IIC_nack();
return receive;
}
//7位设备地址+1位读写位
void IIC_send_ADDR_WR(uint8_t addr,uint8_t flag)
{
uint8_t data;
data = addr<<1;
data += flag;
IIC_send_byte(data);
}
//等待应答信号,返回0表示应答,返回1表示非应答
uint8_t wait_receive_ack(void)
{
int time = 0;
change_GPIO_mode(READ);
SDA_H;
Delay_us(1);
SCL_H;
Delay_us(1);
while(SDA_READ)
{
time++;
if(time>1000)
{
return ACK_FALLED; // 1 表示非应答
}
}
SCL_L;
return ACK_SUCCESS;// 0 表示应答
}
可以使用取模软件取字模
oled_font.h 字模库
#ifndef __OLED_FONT_H
#define __OLED_FONT_H
#include <stdint.h>
static unsigned char Love_Heart0[8]={0x1C,0x22,0x42,0x84,0x84,0x42,0x22,0x1C};/*"空心图形",0*/
static unsigned char Love_Heart1[8]={0x1C,0x3E,0x7E,0xFC,0xFC,0x7E,0x3E,0x1C};/*"实心图形",1*/
/*OLED字模库,宽8像素,高16像素*/
const uint8_t OLED_F8x16[][16]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
const uint8_t OLED_F10x16[][40]=
{
0x00,0x00,0x10,0x10,0x12,0xFE,0x90,0x10,0x10,0x7E,0x50,0x50,0x50,0x48,0x48,0x44,
0x44,0x70,0x40,0x00,0x00,0x02,0x02,0x42,0x41,0x3F,0x00,0x00,0x00,0x41,0x7E,0x2A,
0x2A,0x2A,0x2A,0x2A,0x7F,0x00,0x00,0x00,/*"指",0*/
0x00,0x40,0x60,0x50,0x48,0xC6,0x60,0x20,0x10,0x10,0xF0,0x12,0x1C,0x10,0x90,0x70,
0x10,0x18,0x10,0x00,0x00,0x20,0x24,0x26,0x15,0x94,0x52,0x52,0x40,0x20,0x20,0x13,
0x0C,0x1C,0x33,0x20,0x60,0x40,0x00,0x00,/*"纹",1*/
0x00,0x40,0x40,0x40,0x44,0x54,0x54,0x54,0x54,0xD4,0xD4,0x54,0x54,0x54,0x7C,0xC0,
0x40,0x40,0x40,0x00,0x00,0x20,0x20,0x10,0x10,0x13,0x0E,0x48,0x44,0x7F,0x3F,0x02,
0x04,0x0A,0x12,0x31,0x21,0x20,0x20,0x00,/*"录",2*/
0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0xC4,0x78,0x70,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x20,0x10,0x08,0x04,0x03,0x01,0x00,0x00,0x01,
0x03,0x0C,0x18,0x10,0x30,0x20,0x20,0x00,/*"入",3*/
0x00,0x80,0x80,0xFC,0x84,0xFC,0x84,0x80,0xFC,0x84,0x84,0xFC,0x80,0x80,0xF8,0x08,
0x00,0xFE,0x02,0x00,0x00,0x40,0x38,0x27,0x20,0x3F,0x40,0x38,0x47,0x40,0x40,0x3F,
0x00,0x00,0x0F,0x40,0x40,0x7F,0x00,0x00,/*"删",4*/
0x00,0x00,0xFC,0x04,0x64,0x94,0x8C,0x44,0x20,0x60,0x58,0x4C,0xC2,0x4C,0x50,0x70,
0x20,0x60,0x00,0x00,0x00,0x00,0x7F,0x04,0x08,0x08,0x47,0x20,0x12,0x0E,0x42,0xC2,
0x7F,0x02,0x02,0x0A,0x12,0x22,0x00,0x00,/*"除",5*/
};
#endif
oled.c
/********************OLED屏幕操作函数***************************/
#include "public.h"
#include "oled_font.h"
void OLED_WriteCommand(uint8_t Command)
{
IIC_Start();
IIC_SendByte(0x78); //从机地址,并且写数据
IIC_WaitACK();
IIC_SendByte(0x00); //
IIC_WaitACK();
IIC_SendByte(Command); // 写入命令
IIC_WaitACK();
IIC_Stop();
}
void OLED_WriteData(uint8_t Data)
{
IIC_Start();
IIC_SendByte(0x78); //从机地址
IIC_WaitACK();
IIC_SendByte(0x40);
IIC_WaitACK();
IIC_SendByte(Data); // 写入命令
IIC_WaitACK();
IIC_Stop();
}
/**
* @brief OLED设置光标位置
* @param Y 以左上角为原点,向下方向的坐a'a'a'a'a'a'a'a'a'a'a'a'a'a'a'a'a'a'a标,范围:0~7
* @param X 以左上角为原点,向右方向的坐标,范围:0~127
* @retval 无
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
//协议规定
OLED_WriteCommand(0xB0 | Y); // 设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); // 设置X位置高4位
OLED_WriteCommand(0x00 | (X & 0x0F)); // 设置X位置低4位
}
/**
* @brief OLED清屏
* @param 无
* @retval 无
*/
void OLED_Clear(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for (i = 0; i < 128; i++)
{
OLED_WriteData(0x00);
}
}
}
/**
* @brief OLED显示一个字符
* @param Line 行位置,范围:1~4
* @param Column 列位置,范围:1~16
* @param Char 要显示的一个字符,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowCN(uint8_t Line, uint8_t Column, uint8_t Num)
{
uint8_t i;
uint8_t wide=20;//字宽
OLED_SetCursor((Line-1)*2, (Column-1)*wide); //参数1:把光标设置在第几页. 参数2:把光标设置在第几列
for (i = 0; i < wide; i++)
{
OLED_WriteData(OLED_F10x16[Num][i]); //显示上半部分内容
}
OLED_SetCursor((Line-1)*2+1,(Column-1)*wide);
for (i = 0; i < wide; i++)
{
OLED_WriteData(OLED_F10x16[Num][i+wide]); //显示下半部分内容
}
}
void OLED_ShowLove(uint8_t Line, uint8_t Column)
{
uint8_t i;
uint8_t wide=8;//字宽
OLED_SetCursor((Line-1)*2, (Column-1)*wide); //参数1:把光标设置在第几页. 参数2:把光标设置在第几列
for (i = 0; i < wide; i++)
{
OLED_WriteData(Love_Heart0[i]); //显示内容
}
OLED_SetCursor((Line-1)*2 + 1, (Column-1)*wide);
for (i = 0; i < wide; i++)
{
OLED_WriteData(Love_Heart1[i]); //显示两行
}
}
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); // 设置光标位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); // 显示上半部分内容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); // 设置光标位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); // 显示下半部分内容
}
}
/**
* @brief OLED显示字符串
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++)
{
OLED_ShowChar(Line, Column + i, String[i]);
}
}
/**
* @brief OLED次方函数
* @retval 返回值等于X的Y次方
*/
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}
/**
* @brief OLED显示数字(十进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~4294967295
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十进制,带符号数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-2147483648~2147483647
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
uint8_t i;
uint32_t Number1;
if (Number >= 0)
{
OLED_ShowChar(Line, Column, '+');
Number1 = Number;
}
else
{
OLED_ShowChar(Line, Column, '-');
Number1 = -Number;
}
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十六进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFFFFFF
* @param Length 要显示数字的长度,范围:1~8
* @retval 无
*/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i, SingleNumber;
for (i = 0; i < Length; i++)
{
SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
if (SingleNumber < 10)
{
OLED_ShowChar(Line, Column + i, SingleNumber + '0');
}
else
{
OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
}
}
}
/**
* @brief OLED显示数字(二进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
}
}
/**
* @brief OLED初始化
* @param 无
* @retval 无
*/
void OLED_Init(void)
{
Delay_ms(100);
OLED_WriteCommand(0xAE); // 关闭显示
OLED_WriteCommand(0xD5); // 设置显示时钟分频比/振荡器频率
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); // 设置多路复用率
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); // 设置显示偏移
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); // 设置显示开始行
OLED_WriteCommand(0xA1); // 设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); // 设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); // 设置COM引脚硬件配置
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); // 设置对比度控制
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); // 设置预充电周期
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); // 设置VCOMH取消选择级别
OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); // 设置整个显示打开/关闭
OLED_WriteCommand(0xA6); // 设置正常/倒转显示
OLED_WriteCommand(0x8D); // 设置充电泵
OLED_WriteCommand(0x14);
OLED_WriteCommand(0xAF); // 开启显示
OLED_Clear(); // OLED清屏
}
main.c
#include "public.h"
/*
1. GPIO口软件模拟IIC时序,实现IIC通讯
2. 跟OLED屏幕通讯(OLED驱动代码不需要我们写,直接复制过来)
3. 跟BH1750光照模块通讯,获取光照信息并打印输出
*/
int main(void)
{
//2号分组:2bit给抢占 2bit给响应 0-3 0-3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SysTick_Init();
USART_Init_Config();
IICx_GPIO_Init();
OLED_Init();
// OLED_ShowString(1,1,"123KKK");
OLED_ShowCN(1,1,0);
OLED_ShowCN(1,2,1);
OLED_ShowCN(1,3,2);
OLED_ShowCN(1,4,3);
OLED_ShowCN(1,5,4);
OLED_ShowCN(1,6,5);
OLED_ShowString(1,16,":");
int i,j;
//for(i = 0;i < 3; i++)
//{
// OLED_ShowName(2,i+1,i);
//}
OLED_ShowLove(2,7);
OLED_ShowLove(2,8);
//for(i = 4;i < 7; i++)
//{
// OLED_ShowName(2,i+1,i-1);
//}
OLED_ShowLove(2,15);
OLED_ShowLove(2,16);
OLED_ShowNum(3,1,1,1);
while(1)
{
}
}