STM32 中的IIC通信总线

介绍

IIC通信属于多主机从机通信模型,半双工通信,有两根通信线,SDA:用于表示数据,SCL:用于数据收发的同步

每个设备都有自己的独立地址,主机利用该地址进行通信。

时基单元

起始信号

停止信号

发送字节

接收字节

发送应答

接收应答

软件模拟IIC

#include "stm32f10x.h"
#include "Delay.h"

// 时钟线
#define SCL_PORT GPIOB
#define SCL_PIN GPIO_Pin_10

// 数据线
#define SDA_PORT GPIOB
#define SDA_PIN GPIO_Pin_11

// 时钟线写操作,置电平
void I2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(SCL_PORT, SCL_PIN, (BitAction)BitValue);
	Delay_us(10);
}

// 数据线写操作,置电平
void I2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(SDA_PORT, SDA_PIN, (BitAction)BitValue);
	Delay_us(10);
}

// 读数据线数据
uint8_t I2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(SDA_PORT, SDA_PIN);
	Delay_us(10);

	return BitValue;
}

/// @brief 初始化I2C,模拟IIC(软件IIC)
/// @param
void MyI2C_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

// 以下是6个时序基本单元

/// @brief 起始位
/// @param
void MyI2C_Start(void)
{
	/*
	SDA : -------____

	SCL : -----------
	*/
	
	I2C_W_SDA(1); // 根据时序图释放SDA
	I2C_W_SCL(1); // 根据时序图释放SCL

	I2C_W_SDA(0); // 拉低SDA,根据时序图编写基本时序单元
	I2C_W_SCL(0); // 拉低时钟线,保证时序统一
}

/// @brief 停止位
/// @param
void MyI2C_Stop(void)
{
	/*
	SDA : ____-------

	SCL : -----------
	*/
	I2C_W_SDA(0); // 先保证数据线为低电平

	I2C_W_SCL(1);
	I2C_W_SDA(1);
}

/// @brief 发送一个字节
/// @param Byte 发送的字节
void MyI2C_SendByte(uint8_t Byte)
{
	// 在时钟低电平时将数据放入数据线,再将时钟线拉高读取数据
	// IIC使用MSB(高位先行传输,按一个位一个位传输)
	for (uint32_t i = 0; i < 8; i++)
	{
		// I2C_W_SDA(Byte & 0x80); // 取最高位   0x80 =>> 1000 0000
		I2C_W_SDA(Byte & (0x80 >> i));
		I2C_W_SCL(1);
		I2C_W_SCL(0);
	}
}


/// @brief 接收一个字节
/// @param
/// @return	返回数据线上接收到的字节
uint8_t MyI2C_RecvByte(void)
{
	uint8_t Byte = 0x00;
	I2C_W_SDA(1); // 转交控制权给从机

	for (uint32_t i = 0; i < 8; i++)
	{
		I2C_W_SCL(1); // 时钟高电平读取从机发送的数据
		/* 判断数据并拼接到一起返回字符串 */
		if (I2C_R_SDA() == 1)
		{
			Byte |= (0x80 >> i); // 从高位向地位依次运算,得到结果
		}
		I2C_W_SCL(0); // 时钟低电平等待从机发送的数据
	}

	return Byte;
}

/// @brief 发送应答
/// @param AckBit
void MyI2C_SendAck(uint8_t AckBit)
{
	// 刚开始时钟线是低电平
	I2C_W_SDA(AckBit); // 发送bit
	I2C_W_SCL(1);	   // 从机读取电平
	I2C_W_SCL(0);	   // 恢复低电平
}

/// @brief 读取应答信息
/// @param
/// @return 返回读取到的应答信息
uint8_t MyI2C_RecvAck(void)
{
	uint8_t AckBit; // 存放信息
	I2C_W_SDA(1);
	I2C_W_SCL(1); // 时钟线

	AckBit = I2C_R_SDA(); // 读取bit
	I2C_W_SCL(0);		  // 时钟线

	return AckBit;
}

硬件配置

    /* enable RCC */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* GPIO_INIT */

    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; // 设置为复用开漏输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C_INIT */
    I2C_DeInit(I2C1);
    I2C_InitTypeDef I2C_InitStruct;
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 设置从机地址位数;
    I2C_InitStruct.I2C_ClockSpeed = 400000;                                // lower 400K
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; //
    I2C_InitStruct.I2C_OwnAddress1 = 0x30;  // 主机自己的IIC地址
    I2C_Init(I2C1, &I2C_InitStruct);

    /* I2C enable */
    I2C_Cmd(I2C1, ENABLE);

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值