当前位置:   article > 正文

16:【stm32】I2C的使用一:I2C片上外设的使用

16:【stm32】I2C的使用一:I2C片上外设的使用


具体的通过I2C通信协议传输数据帧的相关信息参考《C51单片机》里面的第13节OLED屏的使用

1、片上外设

如图:I2C片上外设挂载在APB1总线上面,并且I2C1由复用重映射,I2C2没有重映射。
在这里插入图片描述
在这里插入图片描述

1.1:寄存器与内部结构

在这里插入图片描述

TDR -Transmit Data Register -发送数据寄存器
RDR -Receive Data Register -接收数据寄存器
CR  -Control Register -控制寄存器
SR1 -Status Register 1 -状态寄存器1
SR2 -Status Register 2 -状态寄存器2
CCR -Clock Control Register -时钟控制寄存器
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • SR1:状态寄存器1

    SB:起始位发送完成,0代表没有起始位产生,1代表检测到了起始位。
    AF/ADDR:AF代表接收到NAK,寻址失败AF=1;ADDR代表选址成功,寻址成功-ADDR=1。
    TXE:发送数据寄存器TDR空,1代表空,0代表非空。
    RXNE:接收数据寄存器RDR非空,1代表非空,0代表空。
    BTF:发送完成。1代表发送完成
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • SR2:状态寄存器2

    TRA
    BUSY:用于查询总线的空闲状态,0为空闲,1为忙。
    MSL
    
    • 1
    • 2
    • 3
  • CR:控制寄存器

    PE:SCL的开关。
    START:用于产生一个起始位,写入1代表发送一个起始位。
    ACK:用于产生一个应答信号。
    
    • 1
    • 2
    • 3

2、通过I2C向外发送数据

2.1:I2C的初始化

在这里插入图片描述

2.1.1:初始化SCL和SDA

我们使用I2C1,初始化SCL和SDA所连接的IO口,把他们配置为复用开漏模式。

//1 .开启GPIOB挂载的总线时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//初始化IO引脚
GPIO_InitTypeDef GPIOInitStruct;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式
GPIOInitStruct.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIOInitStruct);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.1.2:使能时钟PCLK1(APB1)

//2 .开启I2C挂载APB1总线的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启时钟
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//对I2C1进行复位
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//对I2C1进行释放
  • 1
  • 2
  • 3
  • 4

2.1.3:配置I2C1的参数

在这里插入图片描述
标志模式下:波特率max = 100K,当波特率>=100K时,就按照快速模式进行。快速模式下:波特率max = 400K。
I2C_DutyCycle:在快速模式下,配置时钟信号的形状,即时钟信号的占空比。2:1 = 低电平:高电平/16:9 = 低电平:高电平
下面灰色是工作在从机模式下才需要进行配置的。

//3 .配置I2C1的参数
I2C_InitTypeDef I2CInitStruct;
I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400K
I2CInitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2C模式,一般不使用SMBus
I2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1
I2C_Init(I2C1,&I2CInitStruct);
//4 .使能I2C
I2C_Cmd(I2C1,ENABLE);//闭合开关,PE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.2:发送数据

在这里插入图片描述在这里插入图片描述

2.2.1:等待总线空闲(BUSY标志位)

在这里插入图片描述

//1 .等待总线空闲 
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
  • 1
  • 2

2.2.2:发送起始位(START,SB标志位)

在这里插入图片描述

//2 .发送起始位
I2C_GenerateSTART(I2C1,ENABLE);
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成
  • 1
  • 2
  • 3

2.2.3:发送地址(AF,ADDR标志位)

在这里插入图片描述
发送地址前先清除AF标志位,

//3 .发送地址
  //3.1 清除标志位AF
I2C_ClearFlag(I2C1,I2C_FLAG_AF);
  //3.2 发送8为数据,7+1
I2C_SendData(I2C1,SlaveADDr & 0xfe);
  //3.3 等待发送成功
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET)
{
	if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了
	{
		ret = ERROR;
		goto STOP;
	}
}
STOP:
	I2C_GenerateSTOP(I2C1,ENABLE);//发送停止位
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);//等待总线空闲
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

2.2.4:发送数据

在这里插入图片描述
发送数据前先清除ADDR标志位,清除ADDR(先读SR1寄存器,再度SR2寄存器)。

//4 .发送数据
  //4.1 清除ADDR标志位
I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1
I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2

  //4.2 向TDR寄存器写入数据
uint32_t i;
for(i = 0; i < Size ;i++)//Size是数据数组的个数
{
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1
	{
		if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)
		{
			ret = ERROR;
			goto STOP;
		}
	}
	I2C_SendData(I2C1,pData[i]);//向TDR写入数据
}

while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成
{
	if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)
	{
		ret = ERROR;
		goto STOP;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

最终代码①:

	//1 .等待总线空闲 
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
	
	//2 .发送起始位
	I2C_GenerateSTART(I2C1,ENABLE);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成
	
	//3 .发送地址
	  //3.1 清除标志位AF
	I2C_ClearFlag(I2C1,I2C_FLAG_AF);
	  //3.2 发送8为数据,7+1
	I2C_SendData(I2C1,SlaveADDr & 0xfe);
	  //3.3 等待发送成功
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET)
	{
		if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了
		{
			ret = ERROR;
			goto STOP;
		}
	}

	//4 .发送数据
	  //4.1 清除ADDR标志位
	I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1
	I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2
	
	  //4.2 向TDR寄存器写入数据
	uint32_t i;
	for(i = 0; i < Size ;i++)
	{
		while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1
		{
			if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)
			{
				ret = ERROR;
				goto STOP;
			}
		}
		I2C_SendData(I2C1,pData[i]);
	}
	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成
	{
		if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)
		{
			ret = ERROR;
			goto STOP;
		}
	}
	
	//5 .发送STOP
STOP:
	I2C_GenerateSTOP(I2C1,ENABLE);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

代码测试:通过向OLED模式发送指令将其屏幕点亮

#include "stm32f10x.h"

void App_I2C_Init(void);
void App_I2C_Send(uint8_t SlaveADDr,uint8_t* pData,uint16_t Size);

int main(void)
{
	//OLED指令
  uint8_t oled_init_command[] = {
  0x00, // Command Stream
  0xa8, 0x3f, // Set MUX Ratio
  0xd3, 0x00, // Set Display Offset
  0x40, // Set Display Start Line
  0xa0, // Set Segment re-map
  0xc0, // Set COM Output Scan Direction
  0xda, 0x02, // Set COM Pins hardware configuration
  0x81, 0x7f, // Set Contrast Control
  0xa5, // Enable Entire Display On
  0xa6, // Set Normal Display
  0xd5, 0x80, // Set OSC Frequency
  0x8d, 0x14, // Enable charge pump regulator
  0xaf, // Display on
	};
	App_I2C_Init();
	App_I2C_Send(0x78, oled_init_command, sizeof(oled_init_command)/sizeof(uint8_t));
	
	while(1)
	{
		
	}
}

void App_I2C_Init(void)
{
	//1 .开启GPIOB挂载的总线时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//初始化IO引脚
	GPIO_InitTypeDef GPIOInitStruct;
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;
	GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOB,&GPIOInitStruct);
	
	//2 .开启I2C挂载APB1总线的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启时钟
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//对I2C1进行复位
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//对I2C1进行释放
	
	//3 .配置I2C1的参数
	I2C_InitTypeDef I2CInitStruct;
	I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400K
	I2CInitStruct.I2C_Mode = I2C_Mode_I2C;//一般不使用SMBus
	I2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1
	I2C_Init(I2C1,&I2CInitStruct);
	
	//4 .使能I2C
	I2C_Cmd(I2C1,ENABLE);
}

void App_I2C_Send(uint8_t SlaveADDr,uint8_t* pData,uint16_t Size)
{
	ErrorStatus ret = SUCCESS;
	//1 .等待总线空闲 
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
	
	//2 .发送起始位
	I2C_GenerateSTART(I2C1,ENABLE);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成
	
	//3 .发送地址
	  //3.1 清除标志位AF
	I2C_ClearFlag(I2C1,I2C_FLAG_AF);
	  //3.2 发送8为数据,7+1
	I2C_SendData(I2C1,SlaveADDr & 0xfe);
	  //3.3 等待发送成功
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET)
	{
		if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了
		{
			ret = ERROR;
			goto STOP;
		}
	}

	//4 .发送数据
	  //4.1 清除ADDR标志位
	I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1
	I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2
	
	  //4.2 向TDR寄存器写入数据
	uint32_t i;
	for(i = 0; i < Size ;i++)
	{
		while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1
		{
			if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)
			{
				ret = ERROR;
				goto STOP;
			}
		}
		I2C_SendData(I2C1,pData[i]);
	}
	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成
	{
		if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)
		{
			ret = ERROR;
			goto STOP;
		}
	}
	
	//5 .发送STOP
STOP:
	I2C_GenerateSTOP(I2C1,ENABLE);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/1007061
推荐阅读
相关标签
  

闽ICP备14008679号