一、IIC通信
•I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线
•两根通信线:SCL(Serial Clock)、SDA(Serial Data)
•同步,半双工
•带数据应答
•支持总线挂载多设备(一主多从、多主多从)
二、硬件电路
•所有I2C设备的SCL连在一起,SDA连在一起
•设备的SCL和SDA均要配置成开漏输出模式
•SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右,默认状态为高电平
三、IIC时序单元
•起始条件:SCL高电平期间,SDA从高电平切换到低电平
•终止条件:SCL高电平期间,SDA从低电平切换到高电平
•发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
•接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
•发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
•接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
IIC时序实现代码如下:
IIC_soft.c
#include "gpio.h"
void MyI2C_W_SCL(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,(GPIO_PinState)BitValue);
HAL_Delay(10);
}
void MyI2C_W_SDA(uint8_t BitValue)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,(GPIO_PinState)BitValue);
HAL_Delay(10);
}
uint8_t MyI2C_R_SDA()
{
uint8_t BitValue;
BitValue = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2);
HAL_Delay(10);
return BitValue;
}
void MyI2C_Init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_SET);
/*Configure GPIO pins : PA1 PA2 */
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void MyI2C_Start()
{
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
MyI2C_W_SDA(0);
MyI2C_W_SCL(0); //为发送数据做准备
}
void MyI2C_Stop()
{
MyI2C_W_SDA(0);
MyI2C_W_SCL(1);
MyI2C_W_SDA(1);
}
void MyI2C_SendByte(uint8_t Byte)
{
uint8_t i;
for(i=0;i<8;i++)
{
MyI2C_W_SDA(Byte & (0x80>>i)); //从高到低取数据位
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}
}
uint8_t MyI2C_ReceiveByte()
{
uint8_t i;
uint8_t temp = 0;
MyI2C_W_SDA(1); //接受数据前释放SDA
for(i=0;i<8;i++)
{
MyI2C_W_SCL(1);
if(MyI2C_R_SDA()==1)
{
temp |= (0x80>>i);
}
MyI2C_W_SCL(0);
}
return temp;
}
void MyI2C_SendAck(uint8_t AckBit)
{
MyI2C_W_SDA(AckBit);
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}
uint8_t MyI2C_ReceiveAck()
{
uint8_t AckBit = 0;
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
AckBit = MyI2C_R_SDA();
MyI2C_W_SCL(0);
return AckBit;
}
IIC_soft.h
#ifndef __IIC_SOFT_H__
#define __IIC_SOFT_H__
#include<stdint.h>
void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);
void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);
#endif
四、IIC数据帧格式
1、指定位置写数据
•对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
2、指定位置读数据
•对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
参考代码如下:
I2C_rj.c
#include "IIC_soft.h"
#define SlaveAddress 0x40 //根据实际而定
#define RegAddress 0x80
void IIC_WriteReg(uint8_t Data)
{
MyI2C_Start();
MyI2C_SendByte(SlaveAddress|0x00); //写操作指令
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_SendByte(Data);
MyI2C_ReceiveAck();
MyI2C_Stop();
}
uint8_t IIC_ReadReg(void)
{
uint8_t Data;
MyI2C_Start();
MyI2C_SendByte(SlaveAddress|0x00);
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_Start();
MyI2C_SendByte(SlaveAddress|0x01); //读操作指令
MyI2C_ReceiveAck();
Data = MyI2C_ReceiveByte();
MyI2C_SendAck(1); //非应答,不再读取数据
MyI2C_Stop();
}
上述就是STM32HAL库软件模拟IIC通信的大致内容,更多内容见后续分享,感谢大家的点赞和关注,祝大家每天进步!!!