IIC简介

IIC(Inter-Integrated Circuit,又称为I2C或I²C)是一种简单而灵活的串行通信协议,用于连接微控制器和外部设备,例如传感器、存储器、显示器等。

基本原理

  • 双线制: I2C使用两根线来进行通信:串行数据线(SDA)和串行时钟线(SCL)。SDA线上的数据在SCL线的时钟信号下进行同步传输。

  • 主从结构: I2C通信中,设备分为主设备(通常是微控制器)和从设备(例如传感器或存储器)。主设备负责发起通信和控制通信的时序,而从设备响应主设备的指令。

  • 地址寻址: 每个I2C设备都有一个唯一的7位或10位地址,主设备通过发送目标设备的地址来选择通信对象。

通信过程

  1. 启动条件(Start): 主设备发出一个启动信号,即SDA线从高电平转为低电平,而SCL线保持高电平状态

  2. 发送地址和读写位: 主设备发送目标设备的地址,并指定是读取数据还是写入数据。

  3. 地址确认(ACK): 从设备接收到地址后会发送应答信号(ACK),表示准备好与主设备通信。

  4. 数据传输: 主设备或从设备在SCL时钟信号的边缘上发送或接收数据位。

  5. 停止条件(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总线在传送数据过程中共有三种类型信号, 它们分别是:起始信号、停止信号和应答信号。其基本读写过程如图:

代码编写

/*

  1. GPIO口软件模拟IIC时序,实现IIC通讯

  2. 跟OLED屏幕通讯

*/

//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_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;
			
	
	OLED_ShowLove(2,7);
	OLED_ShowLove(2,8);

	
	OLED_ShowLove(2,15);
	OLED_ShowLove(2,16);
	
    OLED_ShowNum(3,1,1,1);
    
	while(1)
	{
		
	}
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
I协议是指Inter-Integrated Circuit协议,用于在集成电路之间进行通信。而EEPROM是指Electrically Erasable Programmable Read-Only Memory,即电可擦除可编程只读存储器。通过IIC协议,可以实现与EEPROM的通信,并对其进行读写操作。EEPROM通常用于存放用户配置信息数据。 使用IIC协议与EEPROM通信的过程中,可以实现page写、current read、random read、sequential read等命令。其中,page写是将数据写入EEPROM的一页,current read是连续读取数据,random read是随机读取特定地址的数据,sequential read是按顺序读取数据。通过这些命令,可以实现对EEPROM的灵活读写操作。 使用IIC协议与EEPROM通信的实例中,通常会将掉电保存的数据存储到EEPROM中,以保证数据的持久性。这样,在重新上电后,可以从EEPROM中读取之前保存的数据。这对于一些需要长期保存数据的应用场景非常有用。 总之,使用IIC协议与EEPROM通信,可以实现对EEPROM的读写操作,对于存放用户配置信息数据等应用场景非常适用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [通信协议之IIC协议(eeprom)_通俗易懂篇!](https://blog.csdn.net/fpga_Spig/article/details/118143650)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [IIC协议EEPROM实验.7z](https://download.csdn.net/download/weixin_43491077/16732506)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [IIC通讯协议与EEPROM简介](https://blog.csdn.net/qq_41290252/article/details/120053636)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值