STM32F429--I2C通信(读写EEPROM,串口返回测试数据)

一、I2C介绍

I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息,SDA数据线SCL时钟信号线
  
 主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。

  • 如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;
  • 如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。

二、I2C的通信状态

  1. 总线空闲—SDA和SCL都为高电平

  2. 数据的有效位规定

    SCL为高电平期间,数据线SDA上必须保持稳定
    只有SCL为低电平期间,数据线SDA才允许变化
    STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第1张图片

  3. I2C的起始和终止信号

    SCL线为高电平期间,SDA线由高电平—>低电平,表示起始信号
    SCL线为高电平期间,SDA线由低电平—>高电平,表示终止信号

STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第2张图片

3.I2C字节的传送与应答

 每一个字节是8位,先传最高位(MSB),每传一个字节后面必须跟随一个应答位(即一帧有9位)。

STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第3张图片

三、须知

下面代码用到了串口返回读取的数据信息,此处用到了串口一
STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第4张图片
用到的库函数
STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第5张图片
STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第6张图片
主发送器通讯过程
STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第7张图片
主接收器
STM32F429--I2C通信(读写EEPROM,串口返回测试数据)_第8张图片

四、程序部分

bsp_i2c_eeprom.h

#ifndef __BSP_I2C_EEPROM_H
#define	__BSP_I2C_EEPROM_H

#include "stm32f4xx.h"

#define I2C_OWN_ADDR 0x77 /*主机的八位地址,只要不和从机重复*/

#define I2C_SPEED 400000  /*快速模式最高400khz*/

#define EEPROM_ADDR (0x50<<1)   //0xA0,


//引脚定义,移植时修改此处即可,野火的I2C口为PB6和PB7
/*******************************************************/
#define EEPROM_I2C                              I2C1
#define EEPROM_I2C_CLK                         RCC_APB1Periph_I2C1

#define EEPROM_SCL_GPIO_PORT                    GPIOB
#define EEPROM_SCL_GPIO_CLK                     RCC_AHB1Periph_GPIOB
#define EEPROM_SCL_PIN                          GPIO_Pin_6
#define EEPROM_SCL_AF                           GPIO_AF_I2C1
#define EEPROM_SCL_SOURCE                       GPIO_PinSource6

#define EEPROM_SDA_GPIO_PORT                GPIOB
#define EEPROM_SDA_GPIO_CLK                 RCC_AHB1Periph_GPIOB
#define EEPROM_SDA_PIN                       GPIO_Pin_7
#define EEPROM_SDA_AF                        GPIO_AF_I2C1
#define EEPROM_SDA_SOURCE                   GPIO_PinSource7

/************************************************************/
void EEPROM_GPIO_Config(void);
void EEPROM_I2C_ModeConfig(void);
void EEPROM_Byte_Write(uint8_t* pData,uint8_t addr);
uint8_t EEPROM_Byte_Read(uint8_t addr);

#endif /* __BSP_I2C_EEPROM_H */

bsp_i2c_eeprom.c

#include "./i2c/bsp_i2c_eeprom.h"

void Wait_for_EEPROM(void);
//1.初始化GPIO
void EEPROM_GPIO_Config(void)
{

  GPIO_InitTypeDef GPIO_InitStructure;
		
  RCC_AHB1PeriphClockCmd(EEPROM_SCL_GPIO_CLK|EEPROM_SDA_GPIO_CLK,ENABLE);
    
 /* 连接SCL*/
  GPIO_PinAFConfig(EEPROM_SCL_GPIO_PORT,EEPROM_SCL_SOURCE,EEPROM_SCL_AF);
  /*  连接 SDA*/
  GPIO_PinAFConfig(EEPROM_SDA_GPIO_PORT,EEPROM_SDA_SOURCE,EEPROM_SDA_AF);
  
  
  /* GPIO初始化 */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  
  /* 配置SCL引脚为复用功能  */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = EEPROM_SCL_PIN  ;  
  GPIO_Init(EEPROM_SCL_GPIO_PORT, &GPIO_InitStructure);

  /* 配置SDA引脚为复用功能 */
  GPIO_InitStructure.GPIO_Pin = EEPROM_SDA_PIN;
  GPIO_Init(EEPROM_SDA_GPIO_PORT, &GPIO_InitStructure);
  

}

//2.初始化I2C模式
void EEPROM_I2C_ModeConfig(void)
{
  I2C_InitTypeDef I2C_InitStruct;
    
  /* 使能 I2C时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
  
  I2C_InitStruct.I2C_Ack =  I2C_Ack_Enable;
  I2C_InitStruct.I2C_AcknowledgedAddress =  I2C_AcknowledgedAddress_7bit;
  I2C_InitStruct.I2C_ClockSpeed =  I2C_SPEED; 
  I2C_InitStruct.I2C_DutyCycle =  I2C_DutyCycle_2 ;
  I2C_InitStruct.I2C_Mode =  I2C_Mode_I2C ;
  I2C_InitStruct.I2C_OwnAddress1 = I2C_OWN_ADDR;
  
  I2C_Init(EEPROM_I2C,&I2C_InitStruct);
  
  I2C_Cmd(EEPROM_I2C,ENABLE);

}


//3.byte write 函数
void EEPROM_Byte_Write(uint8_t* pData,uint8_t addr)
{
  I2C_GenerateSTART(EEPROM_I2C,ENABLE);
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS )
  {
     //....
  }
    
  I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
  
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS )
  {
  
  }
  
  
  I2C_SendData(EEPROM_I2C,addr);
  
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS )
  {
  
  }
  
  
  I2C_SendData(EEPROM_I2C,*pData);
  
  
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS )
  {
  
  }
  
  
  I2C_GenerateSTOP(EEPROM_I2C,ENABLE);

}


//4.random read
uint8_t EEPROM_Byte_Read(uint8_t addr)
{
  uint8_t readTemp;

  Wait_for_EEPROM();
  
  
  I2C_GenerateSTART(EEPROM_I2C,ENABLE);
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS )
  {
     //....
  }
    
  I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
  
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS )
  {
  
  }
  
  
  I2C_SendData(EEPROM_I2C,addr);
  
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS )
  {
  
  }
  
  
  I2C_GenerateSTART(EEPROM_I2C,ENABLE);
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS )
  {
     //....
  }

  
  I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Receiver);
  
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS )
  {
  
  }
  
  I2C_AcknowledgeConfig(EEPROM_I2C,DISABLE);
  
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS )
  {
  
  }
  
  readTemp = I2C_ReceiveData(EEPROM_I2C);
   
  
  I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
  
  return readTemp;

}

//5.等待EEPROM内部写完毕
void Wait_for_EEPROM(void)
{
  do
  {
    I2C_GenerateSTART(EEPROM_I2C,ENABLE);
  
//    while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS )
//    {
//       //....
//    }
      
    I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);  
  
  }while(I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_ADDR) == RESET);
  
  //等待ADDR = 1 才执行下面的语句
  
  I2C_ClearFlag(EEPROM_I2C,I2C_FLAG_AF);
    
  I2C_GenerateSTOP(EEPROM_I2C,ENABLE);

  while(I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_BUSY) == SET);
  
  //总线空闲,执行下面的语句

}  

bsp_debug_usart.h

#ifndef __DEBUG_USART_H
#define	__DEBUG_USART_H

#include "stm32f4xx.h"
#include 


//引脚定义
/*******************************************************/
#define DEBUG_USART                             USART1
#define DEBUG_USART_CLK                         RCC_APB2Periph_USART1
#define DEBUG_USART_BAUDRATE                    115200  //串口波特率

#define DEBUG_USART_RX_GPIO_PORT                GPIOA
#define DEBUG_USART_RX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART_RX_PIN                      GPIO_Pin_10
#define DEBUG_USART_RX_AF                       GPIO_AF_USART1
#define DEBUG_USART_RX_SOURCE                   GPIO_PinSource10

#define DEBUG_USART_TX_GPIO_PORT                GPIOA
#define DEBUG_USART_TX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART_TX_PIN                      GPIO_Pin_9
#define DEBUG_USART_TX_AF                       GPIO_AF_USART1
#define DEBUG_USART_TX_SOURCE                   GPIO_PinSource9

#define DEBUG_USART_IRQHandler                  USART1_IRQHandler
#define DEBUG_USART_IRQ                 				USART1_IRQn
/************************************************************/

void Debug_USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);

void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);

#endif /* __USART1_H */

bsp_debug_usart.c

#include "./usart/bsp_debug_usart.h"


 /**
  * @brief  配置嵌套向量中断控制器NVIC
  * @param  无
  * @retval 无
  */
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


 /**
  * @brief  DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1 ,中断接收模式
  * @param  无
  * @retval 无
  */
void Debug_USART_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
		
  RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);

  /* 使能 USART 时钟 */
  RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
  
  /* GPIO初始化 */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  
  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN  ;  
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  
 /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);

  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
  
  /* 配置串DEBUG_USART 模式 */
  /* 波特率设置:DEBUG_USART_BAUDRATE */
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  /* 字长(数据位+校验位):8 */
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  /* 停止位:1个停止位 */
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  /* 校验位选择:不使用校验 */
  USART_InitStructure.USART_Parity = USART_Parity_No;
  /* 硬件流控制:不使用硬件流 */
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  /* USART模式控制:同时使能接收和发送 */
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* 完成USART初始化配置 */
  USART_Init(DEBUG_USART, &USART_InitStructure); 
	
  /* 嵌套向量中断控制器NVIC配置 */
	NVIC_Configuration();
  
	/* 使能串口接收中断 */
	USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
	
  /* 使能串口 */
  USART_Cmd(DEBUG_USART, ENABLE);
}

/*****************  发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}

/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l;
	
	/* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF;
	
	/* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	/* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USART, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USART);
}
/*串口中断服务函数*/
void DEBUG_USART_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData( DEBUG_USART );
    USART_SendData(DEBUG_USART,ucTemp);    
	}	 
}	

main.c

#include "stm32f4xx.h"
#include "./usart/bsp_debug_usart.h"
#include "./i2c/bsp_i2c_eeprom.h"

int main(void)
{	
  
	uint8_t test_addr = 0x02;
	uint8_t test_writeData = 0x27;
	uint8_t test_readData =0;
   
    /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
    Debug_USART_Config();
	/* 发送一个字符串 */
	Usart_SendString( DEBUG_USART,"这是一个EEPROM测试实验\n");
	printf("这是一个EEPROM测试实验\n");
  
  
  printf("\r\n初始化I2C\r\n");
  
  EEPROM_GPIO_Config();
  EEPROM_I2C_ModeConfig();
  
  printf("\r\nI2C初始化完毕\r\n");  
  
  EEPROM_Byte_Write(&test_writeData,test_addr);

  test_readData = EEPROM_Byte_Read(test_addr);  

  printf("test_readData =0x%x",test_readData);
	
  while(1)
	{	
		
	}	
}

你可能感兴趣的:(单片机,stm32,嵌入式,串口通信,单片机)