stm32配置总结-iic的使用

本文用到的实验平台:

  • 野火MINI-stm32开发板
  • STM32CUBE-IDE开发工具

1、iic及时序

关于iic的读法,一般说是I²C,就是i to c的意思,意思就是低速设备到高速设备的通信方法,iic一般用于设备与设备之间的低速短距离通信,相比其他总线设备而言就是占用资源少,只需要两根线即可完成数据通信。

一般我们用一个总线通过物理层和协议层来解读,物理层就是这个总线上的设备连接情况,协议层则是通讯逻辑,说的直白点就是电平怎样变化认为是1,怎样变化认为是0。

iic物理层

物理层的连接框图如下所示
在这里插入图片描述

  • 其中SDA为双向串行数据线,SCL为串行时钟线,数据线就是收发数据,时钟线就是用于数据收发同步。
  • 可以看到iic是多机连接的,因此就需要地址来区分不同的设备,每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问,一般从机(大部分是传感器)地址是厂家设定的,但是为了能够多个地址使用,厂家也会预留一些选择,比如设置三个开关,开关的01状态变化就可以使得该传感器可以设置8个不同的地址。
  • 关于总线传输速率,一般iic是有三种速率模式的,但是cubemx上只显示了两种,标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式下可达3.4Mbit/s,可能不支持高速模式吧。

iic协议层

I2C总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。I2C协议规定设备地址可以是7位或10位,实际中7位的地址应用比较广泛。I2C使用SDA信号线来传输数据,使用SCL信号线进行数据同步。SDA数据线在SCL的每个时钟周期传输一位数据。传输时,SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。

以主机向从机写数据为例
在这里插入图片描述
从上面图来看就是:起始信号——从机地址——读写信号——数据位——应答位——… … ——停止位,其中数据位还有应答在不断循环进行,最后是停止
主机向从机中读数据
在这里插入图片描述
分析流程就是:起始信号——从机地址——读写信号——应答位——数据位… … ——停止位,其中数据位还有应答在不断循环进行,最后是停止

关于起始和终止信号:

可以根据这张图来编写起始和终止信号
在这里插入图片描述

关于应答和非应答

每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,从机应答主机所需要的时钟仍是主机提供的,应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,高电平1表示非应答注意这个应答是主机发送的)

在这里插入图片描述

关于数据的有效性

SDA数据线在SCL的每个时钟周期传输一位数据。传输时,SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。
在这里插入图片描述

2、使用io口模拟产生iic

根据前面的内容,我们可以使用软件来模拟iic,不过根据上面的时序,需要us级延时函数,关于us级延时函数可以参考 stm32嘀嗒定时器的使用,下面挑几个重要的介绍下

高低电平的变化可以直接操作寄存器,但是可能被编译器优化,不过cubeide默认情况不开启优化(一定程度的优化可以压缩代码量),右键工程可以查看优化,优化设置如下,默认是最低的优化。
在这里插入图片描述
代码如下
在这里插入图片描述
数据线需要写数据读数据,所以需要改变其模式,配置数据线输入输出模式
在这里插入图片描述
之后只需要按照要求写起始信号,应答信号,停止信号等即可
在这里插入图片描述
具体代码如下

#include "iic.h"


#define fac_us 72   //时钟频率,单位MHZ

/*微秒级延时函数*/
void delay_us(uint32_t nus)
{
    
    
	uint32_t ticks;
	uint32_t told,tnow,tcnt=0;
	uint32_t reload=SysTick->LOAD;			//LOAD的值
	ticks=nus*fac_us; 						//需要的节拍数
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
    
    
		tnow=SysTick->VAL;
		if(tnow!=told)
		{
    
    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}
	}
}


void I2C_SDA_Mode(uint8_t addr) //数据线输入输出
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct;

	if(addr) //为1的时候是输出模式
	{
    
    
		  GPIO_InitStruct.Pin = SDA_Pin;
		  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	}
	else // 为0的时候上拉输入
	{
    
    
		  GPIO_InitStruct.Pin = SDA_Pin;
		  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
		  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	}
}

//启动信号
void I2C_Start(void)
{
    
    
	I2C_SDA_Mode(1);//配置为输出模式

	SCL_HIGH;
	delay_us(5);
	SDA_LOW;
	delay_us(5);
	SCL_LOW;
}
//停止信号
void I2C_Stop(void)
{
    
    
	I2C_SDA_Mode(1);//配置为输出模式

	SDA_LOW;
	delay_us(5);
	SCL_HIGH;
	delay_us(5);
	SDA_HIGH;
}
uint8_t I2C_Write_ACK(void)//写应答
{
    
    
	uint8_t timeACK;

	I2C_SDA_Mode(0);//配置为输入模式

	SCL_HIGH;
	delay_us(4);
	while(HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin)) //等待应答
	{
    
    
		if(++timeACK > 250)//避免死机,加入避免长时间不应答的函数
		{
    
    
			I2C_Stop();
			return 1;
		}
	}
	SCL_LOW;//正常收到应答信号,拉低
	delay_us(4);
	return 0;
}

void I2C_Write_Byte(uint8_t data)
{
    
    
	SCL_LOW;//时钟为低的时候才可以开始写数据
	delay_us(4);
	for(uint8_t i = 0;i<8;i++)//循环八次
	{
    
    
		I2C_SDA_Mode(1);//配置为输出模式
		if((data<<i) & 0x80)//判断是0还是1
			SDA_HIGH;
		else
			SDA_LOW;
		SCL_HIGH;
		delay_us(4);
		SCL_LOW;
		delay_us(4);
	}
}
uint8_t I2C_Read_Byte(void)
{
    
    
	uint8_t data;
	for(uint8_t i = 0;i<8;i++) //循环八次
	{
    
    
		I2C_SDA_Mode(0); //配置为输入模式
		SCL_HIGH;
		delay_us(4);
		data <<= 1; //数据一位位的往前读
		if(HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin) == GPIO_PIN_SET)
		{
    
    
			data |= 0x01;
		}
		SCL_LOW;
		delay_us(4);
	}
	return data;
}

3、使用iic来控制oled显示

下面们来尝试用配置好的iic来配置oled,我使用的为0.96寸OLED显示屏

在这里插入图片描述
可通过查看背面丝印获取其出厂地址
在这里插入图片描述
关于这个oled屏幕,为128*64,就是宽128bit高64bit,分为8页,所以一页的宽度就是128bit高,8bit宽,如下所示
在这里插入图片描述
关于oled的时序,因为我们用的是中景园的屏幕,驱动芯片是SSD1306,所以其实就是看SSD1306的驱动时序,这个数据手册我也上传到我的gitee上,想详细了解可以直接去查看SSD1306数据手册
在这里插入图片描述
关于这个时序的说明:

  • Co这一位一般是0
  • D/C是数据和命令选择位,命令是0,数据是1
  • 因此可以说,命令寄存器的地址是:00000000,也就是0x00,数据寄存器的地址是:01000000,也就是0x40

所以操作就是
在这里插入图片描述
用流程来解答就是:IIC起始信号 - IIC发送OLED地址 - 应答信号 - IIC发送寄存器地址(命令或数据)- 应答信号-IIC发送命令或数据 - 应答信号 - IIC结束信号

编写程序如下:

void oled_Write_cmd(uint8_t cmd) //写指令
{
    
    
	I2C_Start();
	I2C_Write_Byte(oled_addr);
	I2C_Write_ACK();
	I2C_Write_Byte(0x00);
	I2C_Write_ACK();
	I2C_Write_Byte(cmd);
	I2C_Write_ACK();
	I2C_Stop();
}
void oled_Write_data(uint8_t cmd) //写数据
{
    
    
	I2C_Start();
	I2C_Write_Byte(oled_addr);
	I2C_Write_ACK();
	I2C_Write_Byte(0x40);
	I2C_Write_ACK();
	I2C_Write_Byte(cmd);
	I2C_Write_ACK();
	I2C_Stop();
}

下面就可以根据数据手册的内容(其实我是抄的例程)来编写一些oled的操作函数了,打开和关闭oled

void oled_Clear(void)
{
    
    
	for(uint8_t i=0;i<8;i++)//写页
	{
    
    
		oled_Write_cmd(0xB0|i);
		oled_Write_cmd(0x00);
		oled_Write_cmd(0x10);
		for(uint8_t n=0;n<128;n++)//写行
		{
    
    
			oled_Write_data(0x00);//写0xff为全部点亮
		}
	}
}
void oled_Write_On(void)
{
    
    
	oled_Write_cmd(0x8D);
	oled_Write_cmd(0x14);
	oled_Write_cmd(0xAF);
}
void oled_Write_Off(void)
{
    
    
	oled_Write_cmd(0x8D);
	oled_Write_cmd(0xA0);
	oled_Write_cmd(0xAE);
}

初始化oled,这些函数有一点意思可以行搜索,比如0xAE就是开显示的意思
在这里插入图片描述
下面是初始化代码

void oled_init(void)
{
    
    
	HAL_Delay(200);

	oled_Write_cmd(0xAE);
	oled_Write_cmd(0x00);
	oled_Write_cmd(0x10);
	oled_Write_cmd(0x40);
	oled_Write_cmd(0x81);
	oled_Write_cmd(0xCF);
	oled_Write_cmd(0xA1);
	oled_Write_cmd(0xC8);
	oled_Write_cmd(0xA6);
	oled_Write_cmd(0xA8);
	oled_Write_cmd(0x3f);
	oled_Write_cmd(0xD3);
	oled_Write_cmd(0x00);
	oled_Write_cmd(0xd5);
	oled_Write_cmd(0x80);
	oled_Write_cmd(0xD9);
	oled_Write_cmd(0xF1);
	oled_Write_cmd(0xDA);
	oled_Write_cmd(0x12);
	oled_Write_cmd(0xDB);
	oled_Write_cmd(0x40);
	oled_Write_cmd(0x20);
	oled_Write_cmd(0x02);
	oled_Write_cmd(0x8D);
	oled_Write_cmd(0x14);
	oled_Write_cmd(0xA4);
	oled_Write_cmd(0xA6);
	oled_Write_cmd(0xAF);

	oled_Clear();//最后来一个清屏
}

4、使用逻辑分析仪查看iic效果

我们尝试初始化oled并用逻辑分析仪查看效果,编辑逻辑分析仪的时钟功能,并选定scl和sda线
在这里插入图片描述
查看效果如下,首先是开始的延时
在这里插入图片描述
可以看到命令发送十分成功,基本都很正确
在这里插入图片描述

5、扩展oled显示

使用oled写文字和数据(这部分只要去看下例程,照着来就差不多,它其实也是行列扫描的方式来控制的)

void oled_Display(uint8_t x,uint8_t y,uint8_t length,uint8_t widgh,uint8_t *data)//位置坐标还有高宽,以及数据
{
    
    
	for(uint8_t i=0;i<length;i++)//写页
	{
    
    
		oled_Write_cmd((0xB0|i) + x);
		oled_Write_cmd(0x10 + (y>>4&0x0f));
		oled_Write_cmd(y&0x0f);

		for(uint8_t n=0;n<widgh;n++)//写行
		{
    
    
			oled_Write_data(*data++);//把数据写入
		}
	}
}

这里采用的字模软件为PCtoLCD2002,字模软件设置如下
在这里插入图片描述
生成字模
在这里插入图片描述
显示函数如下
在这里插入图片描述

6、使用自己写的oled驱动移植一些中景园的例程

首先是最基本的字符函数

void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size)
{
    
    
  uint8_t c = 0, i = 0;
  c = chr - ' ';
  if(x > 128 - 1)
  {
    
    
    x = 0;
    y = y + 2;
  }
  if(Char_Size == 16)
  {
    
    
    OLED_Set_Pos(x, y);
    for(i = 0; i < 8; i++)
    	oled_Write_data(F8X16[c * 16 + i]);
    OLED_Set_Pos(x, y + 1);
    for(i = 0; i < 8; i++)
    	oled_Write_data(F8X16[c * 16 + i + 8]);
  }
  else
  {
    
    
    OLED_Set_Pos(x, y);
    for(i = 0; i < 6; i++)
    	oled_Write_data(F6x8[c][i]);
  }
}

这里他巧妙的将字符和ascll码相对应,从而实现字符匹配对应的点阵的效果,并提供了68还有128两种点阵,从偷懒的角度来看,我决定直接用他的。

const unsigned char F6x8[][6] =
{
    
    
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
        0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
        0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
        0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
        0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
        0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
        0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
        0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
        0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
        0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
        0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
        0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
        0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
        0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
        0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
        0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
        0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
        0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
        0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
        0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
        0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
        0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
        0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
        0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
        0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
        0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
        0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
        0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
        0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
        0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
        0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
        0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
        0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
        0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
        0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
        0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
        0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
        0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
        0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
        0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
        0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
        0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
        0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
        0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
        0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
        0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
        0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
        0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
        0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
        0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
        0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
        0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
        0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
        0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
        0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
        0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
        0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
        0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
        0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
        0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
        0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
        0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
        0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
        0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
        0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
        0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
        0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
        0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
        0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
        0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
        0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
        0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
        0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
        0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
        0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
        0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
        0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
        0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
        0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
        0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
        0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
        0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
        0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
        0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
        0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
        0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
        0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
        0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
        0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
        0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
        0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
        0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
};
///****************************************8*16的点阵************************************/
const unsigned char F8X16[] =
{
    
    
        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_Set_Pos函数就是我们前面的display函数的精简版,要注意他这这个里面x,y和我们采用的不一样,正好是相反的所以我修改x和y的位置

void OLED_Set_Pos(uint8_t y, uint8_t x)
{
    
    
	oled_Write_cmd(0xB0 + x);
	oled_Write_cmd(0x10 + (y>>4&0x0f));
	oled_Write_cmd(y&0x0f);
}

下面就是基于这个来写的字符串函数,数字显示函数,图片显示函数

void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size)
{
    
    
  unsigned char j = 0;
  while (chr[j] != '\0')
  {
    
    
    OLED_ShowChar(x, y, chr[j], Char_Size);
    x += 8;
    if(x > 120)
    {
    
    
      x = 0;
      y += 2;
    }
    j++;
  }
}
uint32_t oled_pow(uint8_t m, uint8_t n)
{
    
    
  uint32_t result = 1;
  while(n--)result *= m;
  return result;
}
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size)
{
    
    
  uint8_t t, temp;
  uint8_t enshow = 0;
  for(t = 0; t < len; t++)
  {
    
    
    temp = (num / oled_pow(10, len - t - 1)) % 10;
    if(enshow == 0 && t < (len - 1))
    {
    
    
      if(temp == 0)
      {
    
    
        OLED_ShowChar(x + (size / 2)*t, y, ' ', size);
        continue;
      }
      else enshow = 1;
    }
    OLED_ShowChar(x + (size / 2)*t, y, temp + '0', size);
  }
}
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[])
{
    
    
	uint32_t j = 0;
	uint8_t x, y;

	if(y1 % 8 == 0)
		y = y1 / 8;
	else
		y = y1 / 8 + 1;
	for(y = y0; y < y1; y++)
	{
    
    
		OLED_Set_Pos(x0, y);
		for(x = x0; x < x1; x++)
		{
    
    
			oled_Write_data(BMP[j++]);
		}
	}
}

在函数中调用如下

  OLED_ShowString(0,0,"fdsfsd",16);
  OLED_ShowNum(0,0,16,2,16);
  OLED_DrawBMP(0,0,128,8,(uint8_t *)BMP1);
  for(uint8_t i=0;i<6;i++)
  {
    
    
	  oled_Display(0,i*16,2,16,text[i]);
  }
  for(uint8_t i=0;i<10;i++)
  {
    
    
	  oled_Display(2,i*8,2,8,Num[i]);
  }

还有就是这个关于点阵数组的问题,这里需要使用外部声明
在这里插入图片描述

7、改用硬件iic来去驱动oled

好家伙,那就简单了,硬件iic就不需要我们自己去写iic的函数了,直接使用硬件,调用函数就行了,如图这里直接打开就行(备注:这里使用标准和快速模式都没有影响
在这里插入图片描述
下面修改写命令和写数据韩式,其他一模一样就行,如下所示,使用之前的函数也是一切OK的,不得不说硬件iic的感觉是真的方便!!!

void oled_Write_cmd(uint8_t cmd) //写指令
{
    
    
	uint8_t *pData;
	pData = &cmd;
	HAL_I2C_Mem_Write(&hi2c2,oled_addr,0x00,I2C_MEMADD_SIZE_8BIT,pData,1,100);
}
void oled_Write_data(uint8_t data) //写数据
{
    
    
	uint8_t *pData;
	pData = &data;
	HAL_I2C_Mem_Write(&hi2c2,oled_addr,0x40,I2C_MEMADD_SIZE_8BIT,pData,1,100);
}

8、模拟iic驱动at24c20芯片读写

24C02是一个2KBit的串行EEPROM存储器(掉电不丢失)内部含有256个字节、在24C02里面有一个8字节的页写缓冲器,容量大小为256*8=2048/2k。

在原理图上可以查到该芯片的引脚如下所示
在这里插入图片描述
官方手册同样有他的数据操作说明,本文只研究读取一个位,数据手册我已经放到我的gitee at24c02数据手册
在这里插入图片描述
关于他的设备地址,根据官方描述为:A0、A1、A2 这些输入脚用于多个器件级联时设置器件地址,当这些脚悬空时默认值为0当使用AT24C02 时最大可级联8个器件。如果只有一个AT24C02被总线寻址,这三个地址输入脚(A0、A1、A2 )可悬空或连接到VCC/ GND,这里根据硬件连接为0XA0。
在这里插入图片描述
这里我们新建两个文件
在这里插入图片描述
编写读写函数

#include "at24c02.h"
#include "../../BSP/iic.h"

#define AT24C02 0XA0

void AT24C02_Write(uint8_t addr,uint8_t data)
{
    
    
	I2C_Start();
	I2C_Write_Byte(AT24C02|0x00);
	I2C_Write_ACK();
	I2C_Write_Byte(addr); //器件地址
	I2C_Write_ACK();
	I2C_Write_Byte(data); //写入数据
	I2C_Write_ACK();
	I2C_Stop();
	HAL_Delay(10);
}
uint8_t AT24C02_Read(uint8_t addr)
{
    
    
	uint8_t data;

	I2C_Start();
	I2C_Write_Byte(AT24C02|0x00);
	I2C_Write_ACK();
	I2C_Write_Byte(addr); //器件地址
	I2C_Write_ACK();

	I2C_Start();
	I2C_Write_Byte(AT24C02|0x01);
	I2C_Write_ACK();
	data = I2C_Read_Byte();
	I2C_Write_ACK();
	I2C_Stop();

	return data;
}

测试读写
在这里插入图片描述
下载到开发板后打印结果如下所示
在这里插入图片描述
使用逻辑分析仪查看读写情况,可以看到都是成功写入的
在这里插入图片描述
之前有一次我SDA没设置好,一直读取错误,读取错误就是应答会一直不对,就如下图所示
在这里插入图片描述
好了,因为这个没有和硬件iic的引脚关联,所以用硬件iic来做测试就不方便,不过后续还将继续用这套iic来测试更多的设备!!!

猜你喜欢

转载自blog.csdn.net/m0_51220742/article/details/123054244