你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 3652|回复: 2

【HAL库每天一例】第050例:I2C-EEPROM

[复制链接]

122

主题

129

回帖

0

蝴蝶豆

论坛元老

最后登录
2019-5-28
发表于 2016-6-24 08:31:16 | 显示全部楼层 |阅读模式
【HAL库每天一例】系列例程从今天开始持续更新。。。。。
我们将坚持每天至少发布一个基于YS-F1Pro开发板的HAL库例程,
该系列例程将带领大家从零开始使用HAL库,后面会持续添加模块应用例程。
同样的,我们还程序发布基于HAL库的指导文档和视频教程,欢迎持续关注,并提出改进意见。
例程下载:
资料包括程序、相关说明资料以及软件使用截图
链接:https://pan.baidu.com/s/1i574oPv
密码:r3s3

(硬石YS-F1Pro开发板HAL库例程持续更新\1. 软件设计之基本裸机例程(HAL库版本)\YSF1_HAL-050. I2C-EEPROM

/**
  ******************************************************************************
  *                           硬石YS-F1Pro开发板例程功能说明
  *
  *  例程名称: 1. EEPROM(AT24C02)-硬件I2C
  *   
  ******************************************************************************
  * 说明:
  * 本例程配套硬石stm32开发板YS-F1Pro使用。
  *
  * 淘宝:
  * 论坛:www ing10bbs com
  * 版权归硬石嵌入式开发团队所有,请勿商用。
  ******************************************************************************
  */

【1】例程简介
  I2C总线是飞利浦公司开发的两线式串行总线。用于连接微控制器和外围设备。它是同步通信的一
种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。通过串行数据
(SDA)线和串行时钟 (SCL)线在连接到总线的器件间传递信息。每个器件都有一个唯一的地址识
别,而且都可以作为一个发送器或接收器。
  EEPROM(Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储
器--一种掉电后数据不丢失的存储芯片。EEPROM可以擦除已有信息,重新编程。一般用在即插即用。
YS-F1Pro开发板上集成一个型号为AT24C02的EEPROM,本例程实现对它的读写操作。
  
【2】跳线帽情况
******* 为保证例程正常运行,必须插入以下跳线帽 **********
丝印编号     IO端口      目标功能引脚        出厂默认设置
  JP1        PA10        TXD(CH340G)          已接入
  JP2        PA9         RXD(CH340G)          已接入
  
【3】操作及现象
使用开发板配套的MINI USB线连接到开发板标示“调试串口”字样的MIMI USB接口(需要安装驱动),
在电脑端打开串口调试助手工具,设置参数为115200 8-N-1。下载完程序之后,在串口调试助手窗口
可接收到信息。

/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

CubeMX_1.jpg
CubeMX_2.jpg
CubeMX_3.jpg

bsp_EEPROM.h文件内容
  1. #ifndef __I2C_EEPROM_H__
  2. #define        __I2C_EEPROM_H__
  3. /* 包含头文件 ----------------------------------------------------------------*/
  4. #include "stm32f1xx_hal.h"

  5. /* 类型定义 ------------------------------------------------------------------*/
  6. /* 宏定义 --------------------------------------------------------------------*/
  7. #define I2C_OWN_ADDRESS                            0x0A              // stm32本机I2C地址
  8. #define I2C_SPEEDCLOCK                             400000            // I2C通信速率(最大为400K)
  9. #define I2C_DUTYCYCLE                              I2C_DUTYCYCLE_2   // I2C占空比模式:1/2

  10. #define EEPROM_I2Cx                                I2C1
  11. #define EEPROM_I2C_RCC_CLK_ENABLE()                __HAL_RCC_I2C1_CLK_ENABLE()
  12. #define EEPROM_I2C_RCC_CLK_DISABLE()               __HAL_RCC_I2C1_CLK_DISABLE()

  13. #define EEPROM_I2C_GPIO_CLK_ENABLE()               __HAL_RCC_GPIOB_CLK_ENABLE()
  14. #define EEPROM_I2C_GPIO_CLK_DISABLE()              __HAL_RCC_GPIOB_CLK_DISABLE()   
  15. #define EEPROM_I2C_GPIO_PORT                       GPIOB   
  16. #define EEPROM_I2C_SCL_PIN                         GPIO_PIN_6
  17. #define EEPROM_I2C_SDA_PIN                         GPIO_PIN_7

  18. /*
  19. * EEPROM 2kb = 2048bit = 2048/8 B = 256 B
  20. * 32 pages of 8 bytes each
  21. *
  22. * Device Address
  23. * 1 0 1 0 A2 A1 A0 R/W
  24. * 1 0 1 0 0  0  0  0 = 0XA0
  25. * 1 0 1 0 0  0  0  1 = 0XA1
  26. */
  27. /* EEPROM Addresses defines */
  28. #define EEPROM_I2C_ADDRESS                         0xA0

  29. /* 扩展变量 ------------------------------------------------------------------*/
  30. extern I2C_HandleTypeDef hi2c_eeprom;

  31. /* 函数声明 ------------------------------------------------------------------*/
  32. void               MX_I2C_EEPROM_Init(void);
  33. void               I2C_EEPROM_WriteData(uint16_t Addr, uint8_t Reg, uint8_t Value);
  34. HAL_StatusTypeDef  I2C_EEPROM_WriteBuffer(uint16_t Addr, uint8_t Reg, uint16_t RegSize, uint8_t *pBuffer, uint16_t Length);
  35. uint8_t            I2C_EEPROM_ReadData(uint16_t Addr, uint8_t Reg);
  36. HAL_StatusTypeDef  I2C_EEPROM_ReadBuffer(uint16_t Addr, uint8_t Reg, uint16_t RegSize, uint8_t *pBuffer, uint16_t Length);
  37. HAL_StatusTypeDef  I2C_EEPROM_IsDeviceReady(uint16_t DevAddress, uint32_t Trials);

  38. #endif /* __I2C_EEPROM_H__ */

  39. /******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/
复制代码

bsp_EEPROM.c文件内容
  1. /**
  2.   ******************************************************************************
  3.   * 文件名程: bsp_EEPROM.c
  4.   * 作    者: 硬石嵌入式开发团队
  5.   * 版    本: V1.0
  6.   * 编写日期: 2015-10-04
  7.   * 功    能: 板载EEPROM(AT24C02)底层驱动程序
  8.   ******************************************************************************
  9.   * 说明:
  10.   * 本例程配套硬石stm32开发板YS-F1Pro使用。
  11.   *
  12.   * 淘宝:
  13.   * 论坛:http://www.ing10bbs.com
  14.   * 版权归硬石嵌入式开发团队所有,请勿商用。
  15.   ******************************************************************************
  16.   */
  17. /* 包含头文件 ----------------------------------------------------------------*/
  18. #include "i2c/bsp_EEPROM.h"

  19. /* 私有类型定义 --------------------------------------------------------------*/
  20. /* 私有宏定义 ----------------------------------------------------------------*/
  21. #define EVAL_I2Cx_TIMEOUT_MAX                   3000

  22. /* 私有变量 ------------------------------------------------------------------*/
  23. I2C_HandleTypeDef hi2c_eeprom;
  24. uint32_t I2cxTimeout = EVAL_I2Cx_TIMEOUT_MAX;

  25. /* 扩展变量 ------------------------------------------------------------------*/
  26. /* 私有函数原形 --------------------------------------------------------------*/
  27. /* 函数体 --------------------------------------------------------------------*/
  28. /**
  29.   * 函数功能: I2C外设初始化
  30.   * 输入参数: 无
  31.   * 返 回 值: 无
  32.   * 说    明:无
  33.   */
  34. void MX_I2C_EEPROM_Init(void)
  35. {
  36.   hi2c_eeprom.Instance             = EEPROM_I2Cx;
  37.   hi2c_eeprom.Init.ClockSpeed      = I2C_SPEEDCLOCK;
  38.   hi2c_eeprom.Init.DutyCycle       = I2C_DUTYCYCLE;
  39.   hi2c_eeprom.Init.OwnAddress1     = 0;
  40.   hi2c_eeprom.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
  41.   hi2c_eeprom.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  42.   hi2c_eeprom.Init.OwnAddress2     = 0;
  43.   hi2c_eeprom.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  44.   hi2c_eeprom.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
  45.   HAL_I2C_Init(&hi2c_eeprom);
  46. }

  47. /**
  48.   * 函数功能: I2C外设硬件初始化配置
  49.   * 输入参数: hi2c:I2C句柄类型指针
  50.   * 返 回 值: 无
  51.   * 说    明: 该函数被HAL库内部调用
  52.   */
  53. void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
  54. {
  55.   GPIO_InitTypeDef GPIO_InitStruct;
  56.   if(hi2c->Instance==EEPROM_I2Cx)
  57.   {  
  58.     /* 使能外设时钟 */
  59.     EEPROM_I2C_RCC_CLK_ENABLE();        
  60.     EEPROM_I2C_GPIO_CLK_ENABLE();
  61.    
  62.     /**I2C1 GPIO Configuration   
  63.     PB6     ------> I2C1_SCL
  64.     PB7     ------> I2C1_SDA
  65.     */
  66.     GPIO_InitStruct.Pin = EEPROM_I2C_SCL_PIN|EEPROM_I2C_SDA_PIN;
  67.     GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  68.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  69.     HAL_GPIO_Init(EEPROM_I2C_GPIO_PORT, &GPIO_InitStruct);
  70.   }
  71. }

  72. /**
  73.   * 函数功能: I2C外设硬件反初始化配置
  74.   * 输入参数: hi2c:I2C句柄类型指针
  75.   * 返 回 值: 无
  76.   * 说    明: 该函数被HAL库内部调用
  77.   */
  78. void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
  79. {
  80.   if(hi2c->Instance==EEPROM_I2Cx)
  81.   {
  82.     /* 禁用外设时钟 */
  83.     EEPROM_I2C_GPIO_CLK_DISABLE();
  84.   
  85.     /**I2C1 GPIO Configuration   
  86.     PB6     ------> I2C1_SCL
  87.     PB7     ------> I2C1_SDA
  88.     */
  89.     HAL_GPIO_DeInit(EEPROM_I2C_GPIO_PORT, EEPROM_I2C_SCL_PIN|EEPROM_I2C_SDA_PIN);
  90.   }
  91. }


  92. /**
  93.   * 函数功能: I2C通信错误处理函数
  94.   * 输入参数: 无
  95.   * 返 回 值: 无
  96.   * 说    明: 一般在I2C通信超时时调用该函数
  97.   */
  98. static void I2C_EEPROM_Error (void)
  99. {
  100.   /* 反初始化I2C通信总线 */
  101.   HAL_I2C_DeInit(&hi2c_eeprom);
  102.   
  103.   /* 重新初始化I2C通信总线*/
  104.   MX_I2C_EEPROM_Init();
  105.   printf("EEPROM I2C通信超时!!! 重新启动I2C...\n");
  106. }

  107. /**
  108.   * 函数功能: 通过I2C写入一个值到指定寄存器内
  109.   * 输入参数: Addr:I2C设备地址
  110.   *           Reg:目标寄存器
  111.   *           Value:值
  112.   * 返 回 值: 无
  113.   * 说    明: 无
  114.   */
  115. void I2C_EEPROM_WriteData(uint16_t Addr, uint8_t Reg, uint8_t Value)
  116. {
  117.   HAL_StatusTypeDef status = HAL_OK;
  118.   
  119.   status = HAL_I2C_Mem_Write(&hi2c_eeprom, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1, I2cxTimeout);
  120.   
  121.   /* 检测I2C通信状态 */
  122.   if(status != HAL_OK)
  123.   {
  124.     /* 调用I2C通信错误处理函数 */
  125.     I2C_EEPROM_Error();
  126.   }
  127. }

  128. /**
  129.   * 函数功能: 通过I2C写入一段数据到指定寄存器内
  130.   * 输入参数: Addr:I2C设备地址
  131.   *           Reg:目标寄存器
  132.   *           RegSize:寄存器尺寸(8位或者16位)
  133.   *           pBuffer:缓冲区指针
  134.   *           Length:缓冲区长度
  135.   * 返 回 值: HAL_StatusTypeDef:操作结果
  136.   * 说    明: 在循环调用是需加一定延时时间
  137.   */
  138. HAL_StatusTypeDef I2C_EEPROM_WriteBuffer(uint16_t Addr, uint8_t Reg, uint16_t RegSize, uint8_t *pBuffer, uint16_t Length)
  139. {
  140.   HAL_StatusTypeDef status = HAL_OK;
  141.   
  142.   status = HAL_I2C_Mem_Write(&hi2c_eeprom, Addr, (uint16_t)Reg, RegSize, pBuffer, Length, I2cxTimeout);

  143.   /* 检测I2C通信状态 */
  144.   if(status != HAL_OK)
  145.   {
  146.     /* 调用I2C通信错误处理函数 */
  147.     I2C_EEPROM_Error();
  148.   }        
  149.   return status;
  150. }


  151. /**
  152.   * 函数功能: 通过I2C读取一个指定寄存器内容
  153.   * 输入参数: Addr:I2C设备地址
  154.   *           Reg:目标寄存器
  155.   * 返 回 值: uint8_t:寄存器内容
  156.   * 说    明: 无
  157.   */
  158. uint8_t I2C_EEPROM_ReadData(uint16_t Addr, uint8_t Reg)
  159. {
  160.   HAL_StatusTypeDef status = HAL_OK;
  161.   uint8_t value = 0;
  162.   
  163.   status = HAL_I2C_Mem_Read(&hi2c_eeprom, Addr, Reg, I2C_MEMADD_SIZE_8BIT, &value, 1, I2cxTimeout);

  164.   /* 检测I2C通信状态 */
  165.   if(status != HAL_OK)
  166.   {
  167.     /* 调用I2C通信错误处理函数 */
  168.     I2C_EEPROM_Error();
  169.   
  170.   }
  171.   return value;
  172. }

  173. /**
  174.   * 函数功能: 通过I2C读取一段寄存器内容存放到指定的缓冲区内
  175.   * 输入参数: Addr:I2C设备地址
  176.   *           Reg:目标寄存器
  177.   *           RegSize:寄存器尺寸(8位或者16位)
  178.   *           pBuffer:缓冲区指针
  179.   *           Length:缓冲区长度
  180.   * 返 回 值: HAL_StatusTypeDef:操作结果
  181.   * 说    明: 无
  182.   */
  183. HAL_StatusTypeDef I2C_EEPROM_ReadBuffer(uint16_t Addr, uint8_t Reg, uint16_t RegSize, uint8_t *pBuffer, uint16_t Length)
  184. {
  185.   HAL_StatusTypeDef status = HAL_OK;

  186.   status = HAL_I2C_Mem_Read(&hi2c_eeprom, Addr, (uint16_t)Reg, RegSize, pBuffer, Length, I2cxTimeout);
  187.   
  188.   /* 检测I2C通信状态 */
  189.   if(status != HAL_OK)
  190.   {
  191.     /* 调用I2C通信错误处理函数 */
  192.     I2C_EEPROM_Error();
  193.   }        
  194.   return status;
  195. }

  196. /**
  197.   * 函数功能: 检测I2C设备是否处于准备好可以通信状态
  198.   * 输入参数: DevAddress:I2C设备地址
  199.   *           Trials:尝试测试次数
  200.   * 返 回 值: HAL_StatusTypeDef:操作结果
  201.   * 说    明: 无
  202.   */
  203. HAL_StatusTypeDef I2C_EEPROM_IsDeviceReady(uint16_t DevAddress, uint32_t Trials)
  204. {
  205.   return (HAL_I2C_IsDeviceReady(&hi2c_eeprom, DevAddress, Trials, I2cxTimeout));
  206. }

  207. /******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/
复制代码
串口调试助手截图.jpg



<
回复

使用道具 举报

122

主题

129

回帖

0

蝴蝶豆

论坛元老

最后登录
2019-5-28
 楼主| 发表于 2016-6-24 08:32:02 | 显示全部楼层
2. EEPROM(AT24C02)-软件模拟I2C(建议使用)
bsp_EEPROM.h文件内容
  1. #ifndef __I2C_EEPROM_H__
  2. #define        __I2C_EEPROM_H__
  3. /* 包含头文件 ----------------------------------------------------------------*/
  4. #include "stm32f1xx_hal.h"

  5. /* 类型定义 ------------------------------------------------------------------*/
  6. /* 宏定义 --------------------------------------------------------------------*/
  7. #define I2C_OWN_ADDRESS                            0x0A

  8. #define I2C_WR                0                /* 写控制bit */
  9. #define I2C_RD                1                /* 读控制bit */

  10. #define I2C_GPIO_CLK_ENABLE()               __HAL_RCC_GPIOB_CLK_ENABLE()
  11. #define I2C_GPIO_PORT                       GPIOB   
  12. #define I2C_SCL_PIN                         GPIO_PIN_6
  13. #define I2C_SDA_PIN                         GPIO_PIN_7

  14. #define I2C_SCL_HIGH()                      HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SCL_PIN,GPIO_PIN_SET)    // 输出高电平
  15. #define I2C_SCL_LOW()                       HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SCL_PIN,GPIO_PIN_RESET)  // 输出低电平
  16. #define I2C_SDA_HIGH()                      HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SDA_PIN,GPIO_PIN_SET)    // 输出高电平
  17. #define I2C_SDA_LOW()                       HAL_GPIO_WritePin(I2C_GPIO_PORT,I2C_SDA_PIN,GPIO_PIN_RESET)  // 输出低电平
  18. #define I2C_SDA_READ()                      HAL_GPIO_ReadPin(I2C_GPIO_PORT,I2C_SDA_PIN)

  19. /*
  20. * AT24C02 2kb = 2048bit = 2048/8 B = 256 B
  21. * 32 pages of 8 bytes each
  22. *
  23. * Device Address
  24. * 1 0 1 0 A2 A1 A0 R/W
  25. * 1 0 1 0 0  0  0  0 = 0XA0
  26. * 1 0 1 0 0  0  0  1 = 0XA1
  27. */

  28. /* AT24C01/02每页有8个字节
  29. * AT24C04/08A/16A每页有16个字节
  30. */
  31. #define EEPROM_DEV_ADDR                           0xA0                    /* 24xx02的设备地址 */
  32. #define EEPROM_PAGE_SIZE                      8                          /* 24xx02的页面大小 */
  33. #define EEPROM_SIZE                                      256                          /* 24xx02总容量 */

  34. /* 扩展变量 ------------------------------------------------------------------*/
  35. /* 函数声明 ------------------------------------------------------------------*/
  36. void    I2C_Start(void);
  37. void    I2C_Stop(void);
  38. void    I2C_SendByte(uint8_t _ucByte);
  39. uint8_t I2C_ReadByte(void);
  40. uint8_t I2C_WaitAck(void);
  41. void    I2C_Ack(void);
  42. void    I2C_NAck(void);
  43. uint8_t I2C_CheckDevice(uint8_t _Address);

  44. uint8_t EEPROM_CheckOk(void);
  45. uint8_t EEPROM_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize);
  46. uint8_t EEPROM_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize);



  47. #endif /* __I2C_EEPROM_H__ */

  48. /******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/
复制代码



bsp_EEPROM.c文件内容
  1. /**
  2.   ******************************************************************************
  3.   * 文件名程: bsp_eeprom.c
  4.   * 作    者: 硬石嵌入式开发团队
  5.   * 版    本: V1.0
  6.   * 编写日期: 2015-10-04
  7.   * 功    能: 板载EEPROM(AT24C02)底层驱动程序
  8.   ******************************************************************************
  9.   * 说明:
  10.   * 本例程配套硬石stm32开发板YS-F1Pro使用。
  11.   *
  12.   * 淘宝:
  13.   * 论坛:http://www.ing10bbs.com
  14.   * 版权归硬石嵌入式开发团队所有,请勿商用。
  15.   ******************************************************************************
  16.   */
  17. /* 包含头文件 ----------------------------------------------------------------*/
  18. #include "i2c/bsp_EEPROM.h"

  19. /* 私有类型定义 --------------------------------------------------------------*/
  20. /* 私有宏定义 ----------------------------------------------------------------*/
  21. /* 私有变量 ------------------------------------------------------------------*/
  22. /* 扩展变量 ------------------------------------------------------------------*/
  23. /* 私有函数原形 --------------------------------------------------------------*/
  24. /* 函数体 --------------------------------------------------------------------*/
  25. /**
  26.   * 函数功能: I2C总线位延迟,最快400KHz
  27.   * 输入参数: 无
  28.   * 返 回 值: 无
  29.   * 说    明:无
  30.   */
  31. static void I2C_Delay(void)
  32. {
  33.         uint8_t i;

  34.         /* 
  35.                  下面的时间是通过逻辑分析仪测试得到的。
  36.                 CPU主频72MHz时,在内部Flash运行, MDK工程不优化
  37.                 循环次数为10时,SCL频率 = 205KHz
  38.                 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
  39.                  循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
  40.         
  41.     IAR工程编译效率高,不能设置为7
  42.         */
  43.         for (i = 0; i < 10; i++);
  44. }

  45. /**
  46.   * 函数功能: CPU发起I2C总线启动信号
  47.   * 输入参数: 无
  48.   * 返 回 值: 无
  49.   * 说    明:无
  50.   */
  51. void I2C_Start(void)
  52. {
  53.         /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
  54.         I2C_SDA_HIGH();
  55.         I2C_SCL_HIGH();
  56.         I2C_Delay();
  57.         I2C_SDA_LOW();
  58.         I2C_Delay();
  59.         I2C_SCL_LOW();
  60.         I2C_Delay();
  61. }

  62. /**
  63.   * 函数功能: CPU发起I2C总线停止信号
  64.   * 输入参数: 无
  65.   * 返 回 值: 无
  66.   * 说    明:无
  67.   */
  68. void I2C_Stop(void)
  69. {
  70.         /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
  71.         I2C_SDA_LOW();
  72.         I2C_SCL_HIGH();
  73.         I2C_Delay();
  74.         I2C_SDA_HIGH();
  75. }

  76. /**
  77.   * 函数功能: CPU向I2C总线设备发送8bit数据
  78.   * 输入参数: Byte : 等待发送的字节
  79.   * 返 回 值: 无
  80.   * 说    明:无
  81.   */
  82. void I2C_SendByte(uint8_t Byte)
  83. {
  84.         uint8_t i;

  85.         /* 先发送字节的高位bit7 */
  86.         for (i = 0; i < 8; i++)
  87.         {               
  88.                 if (Byte & 0x80)
  89.                 {
  90.                         I2C_SDA_HIGH();
  91.                 }
  92.                 else
  93.                 {
  94.                         I2C_SDA_LOW();
  95.                 }
  96.                 I2C_Delay();
  97.                 I2C_SCL_HIGH();
  98.                 I2C_Delay();        
  99.                 I2C_SCL_LOW();
  100.                 if (i == 7)
  101.                 {
  102.                         I2C_SDA_HIGH(); // 释放总线
  103.                 }
  104.                 Byte <<= 1;        /* 左移一个bit */
  105.                 I2C_Delay();
  106.         }
  107. }


  108. /**
  109.   * 函数功能: CPU从I2C总线设备读取8bit数据
  110.   * 输入参数: 无
  111.   * 返 回 值: 读到的数据
  112.   * 说    明:无
  113.   */
  114. uint8_t I2C_ReadByte(void)
  115. {
  116.         uint8_t i;
  117.         uint8_t value;

  118.         /* 读到第1个bit为数据的bit7 */
  119.         value = 0;
  120.         for (i = 0; i < 8; i++)
  121.         {
  122.                 value <<= 1;
  123.                 I2C_SCL_HIGH();
  124.                 I2C_Delay();
  125.                 if (I2C_SDA_READ())
  126.                 {
  127.                         value++;
  128.                 }
  129.                 I2C_SCL_LOW();
  130.                 I2C_Delay();
  131.         }
  132.         return value;
  133. }

  134. /**
  135.   * 函数功能: CPU产生一个时钟,并读取器件的ACK应答信号
  136.   * 输入参数: 无
  137.   * 返 回 值: 返回0表示正确应答,1表示无器件响应
  138.   * 说    明:无
  139.   */
  140. uint8_t I2C_WaitAck(void)
  141. {
  142.         uint8_t re;

  143.         I2C_SDA_HIGH();        /* CPU释放SDA总线 */
  144.         I2C_Delay();
  145.         I2C_SCL_HIGH();        /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
  146.         I2C_Delay();
  147.         if (I2C_SDA_READ())        /* CPU读取SDA口线状态 */
  148.         {
  149.                 re = 1;
  150.         }
  151.         else
  152.         {
  153.                 re = 0;
  154.         }
  155.         I2C_SCL_LOW();
  156.         I2C_Delay();
  157.         return re;
  158. }

  159. /**
  160.   * 函数功能: CPU产生一个ACK信号
  161.   * 输入参数: 无
  162.   * 返 回 值: 无
  163.   * 说    明:无
  164.   */
  165. void I2C_Ack(void)
  166. {
  167.         I2C_SDA_LOW();        /* CPU驱动SDA = 0 */
  168.         I2C_Delay();
  169.         I2C_SCL_HIGH();        /* CPU产生1个时钟 */
  170.         I2C_Delay();
  171.         I2C_SCL_LOW();
  172.         I2C_Delay();
  173.         I2C_SDA_HIGH();        /* CPU释放SDA总线 */
  174. }

  175. /**
  176.   * 函数功能: CPU产生1个NACK信号
  177.   * 输入参数: 无
  178.   * 返 回 值: 无
  179.   * 说    明:无
  180.   */
  181. void I2C_NAck(void)
  182. {
  183.         I2C_SDA_HIGH();        /* CPU驱动SDA = 1 */
  184.         I2C_Delay();
  185.         I2C_SCL_HIGH();        /* CPU产生1个时钟 */
  186.         I2C_Delay();
  187.         I2C_SCL_LOW();
  188.         I2C_Delay();        
  189. }

  190. /**
  191.   * 函数功能: 配置I2C总线的GPIO,采用模拟IO的方式实现
  192.   * 输入参数: 无
  193.   * 返 回 值: 无
  194.   * 说    明:无
  195.   */
  196. static void I2C_InitGPIO(void)
  197. {
  198.   GPIO_InitTypeDef GPIO_InitStruct;
  199.   
  200.   /* 打开GPIO时钟 */
  201.         I2C_GPIO_CLK_ENABLE();

  202.   GPIO_InitStruct.Pin = I2C_SCL_PIN|I2C_SDA_PIN;
  203.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  204.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
  205.   HAL_GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStruct);

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

  209. /**
  210.   * 函数功能: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
  211.   * 输入参数: _Address:设备的I2C总线地址
  212.   * 返 回 值: 返回值 0 表示正确, 返回1表示未探测到
  213.   * 说    明:在访问I2C设备前,请先调用 I2C_CheckDevice() 检测I2C设备是否正常,该函数会配置GPIO
  214.   */
  215. uint8_t I2C_CheckDevice(uint8_t _Address)
  216. {
  217.         uint8_t ucAck;

  218.         I2C_InitGPIO();                /* 配置GPIO */        
  219.         I2C_Start();                /* 发送启动信号 */
  220.         /* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
  221.         I2C_SendByte(_Address | I2C_WR);
  222.         ucAck = I2C_WaitAck();        /* 检测设备的ACK应答 */
  223.         I2C_Stop();                        /* 发送停止信号 */
  224.         return ucAck;
  225. }

  226. /**
  227.   * 函数功能: 判断串行EERPOM是否正常
  228.   * 输入参数: 无
  229.   * 返 回 值: 1 表示正常, 0 表示不正常
  230.   * 说    明:无
  231.   */
  232. uint8_t EEPROM_CheckOk(void)
  233. {
  234.         if(I2C_CheckDevice(EEPROM_DEV_ADDR) == 0)
  235.         {
  236.                 return 1;
  237.         }
  238.         else
  239.         {
  240.                 /* 失败后,切记发送I2C总线停止信号 */
  241.                 I2C_Stop();               
  242.                 return 0;
  243.         }
  244. }

  245. /**
  246.   * 函数功能: 从串行EEPROM指定地址处开始读取若干数据
  247.   * 输入参数: ReadBuf : 存放读到的数据的缓冲区指针
  248.   *           Address : 起始地址  
  249.   *           Size : 数据长度,单位为字节
  250.   * 返 回 值:  0 表示失败,1表示成功
  251.   * 说    明:无
  252.   */
  253. uint8_t EEPROM_ReadBytes(uint8_t *ReadBuf, uint16_t Address, uint16_t Size)
  254. {
  255.         uint16_t i;
  256.         
  257.         /* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */
  258.         
  259.         /* 第1步:发起I2C总线启动信号 */
  260.         I2C_Start();        
  261.   
  262.         /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  263.         I2C_SendByte(EEPROM_DEV_ADDR | I2C_WR);        /* 此处是写指令 */        
  264.   
  265.         /* 第3步:等待ACK */
  266.         if (I2C_WaitAck() != 0)
  267.         {
  268.                 goto cmd_fail;        /* EEPROM器件无应答 */
  269.         }
  270.   
  271.         /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
  272.         I2C_SendByte((uint8_t)Address);        
  273.   
  274.         /* 第5步:等待ACK */
  275.         if (I2C_WaitAck() != 0)
  276.         {
  277.                 goto cmd_fail;        /* EEPROM器件无应答 */
  278.         }        
  279.         /* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */
  280.         I2C_Start();        
  281.   
  282.         /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  283.         I2C_SendByte(EEPROM_DEV_ADDR | I2C_RD);        /* 此处是读指令 */
  284.         
  285.         /* 第8步:发送ACK */
  286.         if (I2C_WaitAck() != 0)
  287.         {
  288.                 goto cmd_fail;        /* EEPROM器件无应答 */
  289.         }        
  290.         
  291.         /* 第9步:循环读取数据 */
  292.         for (i = 0; i < Size; i++)
  293.         {
  294.                 ReadBuf[i] = I2C_ReadByte();        /* 读1个字节 */
  295.                
  296.                 /* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */
  297.                 if (i != Size - 1)
  298.                 {
  299.                         I2C_Ack();        /* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */
  300.                 }
  301.                 else
  302.                 {
  303.                         I2C_NAck();        /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
  304.                 }
  305.         }
  306.         /* 发送I2C总线停止信号 */
  307.         I2C_Stop();
  308.         return 1;        /* 执行成功 */

  309. cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
  310.         /* 发送I2C总线停止信号 */
  311.         I2C_Stop();
  312.         return 0;
  313. }

  314. /**
  315.   * 函数功能: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率
  316.   * 输入参数: WriteBuf : 存放带写入的数据的缓冲区指针
  317.   *           Address : 起始地址
  318.   *           Size : 数据长度,单位为字节
  319.   * 返 回 值:  0 表示失败,1表示成功
  320.   * 说    明:无
  321.   */
  322. uint8_t EEPROM_WriteBytes(uint8_t *WriteBuf, uint16_t Address, uint16_t Size)
  323. {
  324.         uint16_t i,m;
  325.         uint16_t usAddr;
  326.         
  327.         /*
  328.          * 写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。
  329.          * 对于24xx02,page size = 8
  330.          * 简单的处理方法为:按字节写操作模式,没写1个字节,都发送地址
  331.          * 为了提高连续写的效率: 本函数采用page wirte操作。
  332.          */

  333.         usAddr = Address;        
  334.         for (i = 0; i < Size; i++)
  335.         {
  336.                 /* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */
  337.                 if ((i == 0) || (usAddr & (EEPROM_PAGE_SIZE - 1)) == 0)
  338.                 {
  339.                         /* 第0步:发停止信号,启动内部写操作 */
  340.                         I2C_Stop();
  341.                         
  342.                         /* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms                        
  343.                                 CLK频率为200KHz时,查询次数为30次左右
  344.                         */
  345.                         for (m = 0; m < 1000; m++)
  346.                         {                                
  347.                                 /* 第1步:发起I2C总线启动信号 */
  348.                                 I2C_Start();
  349.                                 
  350.                                 /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  351.                                 I2C_SendByte(EEPROM_DEV_ADDR | I2C_WR);        /* 此处是写指令 */
  352.                                 
  353.                                 /* 第3步:发送一个时钟,判断器件是否正确应答 */
  354.                                 if (I2C_WaitAck() == 0)
  355.                                 {
  356.                                         break;
  357.                                 }
  358.                         }
  359.                         if (m  == 1000)
  360.                         {
  361.                                 goto cmd_fail;        /* EEPROM器件写超时 */
  362.                         }
  363.                
  364.                         /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
  365.                         I2C_SendByte((uint8_t)usAddr);
  366.                         
  367.                         /* 第5步:等待ACK */
  368.                         if (I2C_WaitAck() != 0)
  369.                         {
  370.                                 goto cmd_fail;        /* EEPROM器件无应答 */
  371.                         }
  372.                 }
  373.         
  374.                 /* 第6步:开始写入数据 */
  375.                 I2C_SendByte(WriteBuf[i]);
  376.         
  377.                 /* 第7步:发送ACK */
  378.                 if (I2C_WaitAck() != 0)
  379.                 {
  380.                         goto cmd_fail;        /* EEPROM器件无应答 */
  381.                 }

  382.                 usAddr++;        /* 地址增1 */               
  383.         }
  384.         
  385.         /* 命令执行成功,发送I2C总线停止信号 */
  386.         I2C_Stop();
  387.         return 1;

  388. cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
  389.         /* 发送I2C总线停止信号 */
  390.         I2C_Stop();
  391.         return 0;
  392. }

  393. /******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/
复制代码




回复 支持 反对

使用道具 举报

0

主题

153

回帖

0

蝴蝶豆

中级会员

最后登录
2020-1-5
发表于 2016-7-1 22:30:56 | 显示全部楼层
多谢分享
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版