硬件I2C-三种方法,阻塞,中断和DMA的EEPROM测试

HAL库硬件I2C 阻塞,中断,DMA三种方法读写EEPROM

在这里插入图片描述在这里插入图片描述在这里插入图片描述

GPIO是开漏模式外部必须要上拉电阻

在这里插入图片描述
IIC_hard.c如下:

//iic_hard.c
#include "main.h"
#include "iic_hard.h"
#include "i2c.h"
#include "rs485.h"
#include "usart.h"
#include "stdio.h"

#define _DBUG_PRINTF_
#ifdef _DBUG_PRINTF_
#define DBUG_PRINTF(format, ...)	printf("LINE-Error : %d "format"\r\n",__LINE__,##__VA_ARGS__)
#define DBUG_ERROR(format, ...)	printf(format"\r\n",##__VA_ARGS__)
#else
#define DBUG_PRINTF(format, ...)	
#define DBUG_ERROR(format, ...)	
#endif


/*
	写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。
	对于24xx02,page size = 8
	对于24xx04,page size = 16
	简单的处理方法为:按字节写操作模式,每写1个字节,都发送地址
	为了提高连续写的效率: 本函数采用page wirte操作。

I2C_MEMADD_SIZE_8BIT
I2C_MEMADD_SIZE_16BIT
24C16以下容量的地址为8位,24C32以上容量的地址为16位,
在调用读写函数时需要注意,选择I2C_MEMADD_SIZE_8BIT或者I2C_MEMADD_SIZE_16BIT
*/



#define	hIIC			hi2c1
#define	hEEPROM_IIC		I2C1

#define EE_DEV_WR	I2C_7BIT_ADD_WRITE(EE_DEV_ADDR)		/* 写控制bit */
#define EE_DEV_RD	I2C_7BIT_ADD_READ(EE_DEV_ADDR)		/* 读控制bit */
// #define EE_Delay()	HAL_Delay(2)//阻塞
#define EE_Delay()	HAL_Delay(5)//中断和DMA

//------------------------------------------------------------------------------------


// #define IIC_MEM_WRITE(W_Addr,W_buf,W_size) 	HAL_I2C_Mem_Write(&hIIC,EE_DEV_WR,W_Addr,I2C_MEMADD_SIZE_8BIT,W_buf, W_size,0xffff);
// #define IIC_MEM_WRITE(W_Addr,W_buf,W_size) 	HAL_I2C_Mem_Write_IT(&hIIC,EE_DEV_WR,W_Addr,I2C_MEMADD_SIZE_8BIT,W_buf, W_size);
#define IIC_MEM_WRITE(W_Addr,W_buf,W_size) 	HAL_I2C_Mem_Write_DMA(&hIIC,EE_DEV_WR,W_Addr,I2C_MEMADD_SIZE_8BIT,W_buf, W_size);

// #define IIC_MEM_READ(R_Addr,R_buf,R_size)	HAL_I2C_Mem_Read(&hIIC,EE_DEV_RD,R_Addr,I2C_MEMADD_SIZE_8BIT,R_buf, R_size,0xffff)//阻塞
// #define IIC_MEM_READ(R_Addr,R_buf,R_size)	HAL_I2C_Mem_Read_IT(&hIIC,EE_DEV_RD,R_Addr,I2C_MEMADD_SIZE_8BIT,R_buf, R_size); //中断
#define IIC_MEM_READ(R_Addr,R_buf,R_size)	HAL_I2C_Mem_Read_DMA(&hIIC,EE_DEV_RD,R_Addr,I2C_MEMADD_SIZE_8BIT,R_buf, R_size); //中断DMA

//------------------------------------------------------------------------------------
void I2C_DMA_IS_BUSY(I2C_HandleTypeDef *hi2c);


uint8_t E2ROM_CheckOk(void)
{
	if (HAL_I2C_Master_Transmit(&hIIC, EE_DEV_WR,0,1,0xFFFF ) == HAL_OK)
		return 1;
	else
		return 0;

}

uint8_t EE_WaitStandState(HAL_StatusTypeDef IIC_status)
{
	if (IIC_status != HAL_OK)
	{
		uint32_t IIC_error = HAL_I2C_GetError(&hIIC);
		if(IIC_error){
			DBUG_ERROR("IIC_error : 0X%0x\r\n",IIC_error);
			return 0;
		}
	}
		
return 1;
}

/*
*********************************************************************************************************
*	函 数 名: E2ROM_ReadBytes
*	功能说明: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率
*	形    参:  usAddress : 起始地址
*			 usSize : 数据长度,单位为字节
*			 pReadBuf : 存放读到的数据的缓冲区指针
*	返 回 值: 0 表示失败,1表示成功
*********************************************************************************************************
*/
uint8_t E2ROM_ReadBytes(uint8_t *pReadBuf, uint16_t usAddress, uint16_t usSize)
{
	uint16_t i;
	int32_t iTime1, iTime2;
	u8 IIC_status=0; 

	IIC_status = HAL_I2C_IsDeviceReady(&hIIC, EE_DEV_ADDR| I2C_RD, 10, 0xFFFF);
	if (IIC_status != HAL_OK)
	{
		printf("HAL_I2C_IsDeviceReady: \r\n");
		goto cmd_fail;
	}
	

	IIC_status = IIC_MEM_READ(usAddress,pReadBuf,usSize); 
	if (IIC_status != HAL_OK)
	{
		printf("HAL_I2C_Mem_Read_DMA: \r\n");
		goto cmd_fail;
	}

return 1;

cmd_fail:
	printf("读eeprom出错!\r\n");
	switch( IIC_status )
	{
		case HAL_OK:break;
		case HAL_ERROR:printf("HAL_ERROR \r\n");return 0;
		case HAL_BUSY:printf("HAL_BUSY  \r\n");return 0;
		case HAL_TIMEOUT:printf("HAL_TIMEOUT\r\n");return 0;
		default:return 0;
	}

return 0;

}
/*
*********************************************************************************************************
*	函 数 名: E2ROM_WriteBytes
*	功能说明: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率
*	形    参:  usAddress : 起始地址
*			 usSize : 数据长度,单位为字节
*			 pWriteBuf : 存放读到的数据的缓冲区指针
*	返 回 值: 0 表示失败,1表示成功
*********************************************************************************************************
*/
uint8_t E2ROM_WriteBytes(uint8_t *pWriteBuf, uint16_t usAddress, uint16_t usSize)
{
	uint16_t i,m;
	uint16_t usAddr;

	u8 IIC_status=0; 
	IIC_status = HAL_I2C_IsDeviceReady(&hIIC, EE_DEV_ADDR, 10, 0xFFFF);
	if (!EE_WaitStandState(IIC_status))
	{
		DBUG_PRINTF();
		goto cmd_fail;
	}
//-----------------------------------------------------------------------------------

	uint8_t num_page=0,num_single=0,addr =0,count=0,temp=0;

	addr 	=usAddress%EE_PAGE_SIZE;
	count	=EE_PAGE_SIZE-addr;

	num_page	=usSize/EE_PAGE_SIZE;
	num_single	=usSize%EE_PAGE_SIZE;

	usAddr = usAddress;

	// 当发送的地址是页开始
	if(!addr)
	{
		if(!num_page)//小于1页
		{
			IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, num_single);
			if (!EE_WaitStandState(IIC_status))
			{
				DBUG_PRINTF();
				goto cmd_fail;
			}
		}
		else//大于1页
		{
			while(num_page--)
			{
				
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, EE_PAGE_SIZE);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}
				usAddr +=EE_PAGE_SIZE;
				pWriteBuf +=EE_PAGE_SIZE;
				EE_Delay();
				I2C_DMA_IS_BUSY(&hIIC);
			}

			if(num_single !=0)
			{
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, num_single);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}

			}
		}
	}
	else//地址没有对齐到页
	{
		if(!num_page)//写入的小于1页
		{
			if(num_single>count)//数量大于1页的剩余数量
			{
				//先把1页写满
				temp=num_single-count;
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, count);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}
				usAddr +=count;
				pWriteBuf +=count;
				EE_Delay();
				
				//剩余的翻页写
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, temp);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}
			}
			else
			{
				//写入的数量小于,写满1页的剩余数量
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, num_single);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}

			}
		}
		else
		{
			usSize -= count;
			num_page	=usSize/EE_PAGE_SIZE;
			num_single	=usSize%EE_PAGE_SIZE;

			//写入的大于1页
			// 先把开始地址所在的页写满
			if(count)
			{
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, count);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}
				usAddr +=count;
				pWriteBuf +=count;
				EE_Delay();
			}

			//剩下的和大于1页的相同
			while(num_page--)
			{
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, EE_PAGE_SIZE);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}
				usAddr +=EE_PAGE_SIZE;
				pWriteBuf +=EE_PAGE_SIZE;
				EE_Delay();

			}

			if(num_single )
			{
				IIC_status =IIC_MEM_WRITE(usAddr,pWriteBuf, num_single);
				if (!EE_WaitStandState(IIC_status))
				{
					DBUG_PRINTF();
					goto cmd_fail;
				}

			}
		}
		

	}


/* 命令执行成功 */
return 1;

cmd_fail: /* 命令执行失败*/

	printf("写 eeprom 出错!\r\n");
	switch( IIC_status )
	{
		case HAL_OK:break;
		case HAL_ERROR:printf("HAL_ERROR \r\n");return 0;
		case HAL_BUSY:printf("HAL_BUSY  \r\n");return 0;
		case HAL_TIMEOUT:printf("HAL_TIMEOUT\r\n");return 0;
		default:return 0;
	}

return 0;

}

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hIIC.Instance == hEEPROM_IIC)
	{
		
	}
	
	
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hIIC.Instance == hEEPROM_IIC)
	{
	}

}
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hIIC.Instance == hEEPROM_IIC)
	{
		uint8_t DMA_state=HAL_DMA_GetState(hi2c->hdmatx);
		if(HAL_DMA_STATE_READY != DMA_state)
		{
			hi2c->hdmatx->State =HAL_DMA_STATE_READY;
		}
	}
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hIIC.Instance == hEEPROM_IIC)
	{
		uint8_t DMA_state=HAL_DMA_GetState(hi2c->hdmarx);
		if(HAL_DMA_STATE_READY != DMA_state)
		{
			hi2c->hdmarx->State =HAL_DMA_STATE_READY;
		}
		
	}
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
	if(hIIC.Instance == hEEPROM_IIC)
	{
	}
}
void I2C_DMA_IS_BUSY(I2C_HandleTypeDef *hi2c)
{

	uint8_t DMA_state=HAL_DMA_GetState(hi2c->hdmatx);
	if(HAL_DMA_STATE_READY != DMA_state)
	{
		hi2c->hdmatx->State =HAL_DMA_STATE_READY;
	}
	
}


//---------------------------------------------------------------------------------------------------------------
//测试程序
static uint8_t buf[EE_SIZE];

/*
*********************************************************************************************************
*	函 数 名: E2ROM_ReadTest
*	功能说明: 读串行EEPROM全部数据,并打印出来
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
static void E2ROM_ReadTest(void)
{
	uint16_t i;
	int32_t iTime1, iTime2;
	u8 IIC_status=0; 


	IIC_status = HAL_I2C_IsDeviceReady(&hIIC, EE_DEV_ADDR| I2C_RD, 10, 0xFFFF);
	if (IIC_status != HAL_OK)
	{
		printf("HAL_I2C_IsDeviceReady: \r\n");
		goto cmd_fail;
	}
	

	/* 读EEPROM, 起始地址 = 0, 数据长度为 256 */
	IIC_status = IIC_MEM_READ(0,buf,EE_SIZE); 
	if (IIC_status != HAL_OK)
	{
		printf("HAL_I2C_Mem_Read_DMA: \r\n");
		goto cmd_fail;
	}
	else
	{
		printf("读eeprom成功,数据如下:\r\n");
	}

	/* 打印数据 */
	for (i = 0; i < EE_SIZE; i++)
	{
		printf(" %02X", buf[i]);

		if ((i & 31) == 31)
		{
			printf("\r\n");	/* 每行显示16字节数据 */
		}
		else if ((i & 31) == 15)
		{
			printf(" - ");
		}
		EE_Delay();
	}

return;

cmd_fail:

	printf("读eeprom出错!\r\n");
	switch( IIC_status )
	{
		case HAL_OK:break;
		case HAL_ERROR:printf("HAL_ERROR \r\n");return;
		case HAL_BUSY:printf("HAL_BUSY  \r\n");return;
		case HAL_TIMEOUT:printf("HAL_TIMEOUT\r\n");return;
		default:return;
	}

return;

}

/*
*********************************************************************************************************
*	函 数 名: E2ROM_WriteTest
*	功能说明: 写串行EEPROM全部数据
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
static void E2ROM_WriteTest(void)
{
	uint16_t i;
	int32_t iTime1, iTime2;

	/* 填充测试缓冲区 */
	for (i = 0; i < EE_SIZE; i++)
	{
		buf[i] = 0;
	}

	/* 写EEPROM, 起始地址 = 0,数据长度为 EE_SIZE */
	if (E2ROM_WriteBytes(buf, 0, EE_SIZE) == 0)
	{
		printf("写eeprom出错!\r\n");
		return;
	}
	else
	{
		printf("写eeprom成功!\r\n");
	}

}

/*
*********************************************************************************************************
*	函 数 名: ee_ReadTest
*	功能说明: 读串行EEPROM全部数据,并打印出来
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
static void E2ROM_Erase(void)
{
	uint16_t i;

	/* 填充缓冲区 */
	for (i = 0; i < EE_SIZE; i++)
	{
		buf[i] = 0xFF;
	}

	/* 写EEPROM, 起始地址 = 0,数据长度为 EE_SIZE */
	if (E2ROM_WriteBytes(buf, 0, EE_SIZE) == 0)
	{
		printf("擦除eeprom出错!\r\n");
		return;
	}
	else
	{
		printf("擦除eeprom成功!\r\n");
	}
}
static void E2ROM_DispMenu(void)
{
	printf("\r\n------------------------------------------------\r\n");
	printf("请选择操作命令:\r\n");
	printf("1 - 读EEPROM (%d 字节)\r\n", EE_SIZE);
	printf("2 - 写EEPROM (%d 字节,0x00-0xFF)\r\n", EE_SIZE);
	printf("3 - 擦除EEPROM\r\n");
	printf("4 - 从头开始写入\r\n");
	printf("5 - 从指定位置写数据\r\n");
	printf("6 - 显示命令提示\r\n");
}
void DemoEEPROM(void)
{
	uint8_t cmd;

	if (E2ROM_CheckOk() == 0)
	{
		/* 没有检测到EEPROM */
		printf("没有检测到串行EEPROM!\r\n");

		while (1);	/* 停机 */
	}

	printf("已经检测到串行EEPROM : \r\n");
	printf("型号: %s, 容量 = %dx2 字节, 页面大小 = %d\r\n", EE_MODEL_NAME, EE_SIZE, EE_PAGE_SIZE);


	E2ROM_DispMenu();		/* 打印命令提示 */
	while(1)
	{
		
		//cmd = getchar();	/* 从串口读入一个字符 (阻塞方式) */
		// if (comGetChar(COM1, &cmd))	/* 从串口读入一个字符(非阻塞方式) */
		RS485_RX();
		if (HAL_OK == HAL_UART_Receive(&huart2,&cmd,1,0xFFFF))	/* 从串口读入一个字符(非阻塞方式) */
		{
			switch (cmd)
			{
				case '1':
					printf("\r\n【1 - 读 EEPROM 测试】\r\n");
					E2ROM_ReadTest();		/* 读EEPROM数据,并打印出来数据内容 */
					break;

				case '2':
					printf("\r\n【2 - 写 EEPROM 测试】\r\n");
					E2ROM_WriteTest();		/* 写EEPROM数据*/
					break;

				case '3':
					printf("\r\n【3 - 擦除 EEPROM】\r\n");
					E2ROM_Erase();			/* 写入全0xFF */
					break;
				
				case '4':
				{
					int num;
					printf("\r\n 请输出写入数量: <100\r\n ");
					scanf("%d",&num);
					if(!num)break;

					printf("\r\n");
					printf("请输入 %d 个数据:",num);
					getchar();
					u8 dat[100];
					for (size_t i = 0; i <num ; i++)
					{
						scanf("%d",(int*)&dat[i]);
					}
					// scanf("%*[^\n]%*c");

					E2ROM_WriteBytes(dat,0,num);
					printf("\r\n 写入完成");
					printf("输入的是 \r\n");
					for (size_t i = 0; i <num ; i++)
					{
						printf("%0X ",dat[i]);
					}
					printf("\n");
					getchar();

				}break;
				case '5':
				{
					int num;
					printf("\r\n 请输写入数量:");
					scanf("%d",&num);
					if(!num)break;
					
					getchar();
					int addr;
					printf("\r\n 请输写入开始地址:");
					scanf("%d",&addr);
					

					getchar();
					printf("\r 请输入 %d 个数据:",num);
					u8 dat[258];
					for (size_t i = 0; i <num ; i++)
					{
						scanf("%d",(int*)&dat[i]);
					}
					E2ROM_WriteBytes(dat,addr,num);
					printf("\r\n 写入完成:");
					getchar();
				}break;
				default:
					E2ROM_DispMenu();	/* 无效命令,重新打印命令提示 */
					break;

			}
		}
	}

}


/*****************************************************************/

IIC_hard.h如下:

//iic_hard.h
#ifndef IIC_HARD_H
#define IIC_HARD_H
#include <stdlib.h>

extern void DemoEEPROM(void);

#endif


回调函数里面的判断和I2C_DMA_IS_BUSY()的作用是,解决用阻塞和DMA时出现BUSY问题
在这里插入图片描述

在main里面调用DemoEEPROM()
源码见源码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值