STM32硬件I2C测试EEPROM读写功能
STM32硬件I2C测试读写EEPROM
一、测试环境
使用正点原子STM32F103,精英V2开发板上 I2C1(B6,B7)测试eeprom 读写数据,网上都说stm32硬件I2C有问题,不提倡使用硬件I2C。
二、程序测试
1.主程序实现
main.c代码如下:
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "i2c.h"
uint8_t I2C_EE_Test(void);
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
I2C1_Init();
printf("stm32 i2c master test:\r\n");
I2C_EE_Test();
while(1)
{
LED0=!LED0;//提示系统正在运行
delay_ms(300);
}
}
uint8_t I2C_EE_Test(void)
{
uint8_t ReadData[256]={0};
uint8_t WriteDdta[256]={0};
uint16_t i;
//初始化写入数组
for(i = 0; i < 256; i++)
{
WriteDdta[i]=i;
}
//向EEPROM从地址为0开始写入256个字节的数据
I2C_EE_BufferWrite(WriteDdta, 0, 256);
//等待EEPROM写入数据完成
EEPROM_WaitForWriteEnd();
//向EEPROM从地址为0开始读出256个字节的数据
EEPROM_Read(ReadData, 0, 256);
for (i=0; i<256; i++)
{
if(ReadData[i] != WriteDdta[i])
{
EEPROM_ERROR("0x%02X ", ReadData[i]);
EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");
return 0;
}
printf("0x%02X ", ReadData[i]);
if(i%16 == 15)
printf("\n\r");
}
EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");
return 1;
}
void Delay(__IO uint32_t nCount) //简单的延时函数
{
for(; nCount != 0; nCount--);
}
2.I2C1驱动
i2c.c代码如下:
#include "i2c.h"
//设置等待时间
static __IO uint32_t I2CTimeout = I2CT_LONG_TIMEOUT;
//等待超时,打印错误信息
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStuctrue;
I2C_InitTypeDef I2C_InitStuctrue;
//开启GPIO外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//开启IIC外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
//SCL引脚-复用开漏输出
GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStuctrue.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStuctrue.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStuctrue);
//SDA引脚-复用开漏输出
GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStuctrue.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStuctrue.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStuctrue);
//IIC结构体成员配置
I2C_InitStuctrue.I2C_Ack = I2C_Ack_Enable;
I2C_InitStuctrue.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStuctrue.I2C_ClockSpeed = EEPROM_I2C_BAUDRATE;
I2C_InitStuctrue.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStuctrue.I2C_Mode = I2C_Mode_I2C;
I2C_InitStuctrue.I2C_OwnAddress1 = STM32_I2C_OWN_ADDR;
I2C_Init(I2C1, &I2C_InitStuctrue);
I2C_Cmd(I2C1, ENABLE);
}
//向EEPROM写入一个字节
void EEPROM_Byte_Write(uint8_t addr,uint8_t data)
{
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
//发送设备写地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
//检测EV6事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
//发送要操作设备内部的地址
I2C_SendData(EEPROM_I2C,addr);
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR);
I2C_SendData(EEPROM_I2C,data);
//检测EV8_2事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
//发送停止信号
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
//向EEPROM写入多个字节
uint32_t EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
//判断IIC总线是否忙碌
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
//重新赋值
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送设备写地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
//检测EV6事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送要操作设备内部的地址
I2C_SendData(EEPROM_I2C,addr);
//检测EV8事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
}
while(Num_ByteToWrite)
{
I2C_SendData(EEPROM_I2C,*data);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
}
Num_ByteToWrite--;
data++;
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//检测EV8_2事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
}
//发送停止信号
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
return 1;
}
//向EEPROM读取多个字节
uint32_t EEPROM_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
//判断IIC总线是否忙碌
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送设备写地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
//检测EV6事件等待从机应答
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送要操作设备内部存储器的地址
I2C_SendData(EEPROM_I2C,addr);
//检测EV8事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送设备读地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Receiver);
//检测EV6事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
while(Num_ByteToRead--)
{
//是否是最后一个字节,若是则发送非应答信号
if( Num_ByteToRead==0)
{
//发送非应答信号
I2C_AcknowledgeConfig(EEPROM_I2C,DISABLE);
//发送停止信号
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//检测EV7事件
while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
*data=I2C_ReceiveData(EEPROM_I2C);
data++;
}
//重新开启应答信号
I2C_AcknowledgeConfig(EEPROM_I2C,ENABLE);
return 1;
}
void I2C_EE_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
//I2C_PageSize=8
Addr = WriteAddr % I2C_PageSize;
count = I2C_PageSize - Addr;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
/* 写入数据的地址对齐,对齐数为8 */
if(Addr == 0)
{
/* 如果写入的数据个数小于8 */
if(NumOfPage == 0)
{
EEPROM_Page_Write(WriteAddr, pBuffer, NumOfSingle);
EEPROM_WaitForWriteEnd();
}
/* 如果写入的数据个数大于8 */
else
{
//按页写入
while(NumOfPage--)
{
EEPROM_Page_Write(WriteAddr, pBuffer, I2C_PageSize);
EEPROM_WaitForWriteEnd();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
//不足一页(8个)单独写入
if(NumOfSingle!=0)
{
EEPROM_Page_Write(WriteAddr, pBuffer, NumOfSingle);
EEPROM_WaitForWriteEnd();
}
}
}
/*写的数据的地址不对齐*/
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
if(count != 0)
{
EEPROM_Page_Write(WriteAddr, pBuffer, count);
EEPROM_WaitForWriteEnd();
WriteAddr += count;
pBuffer += count;
}
while(NumOfPage--)
{
EEPROM_Page_Write(WriteAddr, pBuffer, I2C_PageSize);
EEPROM_WaitForWriteEnd();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
EEPROM_Page_Write(WriteAddr, pBuffer, NumOfSingle);
EEPROM_WaitForWriteEnd();
}
}
}
uint32_t EEPROM_WaitForWriteEnd(void)
{
I2CTimeout = I2CT_FLAG_TIMEOUT;
do
{
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
//检测EV5事件
while( I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_SB )==RESET)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送设备写地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
}while( (I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_ADDR )==RESET) && (I2CTimeout--) );
//发送停止信号
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
return 1;
}
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
/* Block communication and all processes */
EEPROM_ERROR("I2C 等待超时!errorCode = %d",errorCode);
return 0;
}
i2c.h代码如下:
#ifndef __I2C_H
#define __I2C_H
#include <stdio.h>
#include "sys.h"
//IIC1
#define EEPROM_I2C I2C1
#define EEPROM_I2C_BAUDRATE 400000
//STM32自身地址1 与从机设备地址不相同即可(7位地址)
#define STM32_I2C_OWN_ADDR 0x6f
//EEPROM设备地址
#define EEPROM_I2C_Address 0XA0
#define I2C_PageSize 8
//等待次数
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
/*信息输出*/
#define EEPROM_DEBUG_ON 0
#define EEPROM_INFO(fmt,arg...) printf("<<-EEPROM-INFO->> "fmt"\n",##arg)
#define EEPROM_ERROR(fmt,arg...) printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
#define EEPROM_DEBUG(fmt,arg...) do{\
if(EEPROM_DEBUG_ON)\
printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
void I2C1_Init(void);
void EEPROM_Byte_Write(uint8_t addr,uint8_t data);
uint32_t EEPROM_WaitForWriteEnd(void);
uint32_t EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite);
uint32_t EEPROM_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead);
void I2C_EE_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite);
#endif
3.使用逻分抓I2C数据
4.测试结果
三、gitee路径
https://gitee.com/sugang2022/stm32f103zet6.git
作者:sugang1990