stm32cubeMX+FreeRTOS(2)——软件IIC和硬件IIC读写AT24C2

一、硬件IIC读取AT24C2

1.硬件IIC配置

在这里插入图片描述

i2c.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    i2c.c
  * @brief   This file provides code for the configuration
  *          of the I2C instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

I2C_HandleTypeDef hi2c1;

/* I2C1 init function */
void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
      
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = IIC1_SCL_Pin|IIC1_SDA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{

  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */

  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();

    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(IIC1_SCL_GPIO_Port, IIC1_SCL_Pin);

    HAL_GPIO_DeInit(IIC1_SDA_GPIO_Port, IIC1_SDA_Pin);

  /* USER CODE BEGIN I2C1_MspDeInit 1 */

  /* USER CODE END I2C1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

二、软件IIC配置

1.配置SCL和SDA引脚

bsp_soft_iic.h

#ifndef _BOARD_I2C_H_
#define _BOARD_I2C_H_

/*********************************************************************
 * INCLUDES
 */
#include "main.h"


/*********************************************************************
 * DEFINITIONS

// I2C_SCL时钟
#define IIC1_SCL_GPIO_Port        GPIOB                       // GPIO端口
#define IIC1_SCL_Pin         GPIO_PIN_6                  // GPIO引脚
// I2C_SDA时钟
#define IIC1_SDA_GPIO_Port        GPIOB                       // GPIO端口
#define IIC1_SDA_Pin         GPIO_PIN_7                  // GPIO引脚
*/

/*********************************************************************
 * MACROS
 */
#define IIC_SCL_0()         HAL_GPIO_WritePin(IIC1_SCL_GPIO_Port, IIC1_SCL_Pin, GPIO_PIN_RESET) 
#define IIC_SCL_1()         HAL_GPIO_WritePin(IIC1_SCL_GPIO_Port, IIC1_SCL_Pin, GPIO_PIN_SET)
#define IIC_SDA_0()         HAL_GPIO_WritePin(IIC1_SDA_GPIO_Port, IIC1_SDA_Pin, GPIO_PIN_RESET) 
#define IIC_SDA_1()         HAL_GPIO_WritePin(IIC1_SDA_GPIO_Port, IIC1_SDA_Pin, GPIO_PIN_SET) 
#define IIC_SDA_READ()      HAL_GPIO_ReadPin(IIC1_SDA_GPIO_Port, IIC1_SDA_Pin) 

/*********************************************************************
 * API FUNCTIONS
 */
void IIC_Init(void);			 
void IIC_Start(void);
void IIC_Stop(void);
void IIC_SendByte(u8 ucByte);
u8 IIC_ReadByte(void);
u8 IIC_WaitAck(void);
void IIC_Ack(void);
void IIC_NAck(void);
u8 IIC_CheckDevice(u8 address);

#endif /* _BOARD_I2C_H_ */

bsp_soft_iic.c

/*********************************************************************
 * INCLUDES
 */
 
#include "bsp_I2C_Simu.h"

static void SDA_OUT_MODE(void);
static void SDA_IN_MODE(void);

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief I2C驱动初始化,采用模拟IO的方式实现
 @param 无
 @return 无
*/
void IIC_Init(void)
{
	
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = IIC1_SCL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(IIC1_SCL_GPIO_Port, &GPIO_InitStruct);  
  
  GPIO_InitStruct.Pin = IIC1_SDA_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(IIC1_SDA_GPIO_Port, &GPIO_InitStruct);

  IIC_Stop();             // 给一个停止信号, 复位I2C总线上的所有设备到待机模式
}

/**
 @brief CPU发起I2C总线启动信号
 @param 无
 @return 无
*/
void IIC_Start(void)
{
    SDA_OUT_MODE();         // SDA线输出模式
    
    IIC_SDA_1();            	  	  
    IIC_SCL_1();
    osDelay(1);
    IIC_SDA_0();            // 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号
    osDelay(1);    
    IIC_SCL_0();            // 钳住I2C总线,准备发送或接收数据 
}	

/**
 @brief CPU发起I2C总线停止信号
 @param 无
 @return 无
*/
void IIC_Stop(void)
{
    SDA_OUT_MODE();         // SDA线输出模式
    
    IIC_SCL_0();
    IIC_SDA_0();          
    IIC_SCL_1();
    osDelay(1);
    IIC_SDA_1();            // 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号		
    osDelay(1);
}

/**
 @brief CPU向I2C总线设备发送8bit数据
 @param ucByte -[in] 等待发送的字节
 @return 无
*/  
void IIC_SendByte(uint8_t ucByte)
{                        
    uint8_t i;  
    
    SDA_OUT_MODE();         // SDA线输出模式
    
    IIC_SCL_0();            // 拉低时钟开始数据传输
    
    for(i = 0; i < 8; i++)
    {              
        if(ucByte & 0x80) 	
        {            
            IIC_SDA_1();
        }
        else
        {
            IIC_SDA_0();
        }
		ucByte <<= 1; 	
        osDelay(1);        
        IIC_SCL_1();
        osDelay(1);
        IIC_SCL_0();
        osDelay(1);        
    }	 
} 

/**
 @brief CPU从I2C总线设备读取8bit数据
 @param 无
 @return 读到的数据
*/ 
uint8_t IIC_ReadByte(void)
{
    uint8_t i = 0;
    uint8_t value = 0;
    
    SDA_IN_MODE();          // SDA线输入模式
    
    for(i = 0; i < 8; i++)
    {
        value <<= 1;
        IIC_SCL_1();
        osDelay(1);
        if(IIC_SDA_READ())
        {
            value++;
        }            
        IIC_SCL_0(); 
        osDelay(1); 
    }					
    IIC_Ack();
    
    return value;
}

/**
 @brief CPU产生一个时钟,并读取器件的ACK应答信号
 @param 无
 @return 返回0表示正确应答,1表示无器件响应
*/
uint8_t IIC_WaitAck(void)
{
    uint8_t result = 0; 
    
    SDA_IN_MODE();          // SDA线输入模式
    
    IIC_SDA_1();            // CPU释放SDA总线
    osDelay(1); 
    IIC_SCL_1();            // CPU驱动SCL = 1, 此时器件会返回ACK应答
    osDelay(1);
    if(IIC_SDA_READ())
    {
        result = 1;
    }
    else
    {
        result = 0;
    }
    IIC_SCL_0();
    osDelay(1);

    return result;  
} 

/**
 @brief CPU产生一个ACK信号
 @param 无
 @return 无
*/
void IIC_Ack(void)
{
    SDA_OUT_MODE();         // SDA线输出模式
    
    IIC_SDA_0();            // CPU驱动SDA = 0
    osDelay(1);
    IIC_SCL_1();            // CPU产生1个时钟
    osDelay(1);
    IIC_SCL_0();
    osDelay(1);
    IIC_SDA_1();            // CPU释放SDA总线
}

/**
 @brief CPU产生1个NACK信号
 @param 无
 @return 无
*/    
void IIC_NAck(void)
{
    SDA_OUT_MODE();         // SDA线输出模式
    
    IIC_SDA_1();            // CPU驱动SDA = 1
    osDelay(1);
    IIC_SCL_1();            // CPU产生1个时钟
    osDelay(1);
    IIC_SCL_0();
    osDelay(1);
}

/**
 @brief 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
 @param address -[in] 设备的I2C总线地址+读写控制bit(0 = w, 1 = r)
 @return 0 - 表示正确, 1 - 表示未探测到
*/  
uint8_t IIC_CheckDevice(uint8_t address)
{
    uint8_t ucAck;

    IIC_Init();             // 初始化I2C
    IIC_Start();            // 发送启动信号
    IIC_SendByte(address);  // 设备的I2C总线地址+读写控制bit(0 = w, 1 = r)
    ucAck = IIC_WaitAck();	// 检测设备的ACK应答
    IIC_Stop();             // 发送停止信号

    return ucAck;
}


/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief SDA输出配置	
 @param 无
 @return 无
*/ 
static void SDA_OUT_MODE(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = IIC1_SDA_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(IIC1_SDA_GPIO_Port, &GPIO_InitStruct);

}

/**
 @brief SDA输入配置	
 @param 无
 @return 无
*/ 
static void SDA_IN_MODE(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = IIC1_SDA_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	HAL_GPIO_Init(IIC1_SDA_GPIO_Port, &GPIO_InitStruct);
	
}

/****************************************************END OF FILE****************************************************/

三、配置硬件和软件IIC AT24C02驱动文件

bsp_at24c02.h

#ifndef _BSP_24CXX_H
#define _BSP_24CXX_H
#include "main.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  
//我使用的是AT24C02
#define EE_TYPE AT24C02



#define AT24C02_ADDR_WRITE  0xA0
#define AT24C02_ADDR_READ   0xA1
#define IIC_OUTTIMES		500




void AT24CXX_soft_Init(void);
void AT24CXX_hw_ReadOneByte(u16 ReadAddr, u8 *read_data);
void AT24CXX_soft_WriteOneByte(u16 WriteAddr,u8 DataToWrite);
void AT24CXX_soft_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);
void AT24CXX_soft_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);




void AT24CXX_hw_ReadOneByte(u16 ReadAddr, u8 *read_data);					//指定地址读取一个字节
void AT24CXX_hw_WriteOneByte(u16 WriteAddr,u8 *write_data);					//指定地址写入一个字节
void AT24CXX_hw_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);				//从指定地址开始写入指定长度的数据
void AT24CXX_hw_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);   		//从指定地址开始读出指定长度的数据


u8 AT24CXX_Check(void);
void AT24CXX_soft_Init(void); 
#endif

bsp_at24c02.c

#include "bsp_24cxx.h"



//三次写入的字符串
u8 str1[]={"jeck666"};
u8 str2[]={"1234567"};
u8 str3[]={"abcdefg"};

uint8_t ReadBuffer[50];

/***************************软件IIC读写******************************/

void AT24CXX_soft_Init(void)
{
	IIC_Init();		
}

void AT24CXX_soft_ReadOneByte(u16 ReadAddr, u8 *read_data)
{	
	IIC_Start();
	IIC_SendByte(AT24C02_ADDR_WRITE);
    IIC_WaitAck();
	IIC_SendByte(ReadAddr);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(AT24C02_ADDR_READ);
    IIC_WaitAck();
	*read_data = IIC_ReadByte();
	IIC_WaitAck();
	IIC_Stop();
}

void AT24CXX_soft_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{				   	  	    																 
	IIC_Start();
	IIC_SendByte(AT24C02_ADDR_WRITE);
	IIC_WaitAck();
	IIC_SendByte(WriteAddr);
	IIC_WaitAck();
	IIC_SendByte(DataToWrite);
	IIC_WaitAck();
	IIC_Stop();
}
void AT24CXX_soft_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{

}  

void AT24CXX_soft_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{

}


/***************************硬件IIC读写******************************/

void AT24CXX_hw_ReadOneByte(u16 ReadAddr, u8 *read_data)
{				  
	HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, ReadAddr, I2C_MEMADD_SIZE_8BIT, read_data, 1, IIC_OUTTIMES); 
}

void AT24CXX_hw_WriteOneByte(u16 WriteAddr,u8 *write_data)
{ 
	HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, WriteAddr, I2C_MEMADD_SIZE_8BIT, write_data, 1, IIC_OUTTIMES);
}


void AT24CXX_hw_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
	HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, ReadAddr, I2C_MEMADD_SIZE_8BIT, pBuffer, NumToRead, IIC_OUTTIMES); 
}  

void AT24CXX_hw_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, WriteAddr, I2C_MEMADD_SIZE_8BIT, pBuffer, NumToWrite, IIC_OUTTIMES);
}

//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{
	AT24CXX_soft_Init();

    uint8_t temp;
	uint16_t ReadAddr = 127;
    uint8_t data = 0XAB;
    AT24CXX_soft_ReadOneByte(ReadAddr,&temp);//避免每次开机都写AT24CXX 
 
    if(temp == 0XAB)
        return 1;		   
    else//排除第一次初始化的情况
    {
        AT24CXX_soft_WriteOneByte(ReadAddr,data);
        AT24CXX_soft_ReadOneByte(ReadAddr,&temp);	  
        if(temp == 0XAB)
            return 1;
    }
    return 0;

}




实验现象

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

君逸~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值