IIC工作模式时序分析
此处利用IO口模拟IIC通信过程中的时序。
通信过程
在IIC通信过程SDA存在两种模式(接收模式和发送模式),发送或接受一个字节(器件的7个bit+1个bit方向(1 - 读方向,0 - 写方向))
模式配置
- 当SDA为接入模式接收了1字节数据后在第九个时钟脉冲期间就要变成输出模式发送ask
- 当SDA为输出模式发送了1字节数据后在第九个时钟脉冲期间就要变成输入模式检测是否收到ask
- 因此SDA需配置两个模式而SCL模拟时序只需配置输出模式
#define SDA_SET(n) (n) ? GPIO_SetBits(GPIO?,GPIO_Pin_?) : GPIO_ResetBits(GPIO?,GPIO_Pin_?)
#define SCL_SET(n) (n) ? GPIO_SetBits(GPIO?,GPIO_Pin_?) : GPIO_ResetBits(GPIO?,GPIO_Pin_?)
#define SDA_READ GPIO_ReadInputDataBit(GPIO?,GPIO_Pin_?)
IIC的SCL配置
/**
* @name: IIC_SCLConfig
* @brief IIC的SCL配置
* @param void
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_SCLConfig()
{
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIO端口的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIO?,ENABLE);
//SCL
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_?;
GPIO_Init(GPIO?, &GPIO_InitStructure);
}
IIC的SDA配置
/**
* @name: IIC_SDAConfig
* @brief IIC的SCL配置
* @param
@GPIO_Mode
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_SDAConfig(GPIOMode_TypeDef GPIO_Mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIO端口的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIO?,ENABLE);
//SCL
GPIO_InitStructure.GPIO_Mode = GPIO_Mode; //输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_?;
GPIO_Init(GPIO?, &GPIO_InitStructure);
}
IIC的空闲状态
/**
* @name: IIC_Config
* @brief IIC的初始化
* @param
@GPIO_Mode
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_Config(void)
{
//1.设置SDA和SCL为输出模式
IIC_SCLConfig();
IIC_SDAConfig(GPIO_Mode_OUT);
//2.确保SDA和SCL处于空闲状态
SDA_SET(1);
SCL_SET(1);
delay_us(5);
}
IIC的开始信号
/**
* @name: IIC_Start
* @brief IIC的开始信号
* @param void
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_Start(void)
{
//1.设置SDA为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);
//2.确保SDA和SCL处于空闲状态
SDA_SET(1);
SCL_SET(1);
delay_us(5);
//3.设置SDA为低电平
SDA_SET(0);
delay_us(5);
}
IIC的发送字节
/**
* @name: IIC_SendByte
* @brief IIC的发送字节
* @param
@Byte
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_SendByte(uint8_t Byte) //1011 0110
{
//1.设置SDA为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);
//2.设置SDA为低电平,SCL为低电平
SDA_SET(0);
delay_us(5);
SCL_SET(0);
delay_us(5);
//2.循环发送8次,每次发送一个bit 遵循MSB 高位先出
for(int i=0;i<8;i++)
{
SDA_SET(1);
delay_us(5);
//3.判断待发送的字节的最高位 ???? ???? & 1000 0000
if( Byte & 0x80 )
{
SDA_SET(1);
}
else
SDA_SET(0);
Byte <<= 1;
delay_us(5);
SDA_SET(0);
delay_us(5);
}
}
IIC的接收字节
/**
* @name: IIC_RecvByte
* @brief IIC的接受字节
* @param void
* @retval uint8_t
* @date 2024/09/10
* @note 补充 注意 说明
*/
uint8_t IIC_RecvByte(void)
{
uint8_t i=0;
uint8_t data =0;
//保证SDA引脚为输入模式
IIC_SDAConfig(GPIO_Mode_IN);
SCL_SET(0);
delay_us(5);
for(i=0;i<8;i++)
{
//时钟线拉高,数据有效
SCL_SET(1);
delay_us(5);
data <<=1;
data |= SDA_READ;
delay_us(5);
//时钟线拉低,保持占用总线,总线是忙状态
SCL_SET(0);
delay_us(5);
}
}
IIC的判断从机是否应答
/**
* @name: IIC_IsSlaveACK
* @brief IIC的判断从机是否应答
* @param void
* @retval bool
* @date 2024/09/10
* @note 补充 注意 说明
*/
bool IIC_IsSlaveACK(void)
{
bool ack;
//1.设置SDA引脚为输入模式
IIC_SDAConfig(GPIO_Mode_IN);
//3.把SCL引脚电平拉高,此时为第9个脉冲的高电平,主机读取状态
SCL_SET(1);
delay_us(5);
//4.主机读取状态 1 表示未应答 0 表示已应答
if(SDA_READ)
ack = false;
else
ack = true;
//5.把SCL引脚电平拉低
SCL_SET(0);
delay_us(5);
return ack;
}
IIC的收到从机数据发送应答
/**
* @name: IIC_MasterACK
* @brief IIC的收到从机数据发送应答
* @param void
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_MasterACK(void)
{
// 1.设置SDA引脚为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);
// 2.把SCL引脚电平拉低,此时主机准备
SCL_SET(0);
delay_us(5);
// 3.设置SDA为高电平,表示应答
SDA_SET(1);
delay_us(5);
// 4.把SCL电平拉高,此时从机读取bit
SCL_SET(1);
delay_us(5);
}
IIC的停止信号
/**
* @name: IIC_Stop
* @brief IIC的停止信号
* @param void
* @retval void
* @date 2024/09/10
* @note 补充 注意 说明
*/
void IIC_Stop(void)
{
//1.设置SDA引脚为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);
//2.设置SDA和SCL均为低电平
SDA_SET(0);
SCL_SET(0);
delay_us(5);
//3.把SCL电平拉高
SCL_SET(1);
delay_us(5);
//4.把SDA电平拉高
SDA_SET(1);
delay_us(5);
}
标签:SCL,SET,void,模式,时序,SDA,IIC,GPIO
From: https://www.cnblogs.com/lu-ciana/p/18407041