基于stm32f103系列的简单软件I2C和硬件I2C通讯

news2025/1/23 14:59:09

       这篇文章主要分为三个部分来阐述,分别是I2C的基本知识,软件I2C通讯,硬件I2C通讯。I2C的基本知识这一块,部分讲解以及图表来自b站江科大的up,很感谢这位up,大家可以关注一波。操作实现的时候,up使用的是标准库讲解,我是用是HAL库,但都可以实现。

一、I2C的基本知识

1.基本的三种通讯方式

学过通讯的同学都知道,基本的通讯方式有单工,半双工,全双工。那么这三种工作方式有啥区别吗?我给大家举个例子:

      单工通讯就好比象棋里面的“卒”,卒有啥特性?没错,一条路走到黑,不走回头路,说白了,这种通讯方式就是“有去无回”。我只知道我可以通过这条线发过去,但是我没法通过这条线反馈信息。

      半双工通讯就好比你在狭窄的山路上开车,你可以开入山里面,也可以开出山里面,但是山路狭窄,在同一时刻同一路段只能允许一辆车通过。所以你你要想开入山里面,就必须等到出山的车先开出来;要想开出山里面,就必须让开入山里面的车先开进去。说白了,就是说,你可以出入山里,但是一定要确保你在开车的过程中,山路上没有相反方向的车堵住你。所以半双工在同一时刻,只能有一个方向的通讯。等到这个方向通讯完成,你才可以选择下一次通讯的方向。

      全双工通讯就好比我们现在的公路,随时随地,有来有回,去的车道完全不对回来的车道有影响,大家各走各的。

      这三种通道各自有各自的优劣与使用场景,感兴趣的同学可以自己百度百度。我们今天要说的就是I2C就是半双工通讯。

2.I2C通讯规则

起始条件:在SCL高电平的时候,SDA由高电平变为低电平

终止条件:在SCL高电平的时候,SDA由高电平变为低电平

发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA,就是要让SDA=1

发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。

接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)。

请大家看清楚接受和发送的对象是谁,不要混淆了。

3.硬件电路

第一张图告诉我们,所有的从机设备都和主机的时序一样,因此属于同步时序。主机的SDA连接着从机的SDA,这是一张典型的一主多从模型图。主机想要和谁通讯就,只需要输入对应的从机地址就行了。图中的两个R是为了保护电路的,具体咋保护的呢?

按道理说,只要我们按照正常的时序,就可以实现主机的SDA输出,从机的SDA输入;从机的SDA输出,主机的SDA输入,这没问题。但是如果时序没有协调好,有可能会出现一方的SDA输出1,一方的SDA输出0,这样就相当于高低电平直接接在一起,不就短路了吗?

因此I2C的设计规定,禁止所有的设备(无论是主机还是从此,内部的SDA,SCL电路都如第二张图所示)输出强上拉的高电平,采用外置弱上拉的电阻加开路输出的电路结构,这样就不用担心短路的问题了,如上图所示,在输入时,无论是SCL还是SDA的电路,输入高低电平都无影响。但是在输出是,因为SDA和SCL都是开漏模式,因此当输出低电平时,直接导通;输出高电平时,被截断处于浮空状态。但是浮空状态不稳定容易受到干扰,因此有外接一个电阻R,相当于让浮空的引脚与电阻相连,完成弱上拉,变相的输出高电平。

下面我以主机SDA为例,给大家画一下等效图

无论是主机还是从机,SDA和SCL都可以这样简化。如果你想了解为什么可以这样的简化,,你可以去b站上自己学一下场效应管的知识,再结合第一第二张图片的电路,你就懂了,这里我就不细说效应管的知识了。

4.三种基本的I2C时序通讯

指定地址写:指定地址写入一个字节

如果想要写入多个字节,在终止条件前面的应答位应答,并且再次重复主机发送字节写内容及应答即可,直到不想发送,然后在写入终止条件。

当前地址读

如果想要读入多个字节,在终止条件前面的应答位应答,并且再次重复从机发送字节写内容及应答即可,直到不想发送,然后在写入终止条件。

当前地址指针:就是说这个指针目前指向那个寄存器。当我们写的时候,会在该指针的位置写入,写完后自动加1,向下移动;当我们读的时候,会在该指针的位置读出,读完后自动加1,向下移动。

指定地址读:相当于把指定地址写的终止条件去掉,然后和当前地址读结合起来。比如说我在指定地址写的时候,选好了从机的8位储存器地址,那么当前地址指针就要指向这里,我们就在这里写,接着应答,然后开始执行当前地址读的序列,那么就可以再当前的位置(也就是我们指定的写入地址的位置)读取出来数据。

二、软件I2C通讯

1.前提准备

   这里还是依据51单片机的I2C模拟通讯来进行改编,不熟悉的话,可以回看一下51模拟I2C通讯实现OLED显示图片

2.代码部分(运行出来是一条蛇)

这里我们想要用PB7端口模拟SDA,PB6端口模拟SCL,同时根据第一部分介绍,我们应该知道SDA,SCL都应该是开漏模式,所以我们的PB7端口和PB6端口都会配置成开漏模式。

#include "main.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define OLED_I2C_SCL_CLK()		__HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SCL_GPIO  		GPIOB
#define OLED_I2C_SCL_PIN   		GPIO_PIN_6

#define OLED_I2C_SDA_CLK()   	__HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SDA_GPIO  		GPIOB
#define OLED_I2C_SDA_PIN   		GPIO_PIN_7

#define OLED_SCL_RESET() 			HAL_GPIO_WritePin(OLED_I2C_SCL_GPIO,OLED_I2C_SCL_PIN,GPIO_PIN_RESET)  //SCL
#define OLED_SCL_SET() 				HAL_GPIO_WritePin(OLED_I2C_SCL_GPIO,OLED_I2C_SCL_PIN,GPIO_PIN_SET)

#define OLED_SDA_RESET() 			HAL_GPIO_WritePin(OLED_I2C_SDA_GPIO,OLED_I2C_SDA_PIN,GPIO_PIN_RESET)  //SDA
#define OLED_SDA_SET() 				HAL_GPIO_WritePin(OLED_I2C_SDA_GPIO,OLED_I2C_SDA_PIN,GPIO_PIN_SET)

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void MyI2C_Start(void)//起始条件
{
	OLED_SCL_SET();
	OLED_SDA_SET();
	OLED_SDA_RESET();
	OLED_SCL_RESET();
	
}

void MyI2C_Stop(void)//终止条件
{
	OLED_SCL_SET() ;
	OLED_SDA_RESET();
	OLED_SDA_SET();
}

void MyI2C_SendByte(uint8_t Byte)//发送一个字节
{
	uint8_t i;
	uint8_t m,da;
	da = Byte;
	OLED_SCL_RESET();
	for(i = 0; i < 8; i++)		
	{
		m = da;
		m = m&0x80;
		if(m == 0x80)
		  OLED_SDA_SET();
		else 
			OLED_SDA_RESET();
			da = da << 1;
		  OLED_SCL_SET();
		  OLED_SCL_RESET();
	}
}



char MyI2C_SendAck()//发送应答
{
	char flag;
	OLED_SDA_SET();//释放SDA
	OLED_SCL_SET();
	 flag=	HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7);
	OLED_SCL_RESET();
	return flag;
}


/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
void Oled_Write_Cmd(char dataCmd)//发送一个写命令字节
{
   MyI2C_Start();
   MyI2C_SendByte(0x78);
	 MyI2C_SendAck();	
   MyI2C_SendByte(0x00);
	 MyI2C_SendAck();	
   MyI2C_SendByte(dataCmd); 
	 MyI2C_SendAck();	
    MyI2C_Stop();
}

void Oled_Write_Data(char dataData)//发送一个写数据字节
{
 MyI2C_Start();//起始条件
    MyI2C_SendByte(0x78);//发送从机地址
    MyI2C_SendAck();//应答
   MyI2C_SendByte(0x40);//开启写入命令0x00或写入数据0x40
    MyI2C_SendAck();	//应答
   MyI2C_SendByte(dataData);//写入具体的命令或者数据
     MyI2C_SendAck();
    MyI2C_Stop();//IIC结束
}

	void OLED_Init(void)
{
	Oled_Write_Cmd(0xAE);//--display off
	Oled_Write_Cmd(0x00);//---set low column address
	Oled_Write_Cmd(0x10);//---set high column address
	Oled_Write_Cmd(0x40);//--set start line address  
	Oled_Write_Cmd(0xB0);//--set page address
	Oled_Write_Cmd(0x81); // contract control
	Oled_Write_Cmd(0xFF);//--128   
	Oled_Write_Cmd(0xA1);//set segment remap 
	Oled_Write_Cmd(0xA6);//--normal / reverse
	Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
	Oled_Write_Cmd(0x3F);//--1/32 duty
	Oled_Write_Cmd(0xC8);//Com scan direction
	Oled_Write_Cmd(0xD3);//-set display offset
	Oled_Write_Cmd(0x00);//
	
	Oled_Write_Cmd(0xD5);//set osc division
	Oled_Write_Cmd(0x80);//
	
	Oled_Write_Cmd(0xD8);//set area color mode off
	Oled_Write_Cmd(0x05);//
	
	Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
	Oled_Write_Cmd(0xF1);//
	
	Oled_Write_Cmd(0xDA);//set com pin configuartion
	Oled_Write_Cmd(0x12);//
	
	Oled_Write_Cmd(0xDB);//set Vcomh
	Oled_Write_Cmd(0x30);//
	
	Oled_Write_Cmd(0x8D);//set charge pump enable
	Oled_Write_Cmd(0x14);//
	
	Oled_Write_Cmd(0xAF);//--turn on oled panel	
}

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void Oled_Screen_Clear(void){
	unsigned char i,n;
	                   

	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xb0+i);              
		Oled_Write_Cmd(0x00);                 
		Oled_Write_Cmd(0x10);                 
		for(n=0;n<128;n++)
		Oled_Write_Data(0x00); 			
	}	
}

unsigned char bmpImager[] = {

/*--  调入了一幅图像:D:\无标题.bmp  --*/
/*--  宽度x高度=128x64  --128x8x8*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0xC0,0xC0,0xC0,0x40,0x40,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF0,0xB8,
0x8C,0x8E,0x86,0x03,0x03,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0xE1,0xF1,
0xE1,0x63,0x03,0x06,0x0E,0x0C,0x18,0x70,0xE0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x81,0x81,
0x81,0x81,0x81,0xC1,0xC3,0x67,0x7E,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0x07,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x00,0x00,0x00,0x00,0xC0,0xF1,0x7F,0x1F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x0F,0x3D,
0x71,0xE1,0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x10,0xF0,0xF0,
0xB0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xF0,0xF0,0xB3,0x33,0x36,0x36,0x16,0x1E,
0x1E,0x1B,0x0F,0x0C,0x06,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x03,0x9F,0xFC,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,
0xFF,0x66,0x66,0x46,0x46,0x46,0x46,0x46,0x62,0x63,0x67,0x7F,0xFC,0xF0,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,
0xC0,0xC0,0xC0,0x60,0x60,0x60,0xE0,0xA0,0x30,0x30,0x30,0x10,0x18,0x98,0xF8,0xFC,
0x6C,0x0C,0x04,0x06,0x06,0x06,0x62,0xF3,0xF3,0xDB,0xDB,0xDB,0xDB,0xF3,0x73,0x03,
0x03,0x0F,0x1F,0x3F,0x33,0x63,0x62,0x66,0x66,0x36,0x3E,0x1E,0x06,0x06,0x06,0x06,
0x06,0x3B,0x7B,0x6F,0xCD,0xCC,0xC4,0xCC,0xCC,0x6C,0x78,0x38,0x80,0xE0,0x7C,0x3F,
0x0F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0xEC,0xFF,0x7F,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x05,0x0D,0x0D,0x09,0x19,
0x19,0x19,0x31,0x31,0x31,0x61,0x61,0x61,0x61,0x41,0xC1,0xC0,0xC0,0xC0,0xC0,0xC0,
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0xC1,0x43,0x63,0x63,0x63,0x31,0x31,0x30,
0x10,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,
0x0C,0x0C,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0x60,0x60,0x60,0xE0,0xF0,0xF0,
0xF0,0xF0,0xF0,0xF0,0xD8,0xD8,0xD8,0xDC,0xFC,0xF6,0xF6,0xE3,0xE3,0xE3,0x63,0x63,
0x63,0x62,0x66,0x36,0x36,0x36,0x1E,0x1E,0x0E,0x0E,0x06,0x07,0x03,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

void Oled_Show_Image(unsigned char *image)
{
	unsigned char i; 
	unsigned int j;
	
	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xB0 + i);//page0--page7
		//每个page从0列
		Oled_Write_Cmd(0x00);
		Oled_Write_Cmd(0x10);
		//0到127列,依次写入0,每写入数据,列地址自动偏移
		for(j = 128 * i; j<(128 * (i+1));j++){
			Oled_Write_Data(image[j]);
		}
	}
}
/* 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 */

/* 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();
  /* USER CODE BEGIN 2 */
	
   OLED_Init();
		 
	//2. 选择一个位置
	//2.1 确认页寻址模式
	Oled_Write_Cmd(0x20);
	Oled_Write_Cmd(0x02);
	Oled_Screen_Clear();
	Oled_Show_Image(bmpImager);
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3.stm32cube配置

SYS,RCC照旧

GPIO的配置如下图,PB6,7配置一样

三、硬件I2C通讯

1.前提准备

       我们的32单片机是有I2C外设的,而51里面没有I2C外设,因此,我们的32单片机既可以用硬件I2C通讯,也可以模拟I2C通讯。这里我们要实现的是利用32单片机和HAL库重新做一下OLED显示图片,oled的操作说明和图片的操作细节可以再http://t.csdnimg.cn/Bk61c和http://t.csdnimg.cn/A8htshttp://t.csdnimg.cn/Bk61c和 里面看一下。

        我们使用硬件I2C后,可以直接调用直接调用库函数来控制寄存器,让寄存器控制硬件电路的状态从而来控制SDA和SCL的时序。诸如起始终止条件,接受发送字节,应答之类的,我们不用软件I2C那样,自己手动控制SDA和SCL的时序,只需要用库函数即可控制硬件,调制出我们需要的时序。那么既然硬件那么好,为啥还要软件I2C?我玩个梗,加个外设,可以,得加钱。

2.代码部分(运行出来是女孩头像)

先说一下我们要用的函数

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,选择哪一个I2C通道的地址

参数二:uint16_t DevAddress,目标器件的地址,七位地址必须左对齐,外加最后一位读写位

参数三:uint16_t MemAddress,目标器件的目标寄存器地址或者指令控制字

参数四:uint16_t MemAddSize,目标器件内部寄存器地址数据长度及一个数据有多大,这里可以选择8位或者16位

参数五:uint8_t *pData,待写的数据首地址

参数六:uint16_t Size,待写的数据长度

参数七:uint32_t Timeout,超时时间 返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

沿着51单片机显示图片的程序,我们继续修改

#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 */
void Oled_Write_Cmd(uint8_t dataCmd)
{
	
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,
										&dataCmd, 1, 0xff);
}

void Oled_Write_Data(uint8_t dataData)
{
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,
										&dataData, 1, 0xff);
}

void Oled_Init(void){
	Oled_Write_Cmd(0xAE);//--display off
	Oled_Write_Cmd(0x00);//---set low column address
	Oled_Write_Cmd(0x10);//---set high column address
	Oled_Write_Cmd(0x40);//--set start line address  
	Oled_Write_Cmd(0xB0);//--set page address
	Oled_Write_Cmd(0x81); // contract control
	Oled_Write_Cmd(0xFF);//--128   
	Oled_Write_Cmd(0xA1);//set segment remap 
	Oled_Write_Cmd(0xA6);//--normal / reverse
	Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
	Oled_Write_Cmd(0x3F);//--1/32 duty
	Oled_Write_Cmd(0xC8);//Com scan direction
	Oled_Write_Cmd(0xD3);//-set display offset
	Oled_Write_Cmd(0x00);//
	
	Oled_Write_Cmd(0xD5);//set osc division
	Oled_Write_Cmd(0x80);//
	
	Oled_Write_Cmd(0xD8);//set area color mode off
	Oled_Write_Cmd(0x05);//
	
	Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
	Oled_Write_Cmd(0xF1);//
	
	Oled_Write_Cmd(0xDA);//set com pin configuartion
	Oled_Write_Cmd(0x12);//
	
	Oled_Write_Cmd(0xDB);//set Vcomh
	Oled_Write_Cmd(0x30);//
	
	Oled_Write_Cmd(0x8D);//set charge pump enable
	Oled_Write_Cmd(0x14);//
	
	Oled_Write_Cmd(0xAF);//--turn on oled panel		
}

void Oled_Screen_Clear(void){
	char i,n;
	Oled_Write_Cmd (0x20);                    //set memory addressing mode
	Oled_Write_Cmd (0x02);                    //page addressing mode

	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xb0+i);               //éè??ò3μ??·£¨0~7£?
		Oled_Write_Cmd(0x00);                 //éè????ê??????aáDμíμ??·
		Oled_Write_Cmd(0x10);                 //éè????ê??????aáD??μ??·   
		for(n=0;n<128;n++)
		Oled_Write_Data(0x00); 			
	}	
}

unsigned char bmpImager[] = {

/*--  调入了一幅图像:D:\无标题.bmp  --*/
/*--  宽度x高度=128x64  --128x8x8*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0xF0,0x08,0x0C,0x04,0x06,0x06,0x0C,0x04,0x0C,0xFC,0x1C,0x74,0xFC,0xF8,
0xF0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0x07,0x04,0x88,0xF8,0x08,0x08,0x0C,0x06,0x01,0x00,0x00,0x01,0x1F,
0x7F,0xFF,0xDC,0xF8,0xE0,0xC0,0x40,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x10,0x18,0x08,0x0C,
0x04,0x04,0x06,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x60,0xC0,0x80,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x03,0x06,0x1C,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0xFC,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x88,0xE8,0x38,0x0E,0x09,0x08,
0x08,0x88,0xE8,0x18,0x08,0x08,0x08,0x00,0x00,0xFF,0x89,0x89,0x89,0xFF,0x00,0xFF,
0x89,0x89,0x89,0x89,0xFF,0x00,0x00,0x04,0x04,0x84,0x74,0x6F,0xA4,0x24,0x24,0x24,
0x24,0xA4,0x64,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x80,0xF0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x08,0x09,0x09,0x06,0x06,
0x06,0x05,0x08,0x08,0x10,0x10,0x00,0x00,0x0C,0x03,0x10,0x10,0x10,0x1F,0x18,0x07,
0x00,0x00,0x10,0x10,0x1F,0x00,0x10,0x08,0x06,0x11,0x10,0x08,0x09,0x0A,0x06,0x06,
0x0B,0x08,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,
0x1E,0x03,0x00,0x00,0xC0,0x60,0x30,0x0C,0x04,0x06,0x02,0x01,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
0x1E,0x60,0x78,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,


};

void Oled_Show_Image(unsigned char *image)
{
	unsigned char i; 
	unsigned int j;
	
	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xB0 + i);//page0--page7
		//每个page从0列
		Oled_Write_Cmd(0x00);
		Oled_Write_Cmd(0x10);
		//0到127列,依次写入0,每写入数据,列地址自动偏移
		for(j = 128 * i; j<(128 * (i+1));j++){
			Oled_Write_Data(image[j]);
		}
	}
}

/* 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 */

/* 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 */
	//1. OLED初始化
	Oled_Init();
	//2. 选择一个位置
	//2.1 确认页寻址模式
	Oled_Write_Cmd(0x20);
	Oled_Write_Cmd(0x02);
	Oled_Screen_Clear();
	Oled_Show_Image(bmpImager);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3.stm32cube的配置

SYS,RCC照旧不变。I2C1里面如下图选择

这里要说一点,就是stm32可以作为主机或者从机是用。实验里面,只要stm32产生起始条件,我们把stm32当做主机使用,因此从机模式里面我们压根就没有管,保持他的默认形式就行。

最后我想说的是,无论是HAL还是标准库,都可以实现我们的需求。标准库写的麻烦,但是可以染你在写程序的时候更多关注于手册的细节,HAL库看似比较简单方便,但是他是高度集成的,里面很多细节不是那么容易看出来的,因为HAL库封装的程度太高了,各取所需吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1214584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三行Python代码即可将视频转Gif

一、前言 很多网站提供视频转GIF的功能&#xff0c;但要么收费要么有广告 实际上我们通过python&#xff0c;几行代码就能够实现视频转gif 二、教程 1. 安装必备库moviepy pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple 2. 写入代码 from moviepy.edi…

大厂必备的6款React UI框架

优秀的ReactUI框架可以为您节省开发时间&#xff0c;提高开发效率&#xff0c;统一设计语言。你还在为你的项目寻找高质量的ReactUI框架吗&#xff1f;为了让您更容易找到易于使用的UI框架&#xff0c;分享6个优秀的ReactUI框架选项&#xff0c;并介绍了每个UI框架的不同功能和…

ArmV8常用汇编指令2

接上文&#xff0c;我们来分析一些具体指令。 1.加载存储指令 Load/Store可以分为立即数、寄存器等操作&#xff0c;格式如下&#xff1a; 这里Rn和Rt均为4位&#xff0c;原因在于&#xff0c;A32/T32是16个通用寄存器。因此使用4bit刚好可以遍历所有。如果是运行在AArch64&a…

Vue中el与data的两种写法

想必大家对Vue中的el与data并不陌生&#xff0c;接下来&#xff0c;让我为大家介绍一下el与data的两种写法吧&#xff01; 一、el的两种写法 1.new Vue时候配置e1属性。 2.先创建Vue实例&#xff0c;随后再通过vm.$mount(#root)指定el的值 <!DOCTYPE html> <html l…

03.智慧商城——路由配置

01. 路由配置 - 一级路由 但凡是单个页面&#xff0c;独立展示的&#xff0c;都是一级路由 路由设计&#xff1a; 登录页首页架子 首页 - 二级分类页 - 二级购物车 - 二级我的 - 二级 搜索页搜索列表页商品详情页结算支付页我的订单页 router/index.js 配置一级路由&#x…

三种跨域解决方案:HttpClient、注解、网关

注解&#xff1a;CrossOrigin网关整合Httpclient 为什么会有跨域问题 因为浏览器的同源政策&#xff0c;就会产生跨域。比如说发送的异步请求是不同的两个源&#xff0c;就比如是不同的的两个端口或者不同的两个协议或者不同的域名。由于浏览器为了安全考虑&#xff0c;就会产…

systrace分析 之 问题初步定位

2、systrace分析 之 问题初步定位 1、找到问题点2、有buffer&#xff0c;SF却什么没有取 2.1、GPU 处理时间长导致2.2、区分HWC release 是否有异常&#xff1a;2.3、SF 异常导致2.4、SF 自身处理时间长2.5、RenderThread处理时间长3、案例分享 1、找到问题点 2、有buffer&a…

【PHP】医院麻醉临床信息系统源码

麻醉临床信息系统以服务围术期临床业务工作的开展为核心&#xff0c;为医护人员、业务管理人员、院级领导提供流程化、信息化、自动化、智能化的临床业务综合管理平台。 麻醉信息系统处理的数据包含病人的手术信息、麻醉信息、病人手术过程中从监护仪上采集到的数据和病人情况等…

解决STM32F429烧录程序后还需复位才能植入程序的bug

1.打开魔术棒&#xff0c;打开debug 2.打开setting 3.打开Flas Download 4.开启Reset and Run 5.点进去Pack选项页面&#xff0c;去掉enable

合肥数字孪生赋能工业制造,加速推进制造业数字化转型

聚焦国家战略需求和先进制造业发展方向&#xff0c;加快数字化发展战略部署&#xff0c;数字孪生、工业互联网、工业物联网已被广泛认为是工业革命的新引擎。合肥数字孪生正在推动工业制造从制造转向智造。通过数字化建模和仿真的方式&#xff0c;优化设计、生产、质量管理、供…

centos图形化桌面中火狐浏览器无法访问项目页面问题处理

项目场景&#xff1a; 使用centos环境中的火狐浏览器访问项目界面 问题描述&#xff1a; 在客户的demo环境中部署了项目&#xff0c;但是使用机器上自带的火狐浏览器访问界面确实白屏&#xff0c;联系开发同事后认为是浏览器版本的问题。 更新火狐浏览器版本后&#xff0c;问…

Python 3.6.10 中的 requests 库 TLS 1.2 强制使用问题及解决方案

Python 3.6.10中&#xff0c;requests库已经强制使用TLS 1.2协议&#xff0c;不再支持TLS 1.3协议。这一变化可能会导致在使用Python 3.6.10时&#xff0c;与使用TLS 1.3的服务器进行通信时出现问题。为了解决这个问题&#xff0c;我们可以采取一些措施来确保安全且有效的网络通…

寒冬只是表象,网安才是归宿

“简历基本没人看” “已读不回” “简历都没看直接告诉你不合适” “能约面试的很少” 据统计&#xff0c;现在的互联网行业都是上面这几种情况。不仅是今年&#xff0c;这两三年以来&#xff0c;互联网大厂的工作岗位缩减了又缩减&#xff0c;计算机专业的毕业生工作难上加难…

振弦传感器表面应变计与振弦采集仪形成岩土工程监测的解决方案

振弦传感器表面应变计与振弦采集仪形成岩土工程监测的解决方案 振弦传感器表面应变计与振弦采集仪可以结合使用&#xff0c;形成岩土工程监测的解决方案。具体的方案包括以下几个步骤&#xff1a; 1. 安装振弦传感器表面应变计&#xff1a;首先需要在需要监测的岩土结构表面安…

前三季度亏损近亿元,「缺钱」的北斗智联拟变更控股股东

本月初&#xff0c;北斗星通发布《关于深圳证券交易所重组问询函回复的公告》&#xff0c;针对公司全资子公司拟出售孙公司北斗星通智联科技有限责任公司&#xff08;以下简称北斗智联&#xff09; 15%的股权事宜做出进一步解读。 按照此前计划&#xff0c;15%的股权&#xff0…

Windows10关闭系统自动更新

1.背景 2.步骤 第一步: 第二步: 完美

基础课5——垂直领域对话系统架构

垂直领域对话系统是指针对特定领域或行业的需求而构建的对话系统。这种系统通常需要具备高度的专业知识和对特定领域的知识库进行深入的学习和训练&#xff0c;以便能够提供准确、高效、实用的服务。 垂直领域对话系统的构建通常包括以下步骤&#xff1a; 确定目标领域或行业…

Java虚拟机运行时数据区结构详解

Java虚拟机运行时数据区结构如图所示 程序计数器 程序计数器&#xff08;Program Counter Register&#xff09;是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的字节码的行号指示器。 多线程切换时&#xff0c;为了能恢复到正确的执行位置&#xff0c;每条线程…

2022年03月 Scratch(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 天天收到了一个语音机器人,当天天说“a”的时候,机器人会说“apple”,当天天说“b”的时候,机器人会说“banana”, 当天天说“c”的时候,机器人会说“cat”,如果天天说其它内容,机器人就会说“I don’t know”。机器人可…

AIGC实战——变分自编码器(Variational Autoencoder, VAE)

AIGC实战——变分自编码器 0. 前言1. 变分自编码器1.1 基本原理1.2 编码器 2. 构建VAE编码器2.1 Sampling 层2.2 编码器2.3 损失函数2.4 训练变分自编码器 3. 变分自编码器分析小结系列链接 0. 前言 我们已经学习了如何实现自编码器&#xff0c;并了解了自编码器无法在潜空间中…