STM32:ハードウェアIIC、EEPROMページ書き込みと連続メモリデータ読み取りを実現しますが、データエラーが発生します(上)

EEPROMページの書き込みと連続メモリデータの読み取りを実現するために、「AT24C01」データマニュアルに従ってコードを実装できます。:図からプログラムを作成する方法の詳細な説明については、私の別の記事「[STM32-I2C学習の概要] STM32:ハードウェア-IICの詳細な説明、ファームウェアライブラリプログラミング、手を携えて教えてください」を参照してください。 IIC実装する方法
データ書き込みと読み出しのアイコン後マニュアル『AT24C01』のデータを、私は直接コードをアップロードし、そして最後に、エラーの原因を分析しました。そして、
以下に示すように解決策を示します
。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.1バイトの読み取り
ここに画像の説明を挿入

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);

ここに画像の説明を挿入

したがって、ここから、データが正しいかどうかにかかわらず、データの書き込みと読み取りを継続的に行うことは、書き込むメモリユニットアドレスの場所に依存し、特定のパターンがあることがわかります。したがって、処理する必要があり、フラッシュ操作と同様に、クロスページ操作は2つのセクターを連続して書き込むことはできませんエラーが発生します。別のページにデータを継続的に書き込むことにより、データの正確性を保証できます。したがって、データアドレスの位置合わせ操作を追加する必要があります以下はWildfireの公式プログラムであり、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」のデータマニュアルには、一度に書き込むことができるデータの長さを制限する文があると思います。これは、クロスページ操作の問題を回避するためです。
ここに画像の説明を挿入

次の記事で住所調整の原則を説明します

おすすめ

転載: blog.csdn.net/qq_45689790/article/details/113729858