1.直接贴代码,不废话。参考这篇文章,感谢原作者。原作者没有提供调用参数。在他的基础上增加修改代码。他对芯片手册中最重要的地方没有做出解释,现在补上。其余的直接复制代码,使用的是STM32的模拟IIC总线。
FM24手册上并没有详细的说这儿,还是我没有看到,请各位指正,仔细看AT24的EEROM说的很清楚,这两个一样的。如果这个A8位是读写地址的最高位,因为FM24C04,是4Kbit,所以4*1024/8=512Bytes,可以分开位两个256,所以写前256字节使用的地址范围是0-255(A8=0,A7-A0=0-255),后面的256字节使用的地址范围是256-512(A8=1,A7-A0=0-255)。
所以遍历整个FRAM的过程就看第4部分主函数调用的部分。
还有需要注意的地方是,R/Wbit,仔细看手册,写的时候R/W是0,读的时候R/W是1。
I2C学习笔记---STM32F091VC+I2C存储设备(AT24C04BN或FM24CL64B)_fm24cl04b与at24c04区别-CSDN博客
2.头文件
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _BSP_FRAM_H
#define _BSP_FRAM_H
#include "main.h"
#ifdef __cplusplus
extern "C" {
#endif
/* 定义读写SCL和SDA的宏,已增加代码的可移植性和可阅读性 */
/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define I2C_SCL_H HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin ,GPIO_PIN_SET) /* SCL = 1 */
#define I2C_SCL_L HAL_GPIO_WritePin(I2C_SCL_GPIO_Port, I2C_SCL_Pin ,GPIO_PIN_RESET) /* SCL = 0 */
#define I2C_SDA_H HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin ,GPIO_PIN_SET) /* SDA = 1 */
#define I2C_SDA_L HAL_GPIO_WritePin(I2C_SDA_GPIO_Port, I2C_SDA_Pin ,GPIO_PIN_RESET) /* SDA = 0 */
#define I2C_SDA_READ() HAL_GPIO_ReadPin(I2C_SDA_GPIO_Port, I2C_SDA_Pin)/* 读SDA口线状态 */
#define I2C_SPEED_1K 5000 //根据处理器速度设置,这里处理器速度是72MHz
typedef enum
{
I2C_SUCCESS = 0,
I2C_TIMEOUT,
I2C_ERROR,
}I2C_StatusTypeDef;
extern uint32_t i2c_speed; //I2C访问速度 = I2C_SPEED_1K / i2c_speed
/* ---------------------------依照I2C协议编写的时序函数------------------------------*/
void BSP_I2C_Init(void); //初始化I2C的IO口
void I2C_Start(void); //发送I2C开始信号
void I2C_Stop(void); //发送I2C停止信号
uint8_t I2C_Wait_ACK(void); //I2C等待ACK信号
void I2C_ACK(void); //I2C发送ACK信号
void I2C_NACK(void); //I2C不发送ACK信号
void I2C_Send_Byte(uint8_t data); //I2C发送一个字节
uint8_t I2C_Read_Byte(uint8_t ack); //I2C读取一个字节
uint16_t I2C_SetSpeed(uint16_t speed);//设置I2C速度(1Kbps~400Kbps,speed单位,Kbps)
/* ---------------------------以下部分是封装好的I2C读写函数--------------------------- */
//具体到某一个器件,请仔细阅读器件规格书关于I2C部分的说明,因为某些器件在I2C的读写操作会
//有一些差异,下面的代码我们在绝大多数的I2C器件中,都是验证OK的!
I2C_StatusTypeDef I2C_WriteOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t Data);//向I2C从设备写入一个字节
I2C_StatusTypeDef I2C_WriteBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num);//向I2C从设备连续写入Num个字节
I2C_StatusTypeDef I2C_ReadOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t* Data);//从I2C从设备读取一个字节
I2C_StatusTypeDef I2C_ReadBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num);//从I2C设备连续读取Num个字节
I2C_StatusTypeDef I2C_WriteBit(uint8_t DevAddr, uint8_t DataAddr, uint8_t Bitx, uint8_t BitSet);
#endif /* _bsp_FRAM_H */
3.C文件
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "main.h"
#include "fm24c.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#if 0
#define FM24CL64 1
#endif
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
// I2C访问速度 = I2C_SPEED_1K / i2c_speed
uint32_t i2c_speed;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief 模拟I2C接口初始化
* @param None
* @retval None
* @note
* SCL: PB8
* SDA: PB9
*/
void BSP_I2C_Init(void)
{
I2C_SetSpeed(100);//设置I2C访问速度为100Kbps
}
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pins : PDPin PDPin */
GPIO_InitStruct.Pin = I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pins : PDPin PDPin */
GPIO_InitStruct.Pin = I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
/**
* @brief 产生I2C起始信号
* @param None
* @retval None
* @note
* 请参考I2C通信协议,I2C起始信号:当SCL为高电平时,SDA由高变低
* 如下图所示:方框部分表示I2C起始信号
* _____ |
* __|__ | | ___ ___ ___ ___ ___ ___ ___ ___
* SDA: | \__|____|_/ \/ \/ \/ \/ \/ \/ \/ \ /
* | | | \___/\___/\___/\___/\___/\___/\___/\___/\___/
* __|_____|_ | _ _ _ _ _ _ _ _ _
* SCL: | | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_
* |_____| |
* start D7 D6 D5 D4 D3 D2 D1 D0 ACK
*/
void I2C_Start(void)
{
uint32_t i2c_delay = i2c_speed;
SDA_OUT(); //SDA设置为输出
I2C_SDA_H; //SDA: 高
I2C_SCL_H; //SCL: 高
i2c_delay = i2c_speed;//延时>4.7us
while(i2c_delay--){}
I2C_SDA_L; //当SCL为高电平时,SDA由高变低
i2c_delay = i2c_speed;//延时>4us
while(i2c_delay--){}
I2C_SCL_L; //SCL变低,钳住I2C总线,准备发送或接收数据
}
/**
* @brief 产生I2C停止信号
* @param None
* @retval None
* @note
* 请参考I2C通信协议,I2C停止信号:当SCL为高电平时,SDA由低变高
* 发送完STOP信号后,SCL和SDA都为高电平,即释放了I2C总线
* 如下图所示:方框部分表示I2C起始信号
* _____
* ___ ___ ___ ___ | __|_
* SDA: / \/ \/ \/ \ | / |
* \___/\___/\___/\___/\______|_/ |
* _ _ _ _ _ _|_____|_
* SCL: / \__/ \__/ \__/ \__/ \__/ | |
* |_____|
* D3 D2 D1 D0 ACK stop
*/
void I2C_Stop(void)
{
uint32_t i2c_delay = i2c_speed;
SDA_OUT(); //SDA设置为输出
I2C_SDA_L; //SDA低电平
I2C_SCL_H; //SCL高电平
i2c_delay = i2c_speed;//延时>4us
while(i2c_delay--){}
I2C_SDA_H; //STOP:当SCL为高电平时,SDA由低变高
i2c_delay = i2c_speed;
while(i2c_delay--){}//延时>4.7us
}
/**
* @brief 等待ACK应答信号
* @param None
* @retval 1 - 未接收到应答信号ACK;0 - 接收到应答信号ACK
* @note
* 请参考I2C通信协议,检测ACK应答信号:当SCL为高电平时,读取SDA为低电平
* 如下图所示:方框部分表示I2C起始信号
* ________ _____
* ___ ___ ___ ___ | _ | | __|_
* SDA: / \/ \/ \/ \|/ \ | | / |
* \___/\___/\___/\___/| \____|___|_/ |
* _ _ _ _ | _____ | _|_____|
* SCL: / \__/ \__/ \__/ \__|/ \_|_/ | |
* |________| |_____|
* D3 D2 D1 D0 ACK stop
*/
uint8_t I2C_Wait_ACK(void)
{
uint32_t i2c_delay = i2c_speed;
uint8_t timeout = 0;
SDA_IN(); //SDA设置为输入
I2C_SDA_H; //SDA上拉输入
I2C_SCL_H; //SCL设置为高电平
i2c_delay = i2c_speed;
while(i2c_delay--){}
while(I2C_SDA_READ() == 1)//等待ACK
{
if(timeout++ > 250)
{
I2C_Stop();
return 1;
}
}
I2C_SCL_L;//钳住I2C总线:时钟信号设为低电平
return 0;
}
/**
* @brief 产生ACK应答信号
* @param None
* @retval None
* @note
* 请参考I2C通信协议,产生ACK应答信号: 在SDA为低电平时,SCL产生一个正脉冲
* 如下图所示:方框部分表示I2C起始信号
* _____ _____
* ___ ___ ___ ___ | | | __|_
* SDA: / \/ \/ \/ \| | | / |
* \___/\___/\___/\___/|\____|___|_/ |
* _ _ _ _ | _ | _|_____|_
* SCL: / \__/ \__/ \__/ \__|_/ \_|_/ | |
* |_____| |_____|
* D3 D2 D1 D0 ACK stop
*/
void I2C_ACK(void)
{
uint32_t i2c_delay = i2c_speed;
I2C_SCL_L; //低电平
SDA_OUT(); //设置SDA为输出
I2C_SDA_L; //ACK信号
i2c_delay = i2c_speed;
while(i2c_delay--){}//延时>4us
I2C_SCL_H; //高电平
i2c_delay = i2c_speed;
while(i2c_delay--){}//延时>4us
I2C_SCL_L; //钳住I2C总线:时钟信号设为低电平
}
/**
* @brief 产生非应答信号NACK
* @param None
* @retval None
* @note
* 请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
* 如下图所示:方框部分表示I2C起始信号
* _____ ______
* ___ ___ ___ ___ | ____|_ | __|_
* SDA: / \/ \/ \/ \|/ | \ | / |
* \___/\___/\___/\___/| | \_|__/ |
* _ _ _ _ | _ | __|______|_
* SCL: / \__/ \__/ \__/ \__|_/ \_|_/ | |
* |_____| |______|
* D3 D2 D1 D0 NACK stop
*/
void I2C_NACK(void)
{
uint32_t i2c_delay = i2c_speed;
I2C_SCL_L; //低电平
SDA_OUT(); //SDA设置为输出
I2C_SDA_H; //NACK信号
i2c_delay = i2c_speed;
while(i2c_delay--){}//延时>4us
I2C_SCL_H; //高电平
i2c_delay = i2c_speed;
while(i2c_delay--){}//延时>4us
I2C_SCL_L; //钳住I2C总线:时钟信号设为低电平
}
/**
* @brief I2C发送一个字节
* @param None
* @retval None
* @note
* 请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
* 如下图所示:方框部分表示I2C起始信号
*
* _____ |<------------I2C数据发送周期------------>|
* __|__ | | ___ ___ ___ ___ ___ ___ ___ ___ | _
* SDA: | \__|____|_/ \/ \/ \/ \/ \/ \/ \/ \|/
* | | | \___/\___/\___/\___/\___/\___/\___/\___/|\_
* __|_____|_ | _ _ _ _ _ _ _ _ |
* SCL: | | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
* |_____| | |
* start | D7 D6 D5 D4 D3 D2 D1 D0 |
*/
void I2C_Send_Byte(uint8_t data)
{
uint8_t i = 0;
uint32_t i2c_delay = i2c_speed;
SDA_OUT(); //SDA设为输出
I2C_SCL_L; //钳住I2C总线:SCL设为低电平
for(i = 0; i < 8; i++)
{
if(data&0x80)I2C_SDA_H; //高位先传
else I2C_SDA_L;
i2c_delay = i2c_speed;
while(i2c_delay--){} //延时>4us
I2C_SCL_H; //在SCL上产生一个正脉冲
i2c_delay = i2c_speed;
while(i2c_delay--){} //延时>4us
I2C_SCL_L;
i2c_delay = i2c_speed/3;
while(i2c_delay--){} //延时>1us
data <<= 1; //右移一位
}
}
/**
* @brief 从I2C读取一个字节
* @param ack : 0 - NACK; 1 - ACK
* @retval 接收到的数据
* @note
* 请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
* 如下图所示:方框部分表示I2C起始信号
*
* _____ |<------------I2C数据读取周期(ACK)------------>|
* __|__ | | ___ ___ ___ ___ ___ ___ ___ ___ |
* SDA: | \__|____|_/ \/ \/ \/ \/ \/ \/ \/ \ |
* | | | \___/\___/\___/\___/\___/\___/\___/\___/\____|_
* __|_____|_ | _ _ _ _ _ _ _ _ _ |
* SCL: | | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
* |_____| | |
* start | D7 D6 D5 D4 D3 D2 D1 D0 ACK
*
* _____ |<------------I2C数据读取周期(NACK)----------->|
* __|__ | | ___ ___ ___ ___ ___ ___ ___ ___ ____|_
* SDA: | \__|____|_/ \/ \/ \/ \/ \/ \/ \/ \/ |
* | | | \___/\___/\___/\___/\___/\___/\___/\___/ |
* __|_____|_ | _ _ _ _ _ _ _ _ _ |
* SCL: | | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
* |_____| | |
* start | D7 D6 D5 D4 D3 D2 D1 D0 NACK
*/
uint8_t I2C_Read_Byte(uint8_t ack)
{
uint8_t i, receive = 0x00;
uint32_t i2c_delay = i2c_speed;
I2C_SCL_L; //SCL低电平
SDA_IN(); //SDA设置为输入
for(i = 0; i < 8; i++)
{
i2c_delay = i2c_speed;
while(i2c_delay--);
I2C_SCL_H; //高电平
i2c_delay = i2c_speed;
while(i2c_delay--);
receive <<= 1;
if(I2C_SDA_READ()) receive |= 1; //高位在前
I2C_SCL_L;
}
if (ack == 0) I2C_NACK(); //发送NACK
else I2C_ACK(); //发送ACK
return receive; //返回接收到的数据
}
/**
* @brief 设置I2C速度
* @param speed : I2C速度,单位Kbps
* @retval 返回设置前的I2C速度
* @note I2C速度设置范围是: 1Kbps ~ 400Kbps
*/
uint16_t I2C_SetSpeed(uint16_t speed)
{
uint16_t temp;
//I2C速度必须小于400Kbps,大于 1Kbps
if((speed > 400)|| (speed < 1)) return 0;
temp = I2C_SPEED_1K / i2c_speed; //备份原来的i2c速度
i2c_speed = I2C_SPEED_1K / speed; //设置新的i2c速度
return temp; //返回设置前的i2c速度
}
/* ---------------------------以下部分是封装好的I2C读写函数--------------------------- */
//具体到某一个器件,请仔细阅读器件规格书关于I2C部分的说明,因为某些器件I2C的读写操作会
//有一些差异,下面的代码我们在绝大多数的I2C器件中,都是验证OK的!
/**
* @brief 向设备指定地址写入单一Byte数据
* @param DevAddr : I2C从设备地址
* @param DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
* @param Data : 写入的数据
* @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
* @note
* 1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
* 2 - 时序:
* _______________________________________
* | | | | | | | | |
* Master:|S|DevAddr+W| |DataAddr| |Data| |P|
* |_|_________|___|________|___|____|___|_|
* _______________________________________
* | | | | | | | | |
* Slave: | | |ACK| |ACK| |ACK| |
* |_|_________|___|________|___|____|___|_|
*/
I2C_StatusTypeDef I2C_WriteOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t Data)
{
I2C_Start(); //Master发送起始信号
I2C_Send_Byte(DevAddr); //Master发送从设备地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#ifdef FM24CL64
I2C_Send_Byte(DataAddr >> 8); //发送高8位数据地址
if(I2C_Wait_ACK())
{
return I2C_TIMEOUT;//等待ACK超时错误
}
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK())
{
return I2C_TIMEOUT;//等待ACK超时错误
}
#else
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#endif
I2C_Send_Byte(Data); //发送数据
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
I2C_Stop(); //发送停止信号
return I2C_SUCCESS;
}
/**
* @brief 向设备指定地址连续写入数据(Burst写模式)
* @param DevAddr : I2C从设备地址
* @param DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
* 对于Burst模式,DataAddr一般是设备的FIFO,缓存,或存储设备的数据地址
* @param *pData : 写入的数据首地址
* @param Num : 连续写入的数据个数
* @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
* @note
* 1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
* 2 - 时序:
* ____________________________________________________
* | | | | | | | | | | | |
* Master:|S|DevAddr+W| |DataAddr| |Data| |...|Data| |P|
* |_|_________|___|________|___|____|___|___|____|___|_|
* ____________________________________________________
* | | | | | | | | | | | |
* Slave: | | |ACK| |ACK| |ACK|...| |ACK| |
* |_|_________|___|________|___|____|___|___|____|___|_|
*/
I2C_StatusTypeDef I2C_WriteBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num)
{
uint32_t i = 0;
I2C_Start(); //Master发送起始信号
I2C_Send_Byte(DevAddr); //Master发送从设备地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT; //等待ACK超时错误
#ifdef FM24CL64
I2C_Send_Byte(DataAddr >> 8); //发送高8位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#else
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#endif
for(i = 0; i < Num; i++)
{
I2C_Send_Byte(*(pData+i)); //发送数据
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
}
I2C_Stop(); //发送停止信号
return I2C_SUCCESS;
}
/**
* @brief 从指定设备读取1Byte数据
* @param DevAddr : I2C从设备地址
* @param DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
* @param *Data : 数据的存放地址
* @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
* @note
* 1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
* 2 - 时序:
* _________________________________________________________
* | | | | | | | | | | | |
* Master:|S|DevAddr+W| |DataAddr| |S|DevAddr+R| | |NACK|P|
* |_|_________|___|________|____|_|_________|___|____|____|_|
* _________________________________________________________
* | | | | | | | | | | | |
* Slave: | | |ACK| |ACK | | |ACK|Data| | |
* |_|_________|___|________|____|_|_________|___|____|____|_|
*/
I2C_StatusTypeDef I2C_ReadOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t* Data)
{
I2C_Start(); //Master发送起始信号
I2C_Send_Byte(DevAddr); //Master发送从设备地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT; //等待ACK超时错误
#ifdef FM24CL64
I2C_Send_Byte(DataAddr >> 8); //发送高8位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#else
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#endif
I2C_Start(); //Master发送起始信号
I2C_Send_Byte(DevAddr+1); //Master发送从设备读地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
*Data = I2C_Read_Byte(0); //读数据,NACK
I2C_Stop(); //发送停止信号
return I2C_SUCCESS;
}
/**
* @brief 向设备指定地址连续写入数据(Burst写模式)
* @param DevAddr : I2C从设备地址
* @param DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
* 对于Burst模式,DataAddr一般是设备的FIFO,缓存,或存储设备的数据地址
* @param *pData : 写入的数据首地址
* @param Num : 连续写入的数据个数
* @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
* @note
* 1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
* 2 - 时序:
* _____________________________________________________________________
* | | | | | | | | | | | | | | |
* Master:|S|DevAddr+W| |DataAddr| |S|DevAddr+R| | |ACK|...| |NACK|P|
* |_|_________|___|________|___|_|_________|___|____|___|___|____|____|_|
* _____________________________________________________________________
* | | | | | | | | | | | | | | |
* Slave: | | |ACK| |ACK| | |ACK|Data| |...|Data| | |
* |_|_________|___|________|___|_|_________|___|____|___|___|____|____|_|
*/
I2C_StatusTypeDef I2C_ReadBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num)
{
uint32_t i = 0;
I2C_Start(); //Master发送起始信号
I2C_Send_Byte(DevAddr); //Master发送从设备地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#ifdef FM24CL64
I2C_Send_Byte(DataAddr >> 8); //发送高8位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#else
I2C_Send_Byte(DataAddr); //发送低八位数据地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
#endif
I2C_Start(); //Master发送起始信号
I2C_Send_Byte(DevAddr+1); //Master发送从设备读地址
if(I2C_Wait_ACK()) return I2C_TIMEOUT;//等待ACK超时错误
for(i = 0; i < (Num-1); i++)
{
*(pData+i) = I2C_Read_Byte(1); //读数据,ACK
}
*(pData+i) = I2C_Read_Byte(0); //读数据,NACK
I2C_Stop(); //发送停止信号
return I2C_SUCCESS;
}
/**
* @brief 设置数据的某一位
* @param DevAddr : I2C从设备地址
* @param DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
* @param Bitx : 第几位
* @param BitSet: 需要设置的值
* @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
* @note
*/
I2C_StatusTypeDef I2C_WriteBit(uint8_t DevAddr, uint8_t DataAddr, uint8_t Bitx, uint8_t BitSet)
{
I2C_StatusTypeDef status = I2C_ERROR;
uint8_t tempdata = 0;
status = I2C_ReadOneByte(DevAddr, DataAddr, &tempdata); //获取原有数据
if(status != I2C_SUCCESS) return status; //I2C错误,则返回
tempdata &= ~(1<<Bitx); //将要设定的位清零
tempdata |= (BitSet<<Bitx); //设置指定的bit
status = I2C_WriteOneByte(DevAddr, DataAddr, tempdata); //写入数据
return status; //返回状态
}
4.调用函数
I2C_StatusTypeDef eeStatus=I2C_ERROR;
uint8_t wrEE[256]={0x01};
uint8_t rdEE[256]={0x00};
uint8_t wrEE2[256]={0x01};
uint8_t rdEE2[256]={0x00};
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
BSP_I2C_Init();
HAL_Delay(10);
memset(wrEE,0xFF,256);
memset(rdEE,0x00,256);
for(int i=0;i<256;i++)
{
eeStatus=I2C_WriteOneByte(0xA0,i,wrEE[i]);
}
eeStatus=I2C_ERROR;
HAL_Delay(10);
for(int i=0;i<256;i++)
{
eeStatus=I2C_ReadOneByte(0xA0,0,&rdEE[i]);
}
memset(wrEE2,0xFF,256);
memset(rdEE2,0x00,256);
for(int i=0;i<256;i++)
{
eeStatus=I2C_WriteOneByte(0xA2,i,wrEE2[i]);
}
eeStatus=I2C_ERROR;
HAL_Delay(10);
for(int i=0;i<256;i++)
{
eeStatus=I2C_ReadOneByte(0xA2,0,&rdEE2[i]);
}
while(1)
{}
}