论坛大神
  
- 积分
- 2643
- 金钱
- 2643
- 注册时间
- 2014-2-13
- 在线时间
- 518 小时
|
闲来无事,想起之前没调通的硬件IIC,看了下野火的教程,干脆移植过来,不敢独享  ,送上代码硬件平台:战舰STM32 V2.0
软件平台:keil5
[mw_shl_code=c,true]#include "bsp_i2c_ee.h"
/**
* @brief I2C1 I/O配置
* @param 无
* @retval 无
*/
static void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 开启 I2C 的时钟 */
I2C_APBxClock_FUN (I2C_CLK, ENABLE);
/* 开启 I2C GPIO 端口时钟 */
I2C_GPIO_APBxClock_FUN ( I2C_GPIO_CLK, ENABLE );
/* 引脚设置*/
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 复用开漏输出 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(I2C_SCL_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 复用开漏输出 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(I2C_SDA_PORT, &GPIO_InitStructure);
}
/**
* @brief I2C 工作模式配置
* @param 无
* @retval 无
*/
static void I2C_Mode_Config(void)
{
I2C_InitTypeDef I2C_InitStructure;
/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
/* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 =I2Cx_OWN_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
/* I2C的寻址模式 */
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
/* 通信速率 */
I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
/* I2C1 初始化 */
I2C_Init(I2C1, &I2C_InitStructure);
/* 使能 I2C1 */
I2C_Cmd(I2Cx, ENABLE);
}
/**
* @brief I2C 外设(EEPROM)初始化
* @param 无
* @retval 无
*/
void I2C_EE_Init(void)
{
I2C_GPIO_Config();
I2C_Mode_Config();
}
/**
* @brief 写一个字节到I2C EEPROM中
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @retval 无
*/
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
/* Send STRAT condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2Cx, WriteAddr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send the byte to be written */
I2C_SendData(I2Cx, *pBuffer);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
}
/**
* @brief Wait for EEPROM Standby state
* @param 无
* @retval 无
*/
void I2C_EE_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
/* 发送起始信号 */
I2C_GenerateSTART(I2C1, ENABLE);
/* Read I2C1 SR1 register */
SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
/* 清除 AF 位 */
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
/* 发送停止信号 */
I2C_GenerateSTOP(I2C1, ENABLE);
}
/**
* @brief 在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数
* 不能超过EEPROM页的大小,AT24C02每页有8个字节
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
/* 等待总线空闲 */
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
/* 发送起始信号 */
I2C_GenerateSTART(I2Cx, ENABLE);
/* 检测 EV5 事件并清除标志 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
/* 发送 EEPROM 设备地址+写方向 */
I2C_Send7bitAddress(I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* 检测 EV6 事件并清除标志 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* 发送要写入的 EEPROM 内部地址(即 EEPROM 内部存储器的地址) */
I2C_SendData(I2Cx, WriteAddr);
/* 检测 EV8 事件并清除标志 */
while(! I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* 循环发送 NumByteToWrite 个数据 */
while (NumByteToWrite--)
{
/* 发送缓冲区中的数据 */
I2C_SendData(I2Cx, *pBuffer);
/* 指向缓冲区中的下一个数据 */
pBuffer++;
/* 检测 EV8 事件并清除标志 */
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
/* 发送停止信号 */
I2C_GenerateSTOP(I2Cx, ENABLE);
}
/**
* @brief 将缓冲区中的数据写到I2C EEPROM中
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
void I2C_EE_BufferWrite(u8 *pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
/* mod 运算求余,若 writeAddr 是 I2C_PageSize 整数倍,
运算结果 Addr 值为 0 */
Addr = WriteAddr % I2C_PageSize;
/* 差 count 个数据值,刚好可以对齐到页地址 */
count = I2C_PageSize - Addr;
/* 计算出要写多少整数页 */
NumOfPage = NumByteToWrite / I2C_PageSize;
/* mod 运算求余,计算出剩余不满一页的字节数 */
NumOfSingle = NumByteToWrite % I2C_PageSize;
// Addr=0,则 WriteAddr 刚好按页对齐 aligned
// 这样就很简单了,直接写就可以,写完整页后
// 把剩下的不满一页的写完即可
if (Addr == 0)
{
/* If NumByteToWrite < I2C_PageSize */
if (NumOfPage == 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
while (NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if (NumOfSingle != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
// 如果 WriteAddr 不是按 I2C_PageSize 对齐
// 那就算出对齐到页地址还需要多少个数据,然后
// 先把这几个数据写完,剩下开始的地址就已经对齐
// 到页地址了,代码重复上面的即可
else
{
/* If NumByteToWrite < I2C_PageSize */
if (NumOfPage == 0)
{
/*若 NumOfSingle>count,当前面写不完,要写到下一页*/
if (NumOfSingle > count)
{
// temp 的数据要写到写一页
temp = NumOfSingle - count;
I2C_EE_PageWrite(pBuffer, WriteAddr, count);
I2C_EE_WaitEepromStandbyState();
WriteAddr += count;
pBuffer += count;
I2C_EE_PageWrite(pBuffer, WriteAddr, temp);
I2C_EE_WaitEepromStandbyState();
}
else
{
/*若 count 比 NumOfSingle 大*/
I2C_EE_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
I2C_EE_WaitEepromStandbyState();
}
}
/* If NumByteToWrite > I2C_PageSize */
else
{
/* 地址不对齐多出的 count 分开处理,不加入这个运算 */
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
/* 先把 WriteAddr 所在页的剩余字节写了 */
if (count != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, count);
I2C_EE_WaitEepromStandbyState();
WriteAddr += count;
pBuffer += count;
}
/* 把整数页都写了 */
while (NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
/* 若有多余的不满一页的数据,把它写完 */
if (NumOfSingle != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
}
/**
* @brief 从EEPROM里面读取一块数据
* @param
* @arg pBuffer:存放从EEPROM读取的数据的缓冲区指针
* @arg WriteAddr:接收数据的EEPROM的地址
* @arg NumByteToWrite:要从EEPROM读取的字节数
* @retval 无
*/
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
/* 等待总线空闲 */
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
/* 发送起始信号 */
I2C_GenerateSTART(I2Cx, ENABLE);
/* 检测 EV5 事件并清除标志*/
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
/* 发送 EEPROM 设备地址+写方向 */
I2C_Send7bitAddress(I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* 检测 EV6 事件并清除标志 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/*通过重新设置 PE 位清除 EV6 事件 */
I2C_Cmd(I2Cx, ENABLE);
/* 发送要读取的 EEPROM 内部地址(即 EEPROM 内部存储器的地址) */
I2C_SendData(I2Cx, ReadAddr);
/* 检测 EV8 事件并清除标志 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* 产生第二次 I2C 起始信号 */
I2C_GenerateSTART(I2Cx, ENABLE);
/* 检测 EV5 事件并清除标志 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
/* 发送 EEPROM 设备地址 + 读方向*/
I2C_Send7bitAddress(I2Cx, EEPROM_ADDRESS, I2C_Direction_Receiver);
/* 检测 EV6 事件并清除标志 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/* 读取 NumByteToRead 个数据 */
while(NumByteToRead)
{
/*若 NumByteToRead=1,表示已经接收到最后一个数据了,
发送非应答信号,结束传输*/
if (NumByteToRead == 1)
{
/* 发送非应答信号 */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* 发送停止信号 */
I2C_GenerateSTOP(I2Cx, ENABLE);
}
/* 检测 EV7 事件并清除标志 */
if (I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
/*通过 I2C,从设备中读取一个字节的数据 */
*pBuffer = I2C_ReceiveData(I2Cx);
/* 存储数据的指针指向下一个地址 */
pBuffer++;
/* 接收数据计数自减 */
NumByteToRead--;
}
}
/* 使能应答,方便下一次 I2C 传输 */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
}
[/mw_shl_code]
工程文件:
|
|