IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【STM32CubeMX学习】I2C读写24C02 -> 正文阅读

[嵌入式]【STM32CubeMX学习】I2C读写24C02

目录

1、I2C总线

2、I2C驱动编写

3、24C02

4、EEPROM读写函数编写

5、验证


1、I2C总线

I2C总线有两根线:时钟线SCL、数据线SDA,当总线空闲时,两根线都处于高电平。

I2C的数据传输规范:

①当SCL为高电平的时候,SDA必须保持稳定;只有SCL为低电平时SDA才可以发生变化。

②在数据传输的开始和结束需要定义开始信号和停止信号:

????????开始信号:SCL为高时,SDA高->低。

????????停止信号:SCL为高时,SDA低->高。

④I2C数据先传高位,在开始信号和结束信号之间有多少字节数据不限定,但每字节必须是8位,每一字节后面都有一个“应答/非应答位”(由接受方提供)。

????????在第9个时钟周期,接收方将SDA线拉低,产生“应答”

????????在第9个时钟周期,接收方将SDA线拉高,产生“非应答”

2、I2C驱动编写

在STM32CubeMX配置I2C引脚:

?i2c.h:

#ifndef _I2C_H
#define _I2C_H

#include "main.h"

//IO 操作函数
#define IIC_SDA_GPIO_MODE_Pos    GPIO_CRL_MODE7_Pos                           

#define I2C_SDA_IN {IIC_SDA_GPIO_Port->CRL&=0X0FFFFFFF;GPIOB->CRL|=(uint32_t)8<<IIC_SDA_GPIO_MODE_Pos;}
#define I2C_SDA_OUT {IIC_SDA_GPIO_Port->CRL&=0X0FFFFFFF;GPIOB->CRL|=(uint32_t)3<<IIC_SDA_GPIO_MODE_Pos;}

#define I2C_SCL_LOW      HAL_GPIO_WritePin(IIC_SCL_GPIO_Port,IIC_SCL_Pin,GPIO_PIN_RESET)
#define I2C_SCL_HIGH     HAL_GPIO_WritePin(IIC_SCL_GPIO_Port,IIC_SCL_Pin,GPIO_PIN_SET)
#define I2C_SDA_LOW      HAL_GPIO_WritePin(IIC_SDA_GPIO_Port,IIC_SDA_Pin,GPIO_PIN_RESET)
#define I2C_SDA_HIGH     HAL_GPIO_WritePin(IIC_SDA_GPIO_Port,IIC_SDA_Pin,GPIO_PIN_SET)

#define I2C_SDA_READ     HAL_GPIO_ReadPin(IIC_SDA_GPIO_Port,IIC_SDA_Pin)

#define I2C_ACK          0//应答
#define I2C_NOACK        1//非应答

void I2C_Start(void);
void I2C_Stop(void);
void I2C_PutAck(uint8_t Ack);
uint8_t I2C_GetAck(void);

uint8_t I2C_WriteByte(uint8_t Data);
uint8_t I2C_ReadByte(uint8_t ack);

#endif 

i2c.c:

#include "i2c.h"

static void I2C_Delay(void)
{
   uint8_t i=10; 
   while(i)
   {
     i--;
   }
}

/*开始信号,SCL高时,SDA高->低*/
void I2C_Start(void)
{
  I2C_SCL_HIGH;//SCL高
  I2C_Delay();

  I2C_SDA_HIGH;//SDA高
  I2C_Delay();
  I2C_SDA_LOW;//SDA低  
  I2C_Delay();

  I2C_SCL_LOW;//SCL低
  I2C_Delay();
}

/*停止信号,SCL高时,SDA低->高*/
void I2C_Stop(void)
{
  I2C_SDA_LOW;//SDA低
  I2C_Delay();

  I2C_SCL_HIGH;//SCL高
  I2C_Delay();

  I2C_SDA_HIGH;//SDA高
  I2C_Delay();
}

/*第9个时钟周期时输出应答/非应答信号,SCL高时,接收方将SDA拉低/高*/
void I2C_PutAck(uint8_t Ack)
{
  I2C_SCL_LOW;//SCL低
  I2C_Delay();

  if(I2C_ACK == Ack)
    I2C_SDA_LOW;//应答
  else
    I2C_SDA_HIGH;//非应答
  I2C_Delay();

  I2C_SCL_HIGH;//SCL高,第9个时钟周期
  I2C_Delay();
  I2C_SCL_LOW;//SCL低
  I2C_Delay();
}

/*第9个时钟周期时获得应答/非应答信号*/
uint8_t I2C_GetAck(void)
{
  uint8_t ack;

  I2C_SCL_LOW;//SCL低
  I2C_Delay();

  I2C_SDA_IN;//SDA配置为输入模式

  I2C_SCL_HIGH;//SCL高,第9个时钟周期
  I2C_Delay();

  if(I2C_SDA_READ)
    ack = I2C_NOACK;//非应答
  else
    ack = I2C_ACK;//应答

  I2C_SCL_LOW;  //SCL低
  I2C_Delay();

  I2C_SDA_OUT;//SDA配置为输出模式

  return ack;//返回应答位
}

/*I2C写1字节,SCL低->SDA写1位->SCL高(循环8次),然后获得应答位*/
uint8_t I2C_WriteByte(uint8_t Data)
{
  uint8_t cnt;

  for(cnt=0; cnt<8; cnt++)
  {
    I2C_SCL_LOW;//SCL低
    I2C_Delay();

    if(Data & 0x80)
      I2C_SDA_HIGH;//SDA高
    else
      I2C_SDA_LOW;//SDA低
    Data <<= 1;
    I2C_Delay();

    I2C_SCL_HIGH;//SCL高
    I2C_Delay();
  }
  I2C_SCL_LOW;//SCL低
  I2C_Delay();

  return I2C_GetAck();//获得应答位
}

/*I2C读一字节,SCL高->SDA读1位->SCL低(循环8次),然后发送应答位*/
uint8_t I2C_ReadByte(uint8_t ack)
{
  uint8_t cnt;
  uint8_t data;

  I2C_SCL_LOW;//SCL低
  I2C_Delay();

  I2C_SDA_IN;//SDA配置为输入模式
  for(cnt=0; cnt<8; cnt++)
  {
    I2C_SCL_HIGH;//SCL高
    I2C_Delay();

    data <<= 1;
    if(I2C_SDA_READ)
      data |= 0x01;//SDA为高

    I2C_SCL_LOW;//SCL低
    I2C_Delay();
  }
  I2C_SDA_OUT;//SDA配置为输出模式

  I2C_PutAck(ack); //产生应答(或者非应答)位

  return data;  //返回数据
}

3、24C02

①容量:2K bits = 2048 bits = 256 bytes。

②每页8 bytes,共32页。

③地址长度为8位。

④设备地址,开始信号之后,是8位的设备地址如下:

⑤向EEPROM写一字节步骤:

?⑥从EEPROM读取一字节数据步骤:

?4、EEPROM读写函数编写

eeprom.h

#ifndef _EEPROM_H
#define _EEPROM_H

#include "main.h"

#define EEPROM_DEV_ADDR           0xA0//地址1010000

#define EEPROM_WR                 0x00//写(地址的最后1位)
#define EEPROM_RD                 0x01//读(地址的最后1位)

uint8_t EEPROM_WriteByte(uint8_t Addr, uint8_t Data);
uint8_t EEPROM_ReadByte(uint8_t Addr, uint8_t *Data);

#endif 

eeprom.c

#include "eeprom.h"
#include "i2c.h"

/*EEPROM写1字节*/
uint8_t EEPROM_WriteByte(uint8_t Addr, uint8_t Data)
{
  uint8_t  ack;

  /*开始*/
  I2C_Start();

  /*设备地址/写*/
  ack = I2C_WriteByte(EEPROM_DEV_ADDR | EEPROM_WR);
  if(I2C_NOACK == ack)
  {
    I2C_Stop();
    return I2C_NOACK;
  }

  /*数据地址*/
  ack = I2C_WriteByte(Addr);
  if(I2C_NOACK == ack)
  {
    I2C_Stop();
    return I2C_NOACK;
  }

  /*写1字节数据*/
  ack = I2C_WriteByte(Data);
  if(I2C_NOACK == ack)
  {
    I2C_Stop();
    return I2C_NOACK;
  }

  /*停止*/
  I2C_Stop();

  return I2C_ACK;
}

/*EEPROM读1字节*/
uint8_t EEPROM_ReadByte(uint8_t Addr, uint8_t *Data)
{
  uint8_t  ack;

  /*开始*/
  I2C_Start();

  /*设备地址/写*/
  ack = I2C_WriteByte(EEPROM_DEV_ADDR | EEPROM_WR);
  if(I2C_NOACK == ack)
  {
    I2C_Stop();
    return I2C_NOACK;
  }

  /*数据地址*/
  ack = I2C_WriteByte(Addr);
  if(I2C_NOACK == ack)
  {
    I2C_Stop();
    return I2C_NOACK;
  }

  /*重新开始*/
  I2C_Start();

  /*设备地址/读*/
  ack = I2C_WriteByte(EEPROM_DEV_ADDR | EEPROM_RD);
  if(I2C_NOACK == ack)
  {
    I2C_Stop();
    return I2C_NOACK;
  }

  /*读一字节数据*/
  *Data = I2C_ReadByte(I2C_NOACK);   //读取1字节,产生非应答

  /*停止*/
  I2C_Stop();

  return I2C_ACK;
}

5、验证

在main.c文件添加 #include "eeprom.h" #include "i2c.h"

在main函数里加入下面代码:

  /* USER CODE BEGIN 2 */
  uint8_t  ACK;
  uint8_t  WRITE_DATA = 0;
  uint8_t  READ_DATA;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    WRITE_DATA++;
    ACK = EEPROM_WriteByte(0, WRITE_DATA);//0地址写1字节数据
    if(I2C_ACK == ACK)
    {
      printf("Write Data=%d\r\n",WRITE_DATA);
    }
    else printf("Write Data Erro\r\n");
    Delay_Ms(100);

    ACK = EEPROM_ReadByte(0, &WRITE_DATA);//0地址读一字节数据
    if(I2C_ACK == ACK)
    {
      printf("Read Data=%d\r\n",WRITE_DATA);
    }
    else printf("Write Data Erro\r\n");

  }
  /* USER CODE END 3 */

打印结果如下:

?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:43:47  更:2022-03-12 17:45:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:47:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码