硬件I2C

I2C

STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
支持多主机模型
支持7位/10位地址模式
支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
支持DMA
兼容SMBus协议

STM32F103C8T6 硬件I2C资源:I2C1、I2C2

I2C结构

在这里插入图片描述

SDA 和 SCL:与 GPIO 口复用,或重映射(引脚定义表)
SMBALERT:SMABus 专用(普通 I2C 不需要)
DATA register:将保存待发送或接收到的数据
数据移位寄存器:按照高位先行,将数据移出
状态寄存器:记录数据发送和接收所产生的事件
控制寄存器:使能/失能,是否开启DMA/中断,I2C模式选择

在这里插入图片描述

I2C数据发送接收流程

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

EV5:起始条件已发送
EV6:地址已发送
EV7:已接收到数据(DR寄存器非空)
EV7_1:接收结束
EV8:正在发送数据(DR寄存器空,移位寄存器非空)
EV8_1:可写入DR寄存器(移位、DR寄存器空)
EV8_2:发送结束

初始化流程

  • RCC:开启GPIO和I2C时钟
  • GPIO初始化:SDA和SCL均为(GPIO_Mode_AF_OD复用开漏)
  • I2C结构体:I2C_InitTypeDef
    • I2C_Mode:模式I2C_Mode_I2C
    • I2C_ClockSpeed:速度
    • I2C_DutyCycle:时钟占空比,只在>100kHZ时有用
    • I2C_Ack:从机是否应答
    • I2C_AcknowledgedAddress:作为从机,可响应的地址位数(7/10)
    • I2C_OwnAddress1:做从机时的地址
  • I2C使能:I2C_Cmd()

标准库函数使用模板

I2C初始化函数

void I2C_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_ClockSpeed = 50000;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;
	I2C_Init(I2C2, &I2C_InitStructure);
	
	I2C_Cmd(I2C2, ENABLE);
}

发送数据函数

/* I2C_send
* @ param1  从机地址
* @ param2  待发送数据
* @ retval  None
*/
void I2C_send(unsigned char ADDRESS, unsigned char DATA) 
{
    int Timeout;
    I2C_GenerateSTART(I2C2, ENABLE);
    Timeout = 10000;
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS) {//WAIT EV5
        Timeout --;
        if(Timeout == 0) {
            return ;
        }
    }
    I2C_Send7bitAddress(I2C2, ADDRESS, I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);//wait EV6
//第一个字节
    I2C_SendData(I2C2, DATA);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);//wait EV8
//最后一个字节
    I2C_SendData(I2C2, DATA);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);//wait EV8_2
}

接收数据函数

/* I2C_receive
* @ param1  从机地址
* @ param2  发送的指令
* @ retval  接收的数据
*/
unsigned char I2C_receive(unsigned char ADDRESS, unsigned char DATA) 
{
    int result = 0x00;
    I2C_GenerateSTART(I2C2, ENABLE);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);//WAIT EV5

    I2C_Send7bitAddress(I2C2, ADDRESS, I2C_Direction_Transmitter);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);//wait EV6

//最后一个字节
    I2C_SendData(I2C2, DATA);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);//wait EV8_2
//开始接收
    I2C_GenerateSTART(I2C2, ENABLE);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);//WAIT EV5
//地址
    I2C_Send7bitAddress(I2C2, ADDRESS, I2C_Direction_Receiver);
    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);//wait EV6

    I2C_AcknowledgeConfig(I2C2, DISABLE);
    I2C_GenerateSTOP(I2C2, ENABLE);

    while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
    result = I2C_ReceiveData(I2C2)

    I2C_AcknowledgeConfig(I2C2, ENABLE);

    return result;
}

I2C函数

/* I2C_GenerateSTART        //生成终止条件
* @ param1  选择I2C通道
* @ param2  使能 / 失能
* @ retval  None
*/
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);

/* I2C_GenerateSTOP         //生成起始条件
* @ param1  选择I2C通道
* @ param2  使能 / 失能
* @ retval  None
*/
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);

/* I2C_SendData             //发送一字节数据
* @ param1  选择I2C通道
* @ param2  待发送数据
* @ retval  None
*/
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);

/* I2C_ReceiveData           //接收一字节数据
* @ param1  选择I2C通道
* @ retval  接收到的数据
*/
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);

/* I2C_Send7bitAddress        //发送地址
* @ param1  选择I2C通道
* @ param2  7位地址
* @ param2  接受地址 / 发送地址
* @ retval  None
*/
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);

/* I2C_AcknowledgeConfig       //ACK应答位设置
* @ param1  选择I2C通道
* @ param2  使能 / 失能
* @ retval  None
*/
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);

事件检测函数

/* I2C_CheckEvent
* @ param1  选择I2C通道
* @ param2  选择监视的事件
* @ retval  None
*/
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);

流程图


							 +----------+                 +----+
							 |时钟控制器  +---------------->|GPIO|  SCL
	一主多从模式			     +----------+                 |    +------->
														  +----+
		
							+---------------------------->+----+
						 +--|---------------+             |GPIO|  SDA
						 |  |               |             |    |<------>
		+----------+     |  <<移位寄存器<<    |<------------+----+
		|数据控制器  +---->|         |        |
		+----------+     |   数据寄存器DR     |
			CR  		 |                  |
						 +------------------+


7位主发送:
	+-+   +----+-+         +-----+-+-----+-+         +-----+-+     +-+
	|S|   |ADDR|A|         |DATA1|A|DATA2|A|         |DATAN|A|     |P|
	+-+---+----+-+---------+-----+-+---+-+-+--....---+-----+-+-----+-+
	|EV5|      |EV6|EV8_1| EV8 | |EV8|                     |EV8_2|
	+---+      +---+-----+-----+ +---+                     +-----+
7位主接收:
	+-+   +----+-+   +-----+-+-----+-+          +-----+--+---+
	|S|   |ADDR|A|   |DATA1|A|DATA2|A|          |DATAN|NA| P | 
	+-+---+----+-+---+-----+-+---+-+-+---+ .... +-----+--+---+
	|EV5|        |EV6|EV6_1| |EV7|   |EV7|      |EV7_1|  |EV7|
	+---+        +---+-----+ +---+   +---+      +-----+  +---+


                                     ------ BY Flier

2023.9.3

Reference:江协科技、《stm32f10x用户手册》、《stm32库开发实战指南教程》

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值