AT32F421专题---I2C连接AT24C02 EEPROM

【啰嗦2句】

     本来想I2C有什么难的,连接I2C是51单片机入门就必学的了,没什么可讲。  

     但是,万一有人想直接抄作业,总得有地方复制粘贴吧?总得给他借鉴一些吧,----直到他知道抄作业是没用的

【硬件简介】

    AT24C02是一款自带2Kbit(256Byte)的相当成熟的EEPROM芯片,我最早接触的是ATMAL公司的,当时仍未入行,后来学单片机又是从AT89C52学起,又是这家公司的,于是对这个品牌有深刻印象,他们家的产品品质优秀,值得尊敬。该芯片的通信采用I2C总线,操作容易,资料遍地。国产同型号芯片也非常多,目前用过的没遇到坑,估计闭眼买吧。

   而我们的主角AT32F421C8T7主控,操作I2C跟STM32大同小异,本文更着重小异部分的讲解。

   需要注意:AT24C02虽然电压宽域,但是速度跟电压成正比,也就是说电压越低,速度要慢些,电压越高,速度要快些。手册有提到。并且有的型号支持最低1.8V(达不到最高速度),有的最低可能要2.7V。例如:1.8V有的只能100Kb/s,2.7V-5V才能到400Kb/s,调试中遇到问题或许是这个原因。

 【原理图】

【演示内容】

     AT32F421C8T7单片机通过I2C2跟AT2402相连,通过UART1跟电脑串口连接,上位机发的内容按顺序存储在EEPROM,单片机存储后按位读出并返回给上位机。结束符为"\n"。

【主要源码】

     本源码参考自雅特力官方源码:

AT32F421_Firmware_Library_V2.1.2\project\at_start_f421\examples\i2c\eeprom

官方例程的代码没有修改的就不展示,比如: i2c_application.c、i2c_application.h

文件名:eeprom.c

#include "includes.h"

//这个必须定义,大概是用于区分哪个I2C对象
i2c_handle_type hi2cx;

void error_handler(uint32_t error_code);
void i2c_lowlevel_init(i2c_handle_type* hi2c);

/**
  * @brief  error handler program
  * @param  i2c_status
  * @retval none
  */
void error_handler(uint32_t error_code)
{
  //while(1)
  //{
    //at32_led_toggle(LED2);
    //delay_ms(500);
  //}
}
/**
  * @brief  initializes peripherals used by the i2c.
  * @param  none
  * @retval none
  */
void i2c_lowlevel_init(i2c_handle_type* hi2c)
{
  gpio_init_type gpio_initstructure;

  if(hi2c->i2cx == I2Cx_PORT)
  {
    /* i2c periph clock enable */
    crm_periph_clock_enable(I2Cx_CLK, TRUE);
    crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
    crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);

    /* gpio configuration */
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
    gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;

    /* configure i2c pins: scl */
    gpio_initstructure.gpio_pins = I2Cx_SCL_PIN;
    gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_initstructure);
    gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN_SOURCE, I2Cx_SCL_PIN_MUX_NUM);

    /* configure i2c pins: sda */
    gpio_initstructure.gpio_pins = I2Cx_SDA_PIN;
    gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_initstructure);
    gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN_SOURCE, I2Cx_SDA_PIN_MUX_NUM);

    /* configure and enable i2c dma channel interrupt */
    nvic_irq_enable(I2Cx_DMA_TX_IRQn, 0, 0);
    nvic_irq_enable(I2Cx_DMA_RX_IRQn, 0, 0);

    /* configure and enable i2c interrupt */
    nvic_irq_enable(I2Cx_EVT_IRQn, 0, 0);
    nvic_irq_enable(I2Cx_ERR_IRQn, 0, 0);

    /* i2c dma tx and rx channels configuration */
    /* enable the dma clock */
    crm_periph_clock_enable(I2Cx_DMA_CLK, TRUE);

    /* i2c dma channel configuration */
    dma_reset(hi2c->dma_tx_channel);
    dma_reset(hi2c->dma_rx_channel);

    hi2c->dma_tx_channel = I2Cx_DMA_TX_CHANNEL;
    hi2c->dma_rx_channel = I2Cx_DMA_RX_CHANNEL;

    dma_default_para_init(&hi2c->dma_init_struct);
    hi2c->dma_init_struct.peripheral_inc_enable    = FALSE;
    hi2c->dma_init_struct.memory_inc_enable        = TRUE;
    hi2c->dma_init_struct.peripheral_data_width    = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    hi2c->dma_init_struct.memory_data_width        = DMA_MEMORY_DATA_WIDTH_BYTE;
    hi2c->dma_init_struct.loop_mode_enable         = FALSE;
    hi2c->dma_init_struct.priority                 = DMA_PRIORITY_LOW;
    hi2c->dma_init_struct.direction                = DMA_DIR_MEMORY_TO_PERIPHERAL;

    dma_init(hi2c->dma_tx_channel, &hi2c->dma_init_struct);
    dma_init(hi2c->dma_rx_channel, &hi2c->dma_init_struct);

    i2c_init(hi2c->i2cx, I2C_FSMODE_DUTY_2_1, I2Cx_SPEED);

    i2c_own_address1_set(hi2c->i2cx, I2C_ADDRESS_MODE_7BIT, I2Cx_ADDRESS);
  }
}

/****************************************************************
*函数:AT24CXX_Init
*功能:初始化EEPROM
*参数:无
*          
****************************************************************/
void AT24CXX_Init(void)
{
   hi2cx.i2cx = I2Cx_PORT;

  i2c_config(&hi2cx);
}

/****************************************************************
*函数:AT24CXX_Write
*功能:写入EEPROM
*参数:buf--写入的内容,iAddress--地址,length--写入的内容长度
*          
****************************************************************/
void AT24CXX_Write(uint16_t iAddress, uint8_t *buf, uint32_t length)           
{
	  u8 i=0;  
	  i2c_status_type i2c_status;
		if(iAddress >  EE_TYPE)
		{
			return;
		}
		if(iAddress + length >EE_TYPE)
		{
			 length=EE_TYPE-iAddress;
		}
    for(i=0;i<length;i+=8)
		{	
			  if(length-i>8)
			  {				
				    if((i2c_status = i2c_memory_write(&hi2cx, I2C_MEM_ADDR_WIDIH_8, I2Cx_ADDRESS, iAddress+i, &buf[i], 8, I2C_TIMEOUT)) != I2C_OK)
					  {
						    error_handler(i2c_status);
					  }
				}
			  else
				{
					  if((i2c_status = i2c_memory_write(&hi2cx, I2C_MEM_ADDR_WIDIH_8, I2Cx_ADDRESS, iAddress+i, &buf[i], length-i, I2C_TIMEOUT)) != I2C_OK)
					  {
						    error_handler(i2c_status);
					  }
				}
				delay_ms(5);
		}
}

/****************************************************************
*函数:AT24CXX_Read
*功能:读出EEPROM
*参数:buf--读出的内容,iAddress--地址,length--读出的内容长度
*          
****************************************************************/
void AT24CXX_Read(uint16_t iAddress, uint8_t *buf, int32_t length)
{                    
	u8 i=0;  
	i2c_status_type i2c_status;
	  for(i=0;i<length;i+=8)
		{	
			  if(length-i>8)
			  {				
				    if((i2c_status = i2c_memory_read(&hi2cx, I2C_MEM_ADDR_WIDIH_8, I2Cx_ADDRESS, iAddress+i, &buf[i], 8, I2C_TIMEOUT)) != I2C_OK)
					  {
						    error_handler(i2c_status);
					  }
				}
			  else
				{
					  if((i2c_status = i2c_memory_read(&hi2cx, I2C_MEM_ADDR_WIDIH_8, I2Cx_ADDRESS, iAddress+i, &buf[i], length-i, I2C_TIMEOUT)) != I2C_OK)
					  {
						    error_handler(i2c_status);
					  }
				}
				delay_ms(5);
		}
	  
}





文件名:eeprom.h 

#ifndef __EEPROM_H
#define __EEPROM_H	 

#define AT24C01		127
#define AT24C02		255					  //定义芯片容量
#define AT24C04		511
#define AT24C08		1023
#define AT24C16		2047
#define AT24C32		4095
#define AT24C64	    8191
#define AT24C128	16383
#define AT24C256	32767

#define EE_TYPE AT24C02					 //更换芯片记得改这个型号


#define I2C_TIMEOUT                      0xFFFFFFFF

#define I2Cx_SPEED                       100000
#define I2Cx_ADDRESS                     0xA0

#define I2Cx_PORT                        I2C2
#define I2Cx_CLK                         CRM_I2C2_PERIPH_CLOCK

#define I2Cx_SCL_PIN                     GPIO_PINS_6
#define I2Cx_SCL_PIN_SOURCE              GPIO_PINS_SOURCE6
#define I2Cx_SCL_PIN_MUX_NUM             GPIO_MUX_0
#define I2Cx_SCL_GPIO_PORT               GPIOF
#define I2Cx_SCL_GPIO_CLK                CRM_GPIOF_PERIPH_CLOCK

#define I2Cx_SDA_PIN                     GPIO_PINS_7
#define I2Cx_SDA_PIN_SOURCE              GPIO_PINS_SOURCE7
#define I2Cx_SDA_PIN_MUX_NUM             GPIO_MUX_0
#define I2Cx_SDA_GPIO_PORT               GPIOF
#define I2Cx_SDA_GPIO_CLK                CRM_GPIOF_PERIPH_CLOCK

#define I2Cx_DMA_CLK                     CRM_DMA1_PERIPH_CLOCK
#define I2Cx_DMA_TX_CHANNEL              DMA1_CHANNEL4
#define I2Cx_DMA_TX_IRQn                 DMA1_Channel5_4_IRQn

#define I2Cx_DMA_RX_CHANNEL              DMA1_CHANNEL5
#define I2Cx_DMA_RX_IRQn                 DMA1_Channel5_4_IRQn

#define I2Cx_EVT_IRQn                    I2C2_EVT_IRQn
#define I2Cx_ERR_IRQn                    I2C2_ERR_IRQn


void AT24CXX_Init(void);
void AT24CXX_Write(uint16_t iAddress, uint8_t *buf, uint32_t length);
void AT24CXX_Read(uint16_t iAddress, uint8_t *buf, int32_t length);

		 				    
#endif


文件名:main.c

/******************** (C) COPYRIGHT 2024 移动中的鸭子 ********************
* File Name          : main.c
* Author             : CZY Application Team
* Version            : V1.0.0
* Date               : 2024-08-04
* Description        : 演示入口及串口处理
*************************************************************************/

#include "includes.h"


/*******************************************************************************
* 函数名  : main
* 描述    : 入口函数,你懂的
* 说明    : 
*******************************************************************************/
int main(void)
{
  u8 temp[100];
  Set_System();  //这里是其他时钟等常用初始化
	USART1_Init();  //初始化串口1,用于跟上位机通信
  AT24CXX_Init(); //初始化AT24C02
	
  while(1)
  {
		
		if(PC_ReceiveFlag==1)  //说明触发中断并且接收到"\r\n"
		{
			//接收完成后写入EEPROM,从地址0开始
			AT24CXX_Write(0,PC_RevBuffer,PC_RevLength);
			//写完又读出到temp缓存,从地址0开始
			AT24CXX_Read(0,temp,PC_RevLength);//如果写入失败,这里读出的应该全00或全FF,
			
			//直接回发给上位机
			USART1_SendByte(temp,PC_RevLength);
			PC_ClrRevBuffer();
			PC_ReceiveFlag=0;  //清空接收标记
		}
  }
}

文件名:pc.c

/******************** (C) COPYRIGHT 2024 移动中的鸭子 ********************
* File Name          : main.c
* Author             : CZY Application Team
* Version            : V1.0.0
* Date               : 2024-08-04
* Description        : 演示串口1接收
*************************************************************************/
#include "includes.h"


unsigned char PC_RevBuffer[PC_MAX];	//端口接收数据缓冲区 
unsigned char PC_RevLength=0;      //已接收的长度
unsigned char PC_ReceiveFlag=0;    //接收完整包标记
/*************************************************************************
*函 数 名: PC_ReceiveHandle
*功能描述:	处理电脑串口接收到的数据
*输    入:	data:接收的字节
*输    出:
***************************************************************************/
void PC_ReceiveHandle(u8 dat)
{
	PC_RevBuffer[PC_RevLength]=dat;
	PC_RevLength++;
	if(dat=='\n')  //当收到回车换行符后,标记为接收完成,main函数会处理。
	{
		PC_ReceiveFlag=1;
	}
}
/*************************************************************************
*函 数 名: PC_ClrRevBuffer
*功能描述:	清空接收缓存
*输    入:	
*输    出:
***************************************************************************/
void PC_ClrRevBuffer(void)
{
   memset(PC_RevBuffer,0x00,PC_MAX);
   PC_RevLength=0;
}


文件名:pc.h

#ifndef __PC_H
#define __PC_H	 


#define PC_MAX   100

extern unsigned char PC_ReceiveFlag;
extern unsigned char PC_RevBuffer[PC_MAX];	//端口接收数据缓冲区 
extern unsigned char PC_RevLength;

void PC_ReceiveHandle(unsigned char dat);
void PC_ClrRevBuffer(void);


#endif

文件名:at32f421_int.c(大部分是官方源码,最后部分4个I2Cx开头是I2C重点代码)

/**
  **************************************************************************
  * @file     at32f421_int.c
  * @brief    main interrupt service routines.
  **************************************************************************
  *                       Copyright notice & Disclaimer
  *
  * The software Board Support Package (BSP) that is made available to
  * download from Artery official website is the copyrighted work of Artery.
  * Artery authorizes customers to use, copy, and distribute the BSP
  * software and its related documentation for the purpose of design and
  * development in conjunction with Artery microcontrollers. Use of the
  * software is governed by this copyright notice and the following disclaimer.
  *
  * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  *
  **************************************************************************
  */

/* includes ------------------------------------------------------------------*/
#include "at32f421_int.h"
#include "i2c_application.h"

extern i2c_handle_type hi2cx;
#define I2Cx_DMA_RX_TX_IRQHandler        DMA1_Channel5_4_IRQHandler
#define I2Cx_EVT_IRQHandler              I2C2_EVT_IRQHandler
#define I2Cx_ERR_IRQHandler              I2C2_ERR_IRQHandler

irqCallback_ts *irqCallback_extiLine1;
irqCallback_ts *firstIrqCallback_extiLine1;
/** @addtogroup AT32F421_periph_examples
  * @{
  */

/** @addtogroup 421_SPI_fullduplex_polling
  * @{
  */

/**
  * @brief  this function handles nmi exception.
  * @param  none
  * @retval none
  */
void NMI_Handler(void)
{
}

/**
  * @brief  this function handles hard fault exception.
  * @param  none
  * @retval none
  */
void HardFault_Handler(void)
{
  /* go to infinite loop when hard fault exception occurs */
  while(1)
  {
  }
}

/**
  * @brief  this function handles memory manage exception.
  * @param  none
  * @retval none
  */
void MemManage_Handler(void)
{
  /* go to infinite loop when memory manage exception occurs */
  while(1)
  {
  }
}

/**
  * @brief  this function handles bus fault exception.
  * @param  none
  * @retval none
  */
void BusFault_Handler(void)
{
  /* go to infinite loop when bus fault exception occurs */
  while(1)
  {
  }
}

/**
  * @brief  this function handles usage fault exception.
  * @param  none
  * @retval none
  */
void UsageFault_Handler(void)
{
  /* go to infinite loop when usage fault exception occurs */
  while(1)
  {
  }
}

/**
  * @brief  this function handles svcall exception.
  * @param  none
  * @retval none
  */
void SVC_Handler(void)
{
}

/**
  * @brief  this function handles debug monitor exception.
  * @param  none
  * @retval none
  */
void DebugMon_Handler(void)
{
}

/**
  * @brief  this function handles pendsv_handler exception.
  * @param  none
  * @retval none
  */
void PendSV_Handler(void)
{
}

/**
  * @brief  this function handles systick handler.
  * @param  none
  * @retval none
  */
void SysTick_Handler(void)
{
}


/**
  * @brief  this function handles dma interrupt request.
  * @param  none
  * @retval none
  */
void I2Cx_DMA_RX_TX_IRQHandler(void)
{
  i2c_dma_rx_irq_handler(&hi2cx);
  i2c_dma_tx_irq_handler(&hi2cx);
}
/**
  * @brief  this function handles i2c event interrupt request.
  * @param  none
  * @retval none
  */
void I2Cx_EVT_IRQHandler(void)
{
  i2c_evt_irq_handler(&hi2cx);
}

/**
  * @brief  this function handles i2c error interrupt request.
  * @param  none
  * @retval none
  */
void I2Cx_ERR_IRQHandler(void)
{
  i2c_err_irq_handler(&hi2cx);
}



文件名:usart.c

#include "includes.h"

/****************************************************************
*函 数 名:USART1_Init
*功能说明:串口1配置	  
*参    数:
*输    出:               
**********************************************************/
void USART1_Init(void)
{
		gpio_init_type gpio_init_struct;

  /* enable the usart1 and gpio clock */
  crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);


  gpio_default_para_init(&gpio_init_struct);

  /* configure the usart1 tx/rx pin */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_9 | GPIO_PINS_10;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOA, &gpio_init_struct);

  /* config usart1 iomux */
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_1);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_1);


  /* config usart1 nvic interrupt */
  nvic_irq_enable(USART1_IRQn, 0, 0);


  /* configure usart1 param */
  usart_init(USART1, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
  usart_transmitter_enable(USART1, TRUE);
  usart_receiver_enable(USART1, TRUE);


  /* enable usart1 and usart1 interrupt */
  usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE);
  usart_enable(USART1, TRUE);

	
}

/**
  * @brief  this function handles usart1 handler.
  * @param  none
  * @retval none
  */
void USART1_IRQHandler(void)
{
  if(USART1->ctrl1_bit.rdbfien != RESET)
  {
    if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)
    {
      //读出的字节转给PC.c专门处理
      PC_ReceiveHandle(usart_data_receive(USART1));
    }
  }
  
  if(USART1->ctrl1_bit.tdbeien != RESET)
  {
    if(usart_flag_get(USART1, USART_TDBE_FLAG) != RESET)
    {
      
    }
  }
}

void USART1_Send(unsigned char dat)
{
	while(usart_flag_get(USART1, USART_TDBE_FLAG) == RESET);
	usart_data_transmit(USART1, dat);
	
}

void USART1_SendByte(unsigned char  *p,unsigned int length)
{
	while (length--)
    {
        USART1_Send(*p++);
    }
}







文件名:usart.h

#ifndef __UART_H
#define __UART_H	 


void USART1_Init(void);
void USART1_SendByte(unsigned char *p,unsigned int length);


#endif

【实测效果】 

以上是本文全部内容,讲解不是很详细,可能需要网友具备部分开发经验,才好理解。

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值