IIC协议

IIC全称Inter-Integrated Circuit (集成电路总线),由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双工同步通信方式。

IIC构成

IIC串行总线有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。两条线都接上拉电阻,以确保总线空闲时刻为高电平,其中时钟信号是由主控器件产生。IIC总线支持多设备连接,允许多主机存在,对于并联在一条总线上的每个IIC设备都有唯一的地址(即靠地址来区分每一个IIC设备)。




IIC特点

  • 简单性和有效性:由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件

  • 多主控(multimastering):其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。

IIC传输数据过程的三种信号

起始信号

当时钟线(SCL)为高平时,数据线(SDA)从高电平跳变到低电平。

时序图




终止信号

当时钟线(SCL)为高平时,数据线(SDA)从低电平跳变到高电平。

时序图




应答信号

主机每发送一个字节(8个bit),就在第9个时钟脉冲期间释放数据线(SDA),由从机反馈一个应答信号。

  • 应答信号(SDA)为低电平时,规定为有效应答位(ACK,简称应答位),表示从机成功地接收了该字节。

  • 应答信号(SDA)为高电平时,规定为非应答位(NACK),一般表示从机接收该字节没有成功。

时序图




IIC发送/接收一个字节数据

IIC总线时序图




起始信号函数


/_ 起始信号 _/


void IIC_start()


{


iic_scl(1);


iic_sda(1);


iic_delay(); /_ 延时多长时间取决于从机要求 _/


iic_sda(0);


iic_delay();


iic_scl(0);


iic_delay(); /_ 钳住总线准备发送/接收数据 _/


}

终止信号函数


/_ 终止信号 _/


void IIC_stop()


{


iic_sda(0);


iic_delay(); /_ 延时多长时间取决于从机要求 _/


iic_scl(1);


iic_delay();


iic_sda(1);


iic_delay();


}

应答信号函数(从机)


/_ 发送应答信号 _/


void iic_ack()


{


iic_scl(0);


iic_delay();


iic_sda(0); /_ 拉低数据线,ACK信号 _/


iic_delay();


iic_scl(1);


iic_delay();


}

非应答信号函数(从机)


/_ 发送非应答信号 _/


void iic_nack()


{


iic_scl(0);


iic_delay();


iic_sda(1); /_ 拉高数据线,NACK信号 _/


iic_delay();


iic_scl(1);


iic_delay();


}

检测应答信号(主机)


/_ 检测应答信号:ACK返回0,NACK返回1 _/


uint8_t iic_wait_ack()


{


iic_sda(1); /_ 释放数据线 _/


iic_delay();


iic_scl(1); /_ 从机返回ACK _/


iic_delay();





/_ 读取SDA的电平 _/


if(iic_read_sda){


/_ 如果是高电平则为NACK _/


iic_stop();


return 1;


}





iic_scl(0); /_ 结束应答信号的检测 _/


iic_delay();


return 0;


}

发送一个字节数据函数


/_ 发送一个字节数据 _/


void iic_send_byte(uint8_t data)


{


for(uint8_t i=0;i<8;i++){


/_ 从最高位开始发送 _/


if((data & 0x80) >> 7){


iic_sda(1);


}else{


iic_sda(0);


}


iic_delay();


iic_scl(1);


iic_delay();


iic_scl(0);


data << 1; /_ 将下一位移至最高位 _/


}


iic_scl(1); /_ 发送完成,释放数据线_/


}

读取一个字节数据函数





/_ 读取一个字节数据 _/


uint8_t iic_send_byte(uint8_t ack)


{


uint8_t receive = 0;


for(uint8_t i=0;i<8;i++){


/_ 发送数据时,从高位先发送 _/


receive = receive << 1; /_ 先收到的数据要左移 _/


iic_scl(1);


iic_delay();


if(iic_read_sda){


receive++;


}


iic_scl(0);


iic_delay();


}


if(!ack){


iic_nack();


}else{


iic_ack()


}


return receive;


}

IIC相关HAL库驱动介绍

STM32的hal库关于IIC的函数

HAL_I2C_Mem_Write()

向某个IIC设备发送一个字节数据。


原型:

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef _hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t _pData, uint16_t Size, uint32_t Timeout)



参数:

I2C_HandleTypeDef _hi2c:IIC句柄

uint16_t DevAddress:IIC设备地址

uint16_t MemAddress:内部内存地址

uint16_t MemAddSize:内部内存地址大小

uint8_t _pData:数据

uint16_t Size:数据大小

uint32_t Timeout:超时时间



实例:

HAL_I2C_Mem_Write(&hi2c1,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&writeCmd,1,0xff); /_ 向OLED发送一个字节命令 _/

IIC基本使用步骤

  1. IIC外设初始化:MX_I2C1_Init()

使用STM32CbeMX配置,不用关心此函数

  1. 使能IIC时钟和初始化IIC相关引脚:HAL_I2C_MspInit()

  • 使能SCL和SDA对应时钟:HAL_RCC_GPIOB_CLK_ENABLE()。

 

  • 设置GPIO工作模式(方式1):SDA开漏输出模式,SCL推挽输出模式。

 

  • IIC的SDA引脚既要作为输出,又要作为输入,使用开漏输出模式,很好实现了输入输出共用,避免IO模式频繁切换带来的麻烦。

 

  1. 输出时:主机(MCU)输出0,可以拉低信号;来实现低电平发送,主机输出1(实际不起作用),由外部上拉电阻上拉,实现高电平发送。

 

  1. 输入时:主机(MCU)设置输出1状态,此时因为MCU无法输出1,相当于释放了SDA数据线,此时外部器件可以主动拉低SDA数据线/释放SDA数据线(同样由上拉电阻提供“输出1的功能”),实现SDA数据线的高低电平变化。

 

  1. 由于开漏输出模式下,MCU还是可以读取IDR状态寄存器,来获取引脚高低电平,因此MCU读取IDR,即可以获得SDA引脚的高低电平状态,从而实现输入输出检测。

 

  • 设置GPIO工作模式(方式2):SCL输出模式,SDA输出模式或者输入模式

 

  1. 由于SDA引脚既要作为输出又要作为输入,我们可以将SCL引脚配置成输出引脚,SDA引脚不进行配置,在gpio.c中定义一个函数,以便随时可以修改SDA引脚为输入引脚或者输出引脚。

 

 

3. 编写基本信号函数

 

起始信号、终止信号、应答信号、非应答信号、检测应答信号。

 

4.编写写数据函数和读数据函数

 

发送一个字节函数、读取一个字节函数。

 

 

 

OLED屏

 

OLED写入指令或数据

 




 

①选择OLED屏

 

写入0x78,选择第一个OLED屏,写入0x7A选择第二个OLED屏

 

②选择命令还是数据

 

选择命令写入0x00,选择数据写入0x40

 

③传入信息

 

将命令或数据传入

 

 

OLED的寻址模式(在OLED上哪里显示字符)

 

OLED显示屏是一个128列_64行的点阵,垂直方向由8个PAGE控制,每个PAGE控制8个点阵。

 

 

选择PAGE(在垂直方向的哪个位置显示):

 

向OLED写入指令0xBx,即b(1011 0xxx),例如选择Page 3时,写入指令0xB3,即b(1011 0011)。

 




 

 

选择列(在水平方向的哪个位置显示):

 

向OLED写入指令0x0x和0x1x,即b(0000 xxxx)或b(0001 xxxx)

 

例如

 

  • 选择第1列时,写入指令0x00,即b(0000 0000)和写入指令0x10即b(0001 0000)。 它由第一条指令的低四位和第二条指令的低三位组成七位来控制水平方向的128个点阵

 

  • 选择第64列时,写入指令0x0F,即b(0000 1111)和写入指令0x13即b(0001 0011)。

 




 

 

OLED的三种地址模式

 

页地址模式

 




 

 

水平地址模式

 




 

垂直地址模式

 




 

 

选择寻址模式(在一个PAGE上写满数据后,数据从哪里继续开始):

 

向OLED写入指令0x20后,继续写入指令0x0x,即b(0000 00xx),例如选择页寻址时,写入指令0x02,即b(000 0010)。

 




 

 

OLED初始化

 

写入一下命令来对4针OLED进行初始化

 




 

 




 

 

 

OLED显示自己名字

 

软件IIC

 

OLED与STM32板子接线

 

  • PB6<->SCL

 

  • PB7<->SDA

 

 

STM32CubeMX相关配置

 

配置SYS

 




 

 

配置RCC

 




 




 

 

配置GPIO

 

  • PB6引脚配置成输出高电平模式。

 

  • OLED的SDA引脚(PB7)既需要输入也需要输出,因此需要自己在main函数中配置,无法使用STM32CubeMX配置。

 




 

 

main函数编写

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
 
/* USER CODE BEGIN PV */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
//OLED的字符构造点阵
unsigned char oledFont[]=
{
  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
};
 
//OLED写入一条指令
void oledWriteCmd(uint8_t writeCmd)
{
    HAL_I2C_Mem_Write(&hi2c1,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&writeCmd,1,0xff);
}
 
 
//OLED写入一个数据
void oledWriteData(uint8_t writeData)
{
    HAL_I2C_Mem_Write(&hi2c1,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&writeData,1,0xff);
}    
 
 
//OLCD初始化
void oledInit()
{
    oledWriteCmd(0xAE);
    oledWriteCmd(0x00);
    oledWriteCmd(0x10);
    oledWriteCmd(0x40);
    oledWriteCmd(0xB0);
    oledWriteCmd(0x81);
    oledWriteCmd(0xFF);
    oledWriteCmd(0xA1);
    oledWriteCmd(0xA6);
    oledWriteCmd(0xA8);
    oledWriteCmd(0x3F);
    oledWriteCmd(0xC8);
    oledWriteCmd(0xD3);
    oledWriteCmd(0x00);
    oledWriteCmd(0xD5);
    oledWriteCmd(0x80);
    oledWriteCmd(0xD8);
    oledWriteCmd(0x05);
    oledWriteCmd(0xD9);
    oledWriteCmd(0xF1);
    oledWriteCmd(0xDA);
    oledWriteCmd(0x12);
    oledWriteCmd(0xDB);
    oledWriteCmd(0x30);
    oledWriteCmd(0x8D);
    oledWriteCmd(0x14);
    oledWriteCmd(0xAF);
}
 
//OLED清屏
void olceClean()
{
    int i,j;
    for(i=0;i<8;i++){
        oledWriteCmd(0xB0 + i);  //选择PAGE
        //选择PAGE的第0列开始显示
        oledWriteCmd(0x00);  
        oledWriteCmd(0x10);
        for(j = 0;j < 128; j++){
            oledWriteData(0);  //写入字符0
        }
    }
}
 
//OLED显示一个字符
void oledShowByte(char rows,char columns,char oledByte)
{ 
    unsigned int i;
 
    //显示字符的上半部分
    oledWriteCmd(0xb0+(rows*2-2));  //选择行
    
    //选择列                        
    oledWriteCmd(0x00+(columns&0x0f));                          
    oledWriteCmd(0x10+(columns>>4));      
    
    //显示数据                       
    for(i=((oledByte-32)*16);i<((oledByte-32)*16+8);i++){
        oledWriteData(oledFont[i]);                            
    }
 
     //显示字符的上半部分
    oledWriteCmd(0xb0+(rows*2-1));  //选择行  
    
    //选择列                    
    oledWriteCmd(0x00+(columns&0x0f));                          
    oledWriteCmd(0x10+(columns>>4)); 
    
    //显示数据                           
    for(i=((oledByte-32)*16+8);i<((oledByte-32)*16+8+8);i++){
        oledWriteData(oledFont[i]);                            
    }       
}
 
 
//OLED显示一个字符串
void oledShowString(char rows,char columns,char *str)
{
    while(*str != '\0'){
        oledShowByte(rows,columns,*str);
        str++;
        columns += 8;   
    }       
}
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
 
    oledInit();  //OLED初始化
    olceClean();  //OLED清屏函数
    
    //设置寻址模式
    oledWriteCmd(0x20);  //设置内存
    oledWriteCmd(0x02);  //选择页寻址模式
    
    olceClean();  //清屏函数
    
    oledShowString(1,1,"jiangxiaoya");  //在第一行第一列显示自己的名字
 
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */