版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SheepTech/article/details/82696959
本文章原始地址:http://feotech.com/?p=69
本程序主要用于驱动STM32单片机芯片的硬件I2C寄存器,实现通过使用芯片自带的I2C寄存器进行数据的发送与接收.
本例程中采用I2C寄存器查询的方式来实现数据传输,当I2C对应寄存器指定状态时方可执行下一步操作.
/**
******************************************************************************
* @file Hardware_I2C.c
* @author Ryan Zhao
* @version V1.0.0
* @date 2017-04-27
* @brief STM32硬件I2C底层驱动.
******************************************************************************
* @attention Null
*
******************************************************************************
*/
/**
* @brief I2C引脚与寄存器功能配置.
* @param None.
* @retval None.
*/
void I2C_Configuration(void)
{
/*GPIO与IIC初始化结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/*GPIO与IIC时钟使能*/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //GPIOB时钟使能
RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE ); //I2C时钟使能
/*初始化GPIO*/
GPIO_InitStructure.GPIO_Pin = HW_I2C_SDA_PIN | HW_I2C_SCL_PIN; //初始化 IIC GPIO
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最高输出速度50Hz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //输入输出模式为复用功能开漏输出
GPIO_Init( GPIOB, &GPIO_InitStructure ); //根据GPIO初始化结构体初始化GPIOB
/*初始化I2C*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //设置为I2C模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //设置I2C的占空比,低电平除以高电平值为2
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能ACK信号
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //指定7位地址
I2C_InitStructure.I2C_ClockSpeed = 400000; //时钟频率,必须小于等于400KHz
I2C_Cmd( HW_I2C, ENABLE ); //使能I2C
I2C_Init( HW_I2C, &I2C_InitStructure ); //根据I2C初始化结构体初始化I2C
/*允许一字节一应答模式*/
I2C_AcknowledgeConfig( HW_I2C, ENABLE ); //使能I2C应答状态
}
/**
* @brief 从I2C指定地址中读取数据;
* @param 读取的地址,读取后返回的数据;
* @retval 1:读取数据成功,0:读取数据无效;
*/
unsigned char I2C_ReadByte(unsigned char Read_Address,unsigned char * Read_Data)
{
unsigned char wait_time_out = wait_time_value;//等待I2C器件响应的延时
* Read_Data = 0;
while (I2C_GetFlagStatus(HW_I2C, I2C_FLAG_BUSY)) //判断IIC接口状态.当IIC状态为BUSY时,一直停在这里循环
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
/*发送START之后要等待,意味着START条件被正确释放,此时IIC总线上没有其它外设*/
I2C_GenerateSTART( HW_I2C, ENABLE ); //产生START条件
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_MODE_SELECT)) //判断开始信号是否已经发送完成
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_Send7bitAddress(HW_I2C, ADXL_WRITE, I2C_Direction_Transmitter ); //发送从机地址ADXL_WRITE以选择从机,主机为发送模式
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //如果主机发射模式被选中(死循环等待从机发送ACK信号)
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_SendData(HW_I2C, Read_Address ); //将write_address,即要读的地址通过IIC2发送出去
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) //如果地址已经从IIC成功发射出去(死循环等待ACK信号
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_GenerateSTART(HW_I2C, ENABLE ); //产生START条件
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_MODE_SELECT)) //如果主机被选中(死循环等待ACK信号)
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
/***主机接收数据***/
I2C_Send7bitAddress(HW_I2C, ADXL_READ, I2C_Direction_Receiver ); //主机设置为接收模式
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) //如果主机接收模式被选中(死循环等待ACK信号)
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_AcknowledgeConfig(HW_I2C, DISABLE ); //失能IIC的应答状态 NACK
I2C_GenerateSTOP( HW_I2C, ENABLE ); //产生STOP条件
while (!(I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED))) //判断数据是否接收完成
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_AcknowledgeConfig(HW_I2C, ENABLE ); //再一次使能IIC的应答状态
* Read_Data = I2C_ReceiveData(HW_I2C); //返回IIC接收的数据
return 1;
}
/**
* @brief 通过I2C接口将数据写入从机指定地址中.
* @param 要写入的数据,接收数据的地址;
* @retval 1:数据写入成功 0:数据写入失败
*/
unsigned char I2C_Write_Byte(uint8_t Point_Buffer,uint8_t Write_Address)
{
unsigned char wait_time_out = wait_time_value;//等待I2C器件响应的延时
while (I2C_GetFlagStatus(HW_I2C, I2C_FLAG_BUSY)) //判断当前I2C接口状态是否为Busy
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_GenerateSTARTHW_I2C, ENABLE ); //产生Start信号
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_MODE_SELECT)) //判断Start信号是否已经发送
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_Send7bitAddress(HW_I2C, ADXL_WRITE, I2C_Direction_Transmitter ); //发送从机地址以选择从机,主机为发送模式
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //判断发送的地址是否与从机匹配,等待从机发送ACK信号
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_SendData(HW_I2C, Write_Address ); //将write_address,即要写的寄存器地址通过IIC发送出去
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) //判断数据是否发送完成
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
/*往寄存器发送数据data*/
I2C_SendData(HW_I2C, Point_Buffer );
while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) //判断数据是否发送完成
{
if((wait_time_out --) == 0) //延时等待
{
return 0; //响应超时,返回无效标志
}
}
I2C_GenerateSTOP( HW_I2C, ENABLE ); //IIC2产生STOP条件
return 1;//数据写入完成 1
}
/**
******************************************************************************
* @file Hardware_I2C.h
* @author Ryan Zhao
* @version V1.0.0
* @date 2017-04-27
* @brief STM32硬件I2C底层驱动.
******************************************************************************
* @attention Null
*
******************************************************************************
*/
/*********************I2C 物理层GPIO定义*******************/
#define HW_I2C I2C1 //第一组I2C接口
#define HW_I2C_SDA_PIN GPIO_Pin_7
#define HW_I2C_SDA_GPIO_PORT GPIOB
#define HW_I2C_SCL_PIN GPIO_Pin_6
#define HW_I2C_SCL_GPIO_PORT GPIOB
#define wait_time_value 200 //等待I2C器件响应的延时