EEPROM 페이지 쓰기 및 연속 메모리 데이터 읽기를 실현하기 위해 "AT24C01"데이터 매뉴얼에 따라 코드를 구현할 수 있습니다. : 다이어그램에서 프로그램을 작성하는 방법에 대한 자세한 설명은 내 다른 기사를 볼 수 있습니다. " [STM32-I2C 학습 요약] STM32 : 하드웨어 -IIC 세부 설명, 펌웨어 라이브러리 프로그래밍, 손에서 직접 가르치기 IIC 구현 방법 "
"AT24C01 "Data Manual 데이터 쓰기 및 읽기 아이콘을 마친 후 직접 코드를 업로드하고 오류의 원인을 분석했습니다.
다음과 같이 솔루션 측정 값 을 제공하십시오 .
1. 단일 바이트 쓰기
void I2C_ByteWrite(uint8_t *pBuffer, uint8_t WriteAddr)
{
while(I2C_GetFlagStatus(DEBUG_I2Cx_Port, I2C_FLAG_BUSY));
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Transmitter);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
I2C_SendData(DEBUG_I2Cx_Port, WriteAddr);
//check EV8_2
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_SendData(DEBUG_I2Cx_Port, *pBuffer);
//check EV8_2
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_GenerateSTOP(DEBUG_I2Cx_Port,ENABLE);
}
2. 페이지 쓰기
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
while(I2C_GetFlagStatus(DEBUG_I2Cx_Port, I2C_FLAG_BUSY));
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Transmitter);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
I2C_SendData(DEBUG_I2Cx_Port, WriteAddr);
//check EV8_2
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
/* 参考上图,页写入与单个写入的差别,仅仅是停止信号的发送 */
/* 加入判断即可 */
while(NumByteToWrite)
{
I2C_SendData(DEBUG_I2Cx_Port, *pBuffer);
//check EV8_2
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
pBuffer++;
NumByteToWrite--;
}
I2C_GenerateSTOP(DEBUG_I2Cx_Port,ENABLE);
}
3. 단일 바이트 읽기
void I2C_ByteRead(uint8_t *pBuffer, uint8_t ReadAddr)
{
//这个函数我还没用过,只是参考上图写了出来,方便大家理解
while(I2C_GetFlagStatus(DEBUG_I2Cx_Port, I2C_FLAG_BUSY));
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Transmitter);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
I2C_AcknowledgeConfig(DEBUG_I2Cx_Port,DISABLE);
I2C_GenerateSTOP(DEBUG_I2Cx_Port,ENABLE);
//check EV7
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR);
*pBuffer = I2C_ReceiveData(DEBUG_I2Cx_Port);
I2C_AcknowledgeConfig(DEBUG_I2Cx_Port,DISABLE);
}
4. 단일 데이터 읽기
void I2C_ByteRead(uint8_t *pBuffer, uint8_t ReadAddr)
{
while(I2C_GetFlagStatus(DEBUG_I2Cx_Port, I2C_FLAG_BUSY));
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Transmitter);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
I2C_SendData(DEBUG_I2Cx_Port, ReadAddr);
//check EV8_2
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Receiver);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);
I2C_AcknowledgeConfig(DEBUG_I2Cx_Port,DISABLE);
I2C_GenerateSTOP(DEBUG_I2Cx_Port,ENABLE);
//check EV7
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR);
*pBuffer = I2C_ReceiveData(DEBUG_I2Cx_Port);
I2C_AcknowledgeConfig(DEBUG_I2Cx_Port,DISABLE);
}
5. 지속적으로 데이터 읽기
void I2C_BufferRead(uint8_t* pBuffer, u8 ReadAddr, uint16_t NumByteToRead)
{
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Transmitter);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
I2C_SendData(DEBUG_I2Cx_Port, ReadAddr);
//check EV8_2
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_GenerateSTART(DEBUG_I2Cx_Port,ENABLE);
//check EV5
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_Send7bitAddress(DEBUG_I2Cx_Port,DEBUG_EEPROM_Addr,I2C_Direction_Receiver);
//check EV6
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);
while(NumByteToRead)
{
if(NumByteToRead == 1)
{
I2C_AcknowledgeConfig(DEBUG_I2Cx_Port,DISABLE);
I2C_GenerateSTOP(DEBUG_I2Cx_Port,ENABLE);
}
//check EV7
while(I2C_CheckEvent(DEBUG_I2Cx_Port,I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR);
*pBuffer = I2C_ReceiveData(DEBUG_I2Cx_Port);
pBuffer++;
NumByteToRead--;
}
I2C_AcknowledgeConfig(DEBUG_I2Cx_Port,DISABLE);
}
자, 주요 기능이 구현되었습니다. 다른 처리 기능없이 "AT24C01"데이터 매뉴얼에 따라 이러한 기능이 어떻게 뒤집히는 지 보여 드리겠습니다! 테스트 코드 :
#include "stm32f10x.h"
#include "bsp_i2c.h"
#include "bsp_usart.h"
uint8_t I2C_Buf_Write[256];
uint8_t I2C_Buf_Read[256];
uint16_t i=0;
void delay(uint32_t count)
{
while(count--);
}
int main(void)
{
USART_Config();
I2C_Config();
for(i=0;i<256;i++)
{
I2C_Buf_Write[i] = i;
}
printf("\r\n 这是一个I2C外设(AT24C02)读写测试例程 \r\n");
I2C_EE_PageWrite(&I2C_Buf_Write[2],0x18,8);
delay(0xffff); //加一个延时 确保已经写入EEPROM STM32工作速度可是远大
// 400k 而且我函数里没有处理,这不是关键
I2C_BufferRead(&I2C_Buf_Read[2],0x18,8);
for(i=0; i<8; i++)
{
printf("0x%x \t", I2C_Buf_Read[i+2]);
}
while(1);
}
직렬 포트 도우미 열기
물론 나는 왜 뭔가 잘못되었는지 설명하기 위해 여기에 있습니다. 먼저 테스트 기능을 살펴 봅니다. EEPROM의 단위 주소를 원합니다. 0x18부터 시작하는 8 개의 연속 된 주소가 기록됩니다.이 초기 주소를 오른쪽으로 이동하면 어떻게됩니까?
I2C_EE_PageWrite(&I2C_Buf_Write[2],0x19,8);//仅平移一个
delay(0xffff);
I2C_BufferRead(&I2C_Buf_Read[2],0x19,8);
물론 2 개의 주소를 이동하면 2 개의 잘못된 주소가있을 수 있습니다. 10 개 주소를 이동하면 어떻게됩니까?
I2C_EE_PageWrite(&I2C_Buf_Write[2],0x28,8);//平移10个地址
delay(0xffff);
I2C_BufferRead(&I2C_Buf_Read[2],0x28,8);
따라서 여기에서 데이터가 정확하든 그렇지 않든 연속적으로 쓰고 읽는 것은 사용자가 쓰는 메모리 유닛 주소의 위치에 따라 다르며 일정한 패턴을 가지고 있음을 알 수 있습니다. 따라서, 처리해야하며, 페이지 간 동작 , 플래시 동작과 유사하게, 두 개의 연속 섹터를 쓸 수 없다 . 오류가 발생합니다. 별도의 페이지에 지속적으로 데이터를 작성하여 데이터의 정확성을 보장 할 수 있습니다. 따라서 데이터 주소 정렬 작업 을 추가해야합니다 . 다음은 운영을위한 데이터 주소가 포함 된 Wildfire의 공식 프로그램입니다. 방금 배웠습니다. 프로그램에는 여전히 버그가 있습니다. 처리 한 후에는 프로그램을 첨부합니다.
/**
* @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) {
/* 如果 NumByteToWrite < I2C_PageSize */
if (NumOfPage == 0) {
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
/* 如果 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 {
/* 如果 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();
}
}
/* 如果 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 后,地址就对齐到页了*/
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();
}
}
}
}
"AT24C01"데이터 매뉴얼에는 한 번에 쓸 수있는 데이터의 길이를 제한하는 문장이 있다고 생각하는데, 이는 크로스 페이지 작업 문제를 피하기위한 것입니다.
다음 기사에서 주소 정렬의 원리를 설명하겠습니다.