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

硬件IIC读取AT24C02

[复制链接]
在路上11111111 发布时间:2017-7-16 22:08
今天在这里贴一个今天写的IIC读AT24C02的帖子
  1. #include "stm32f10x_i2c.h"
  2. #include "iic.h"
  3. #include "stdio.h"

  4. #define I2C_Speed  400000
  5. #define I2C1_SLAVE_ADDRESS7 0XA0
  6. #define I2C_PageSize 8

  7. u16 EEPROM_ADDRESS;



  8. void GPIO_Configuration(void)//GPIO_Pin_6,GPIO_Pin_7复用开漏输出
  9. {
  10.         GPIO_InitTypeDef  GPIO_InitStructure;
  11.        
  12.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//IIC1 和 IIC2 都是在APB1上的
  13.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//SCL 和 SDA
  14.        
  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;// GPIO_Pin_6(SCL) GPIO_Pin_7;
  16.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//IIC 的 SDA和SCL都是复用开漏输出模式
  18.         GPIO_Init(GPIOB,&GPIO_InitStructure);
  19. }

  20. void I2C_Configuration(void)
  21. {
  22.         I2C_InitTypeDef  I2C_InitStructure;
  23.        
  24.         I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//设置IIC是IIC模式;
  25.         //IIC 的 工作模式有两种的,一种是IIC 一种是SMBus模式
  26.         I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//
  27.         /*本成员设置的是I2C的SCL线时钟的占空比。SCL线的时钟信号的高电平时间
  28.     与低电平时间是没必要相同的,由于SDA线是在SCL线维持在高电平时读取或写入数据的,而在SCL的
  29.     低电平期间SDA的数据发生变化,所以高电平时间较长就不容易出现数据错误。根据I2C协议,在快速
  30.     模式和高速模式下SCL的高低电平时间可以不同。在STM32的I2C占空比配置中有两个选择,分别为高
  31.     电平时间比低电平时间为16:9 (I2C_DutyCycle_16_9)和2:1 ( I2C_DutyCycle_2)。 本实验中使用
  32.     的是I2C_DutyCycle_2*/
  33.         I2C_InitStructure.I2C_OwnAddress1 = 0;//这个是STM32 本身的地址,可以随便设置,它是作为主设备的,但是如果作为从设备的话,设定的地址,就必须
  34.         //作为主设备进行寻地址的地址了
  35.         I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//
  36.         /*
  37.             本成员是关于I2C应答设置,设置为使能则每接收到一个字节就返回一个应
  38.       答信号。 本实验配置为允许应答(I2C_Ack_Enable),这是绝大多数遵循I2C标准的设备通讯的要求,
  39.       改为禁止应答(I2C_Ack_Disable)往往会导致通讯错误
  40.         ***************/
  41.         I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  42.         //本成员选择I2C的寻址模式是7位还是10位地址
  43.         I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
  44.         /*
  45.             本成员设置的是I2C的传输速率,在调用初始化函数时,函数会根据我们输
  46.       入的数值经过运算后把分频值写入到I2C的时钟控制寄存器。而我们写入的这个参数值不得高于
  47.       400KHz。**************/
  48.        
  49.         I2C_Init(I2C1,&I2C_InitStructure);//初始化
  50.        
  51.         I2C_Cmd(I2C1,ENABLE);//使能I2C1;

  52.         printf("\n\r I2C_Configuration----\r\n");
  53.        
  54. }

  55. void I2C_EE_Init(void)
  56. {
  57.         GPIO_Configuration();
  58.        
  59.         I2C_Configuration();
  60.        
  61. #ifdef EEPROM_Block0_ADDRESS
  62.         EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
  63.         //0xA0
  64. #endif
  65. #ifdef EEPROM_Block1_ADDRESS
  66.         EEPROM_ADDRESS = EEPROM_Block1_AFFRESS;
  67.         //0XA2
  68. #endif
  69. #ifdef EEPROM_Block2_ADDRESS
  70.         EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
  71.         //0XA4
  72. #endif
  73. #ifdef EEPROM_Block3_ADDRESS
  74.         EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
  75.         //0XA6
  76. #endif
  77. }
  78. /*********************

  79. 1:这个的思想就是先看看你的字节数是不是够你的1page的大小;
  80. 2:然后再去看看你设置的需要写的字节的位置
  81. 3:看看你需要写的这一页的还需要多少字节才能写完
  82. 4:最后就是去分析了;
  83. ******************/
  84. //NumOfPage 是指你需要写的字节一共需要占用的的页数
  85. //NumOfSingle 是指你需要写的字节写完完整的页数以后还剩下多少字节数
  86. //Addr 是你要写的第一个字节的位置
  87. //count 是你要写完一页page 的个数;
  88. //注意你写完一page的时候,他的地址会自动变成0的,没写完一页page 的时候,他的地址会自动累加这是一个很重要的特性
  89. void I2C_EE_BufferWrite(u8* pBuffer,u8 WriteAddr,u16 NumByteToWrite)
  90. {
  91.         u8 NumOfPage = 0,NumOfSingle = 0,Addr = 0,count = 0;
  92.   Addr = WriteAddr % I2C_PageSize;//把首个字节的位置找出来
  93.         count = I2C_PageSize - Addr;//把写完该页page的个数找出来
  94.         NumOfPage = NumByteToWrite / I2C_PageSize;//找出你要写的数据能占几页page
  95.         NumOfSingle = NumByteToWrite % I2C_PageSize;//找出写完page以后还剩多少个字节
  96.        
  97.         if(Addr == 0)//如果上来要写的位置是某一个page 的 第一个位置
  98.         {
  99.                 if(NumOfPage == 0)//如果要写的字数小于一页page 所需要的大小
  100.                 {
  101.                         I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);//直接开始从page 写
  102.                         I2C_EE_WaitEepromStandbyState();//等待发送成功;
  103.                 }
  104.                 else
  105.                 {
  106.                         while(NumOfPage--)//如果page >0 那就写完page
  107.                         {
  108.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,I2C_PageSize);//写一页page
  109.                                 I2C_EE_WaitEepromStandbyState();//等待这一页的数据发送完成
  110.                                 WriteAddr += I2C_PageSize;//把地址进行累加
  111.                                 pBuffer += I2C_PageSize;//字符往后加
  112.                         }
  113.                         if(NumOfSingle!=0)//写完你要写的page 以后如果还有写的数据
  114.                         {
  115.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);//将剩下的字符写进去
  116.                                 I2C_EE_WaitEepromStandbyState();//等待数据发送完成
  117.                         }
  118.                 }
  119.         }
  120.         else
  121.         {
  122.                 if(NumOfPage == 0)//要写的字符数小于一page
  123.                 {
  124.                         if(NumOfSingle < count)//如果写的数还不够写完1page的数的话
  125.                         {
  126.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);//直接写进去
  127.                           I2C_EE_WaitEepromStandbyState();//等待这一页的数据发送完成
  128.                         }
  129.                         else//如果要写的数据大于写完这一页的字数
  130.                         {
  131.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,count);//先把这一页写完
  132.                           I2C_EE_WaitEepromStandbyState();//等待数据发送完成
  133.                                 WriteAddr += count;//将地址累加
  134.                                 pBuffer += count;//
  135.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle-count);//再去写完剩下的字节数
  136.                           I2C_EE_WaitEepromStandbyState();//等待数据完成
  137.                   }
  138.                 }
  139.                 else//如果要写的数据大于一page
  140.                 {
  141.                         NumByteToWrite -= count;//这个是写完本页剩下的字节数
  142.       NumOfPage = NumByteToWrite /         I2C_PageSize;//这个是还剩下的数据所占有的页数
  143.       NumOfSingle = NumByteToWrite % I2C_PageSize;//剩下的数据写完页数以后还剩下的字节数
  144.       if(count != 0)//如果要写完一页需要的字节数不是0;
  145.                         {
  146.         I2C_EE_PageWrite(pBuffer,WriteAddr,count);//先把这一页写完
  147.         I2C_EE_WaitEepromStandbyState();
  148.         WriteAddr += count;
  149.         pBuffer += count;
  150.                         }
  151.                         while(NumOfPage--)//写完剩下的page
  152.                         {
  153.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,I2C_PageSize);
  154.                                 I2C_EE_WaitEepromStandbyState();
  155.                                 WriteAddr += I2C_PageSize;
  156.                                 pBuffer += I2C_PageSize;
  157.                         }
  158.                         if(NumOfSingle != 0)//将最后的字节写进去
  159.                         {
  160.                                 I2C_EE_PageWrite(pBuffer,WriteAddr,NumOfSingle);
  161.                                 I2C_EE_WaitEepromStandbyState();
  162.                         }
  163.                 }
  164.         }
  165. }



  166. /*

  167.     IIC通信的步骤;
  168. 1:首先要等待总线BUSY = 0;
  169. 2:产生一个开始的信号;然后等待EV5;
  170. 3:发送一个地址;然后等待EV6;
  171. 4:发送数据;等待EV8;
  172. 5:发送STOP;
  173. 这是通信一次的步骤;
  174.       ******/
  175. void I2C_EE_ByteWrite(u8* pBuffer,u8 WriteAddr)//给EPPROM写一个字节
  176. {
  177.         while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//等待IIC忙结束
  178.        
  179.         I2C_GenerateSTART(I2C1,ENABLE);//产生开始信号
  180.         // I2C_ CheckEvent()  检查最近一次 I2C 事件是否是输入的事件
  181.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//等待EV5;
  182.        
  183.         I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);//配置成发送方向和发送的外设地址
  184.        
  185.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待EV6
  186.        
  187.         I2C_SendData(I2C1,WriteAddr);//发送第一个数据(这里其实第一个数据是给EPPROM写地址)
  188.        
  189.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
  190.        
  191.         I2C_SendData(I2C1,*pBuffer);//发送你要写的数据
  192.        
  193.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
  194.        
  195.         I2C_GenerateSTOP(I2C1,ENABLE);//产生停止信号
  196. }


  197. void I2C_EE_PageWrite(u8* pBuffer,u8 WriteAddr,u8 NumByteToWrite)//写一个EPPROM 的 Page
  198. {
  199.         while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//等待IIC忙结束
  200.        
  201.         I2C_GenerateSTART(I2C1,ENABLE);//这个是产生开始信号
  202.        
  203.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//等待EV5
  204.        
  205.         I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);//设置发送方向以及发送的地址
  206.        
  207.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待EV6(这里的EV6和EV8一块了,主要是因为这里的速度确实快)
  208.        
  209.         I2C_SendData(I2C1,WriteAddr);//发送第一个数据(这个其实就是给EPPROM写地址)
  210.        
  211.         while(! I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
  212.        
  213.         while(NumByteToWrite--)//写数据
  214.         {
  215.                 I2C_SendData(I2C1,*pBuffer);
  216.                
  217.                 pBuffer++;
  218.                
  219.                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//等待EV8
  220.         }
  221.        
  222.         I2C_GenerateSTOP(I2C1,ENABLE);//产生停止信号
  223. }





  224. void I2C_EE_BufferRead(u8* pBuffer,u8 ReadAddr,u16 NumByteToRead)//读NumByteToRead个EPPROM的字节
  225. {
  226.         while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//等待BUSY = 0;
  227.        
  228.         I2C_GenerateSTART(I2C1,ENABLE);//产生一个开始信号
  229.        
  230.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//等待EV5
  231.        
  232.         I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);//发送一个外设地址
  233.        
  234.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待VE6;
  235.        
  236.         I2C_Cmd(I2C1,ENABLE);//使能外设
  237.        
  238.         I2C_SendData(I2C1,ReadAddr);//发送一个数据(这个就是你要读的数据的地址)
  239.        
  240.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8
  241.        
  242.         I2C_GenerateSTART(I2C1,ENABLE);//发送一个开始信号
  243.        
  244.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
  245.        
  246.         I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Receiver);//发送一个数据,加一个方向(这个就是读的方向)
  247.        
  248.         while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6
  249.        
  250.         while(NumByteToRead)//剩下的就是读数据了
  251.         {
  252.                 if(NumByteToRead == 1)//只有当最后一个数据的时候,才不会去应答,其他读的数据的时候需要去应答
  253.                 {
  254.                         I2C_AcknowledgeConfig(I2C1,DISABLE);//最后一个传输的数据不需要响应
  255.                         I2C_GenerateSTOP(I2C1,ENABLE);
  256.                 }
  257.                 if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))//EV7
  258.                 {
  259.                         *pBuffer = I2C_ReceiveData(I2C1);
  260.                         pBuffer++;
  261.                         NumByteToRead--;
  262.                 }
  263.         }
  264.         I2C_AcknowledgeConfig(I2C1,ENABLE);//把硬件自动应答打开
  265. }



  266. void I2C_EE_WaitEepromStandbyState(void)
  267. {
  268.         vu16 SR1_Tmp = 0;
  269.         do
  270.         {
  271.                 I2C_GenerateSTART(I2C1,ENABLE);//产生一个开始的信号;
  272.                
  273.                 SR1_Tmp = I2C_ReadRegister(I2C1,I2C_Register_SR1);//
  274.                
  275.                 I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);
  276.         }
  277.         while(!(I2C_ReadRegister(I2C1,I2C_Register_SR1) & 0x0002));//这个是判断你发送的数据成功没成功
  278.        
  279.        
  280.         I2C_ClearFlag(I2C1,I2C_FLAG_AF);//清除应答错误标志位
  281.        
  282.         I2C_GenerateSTOP(I2C1,ENABLE);
  283. }

  284. void I2C_Test(void)
  285. {
  286.         u16 i;
  287.         u8 I2c_Buf_Write[256];
  288.         u8 I2c_Buf_Read[256];
  289.        
  290.         printf("写入数据\n\r");
  291.        
  292.         for(i=0;i<=255;i++)
  293.         {
  294.                 I2c_Buf_Write[i] = i;
  295.                 printf("0x%02X ",I2c_Buf_Write[i]);
  296.                 if(i%16 == 15)
  297.                 {
  298.                         printf("\n\r");
  299.                 }
  300.         }
  301.         I2C_EE_BufferWrite(I2c_Buf_Write,EEP_Firstpage,256);
  302.        
  303.         printf("\n\r读出的数据\r\n");

  304.   I2C_EE_BufferRead(I2c_Buf_Read,EEP_Firstpage,256);
  305.        
  306.         for(i=0;i<256;i++)
  307.         {
  308.                 if(I2c_Buf_Read[i] != I2c_Buf_Write[i])
  309.                 {
  310.                         printf("0x%02X ",I2c_Buf_Read[i]);
  311.                         printf("错误:I2C EEPROM写入与读出数据不一样\r\n");
  312.                         return;
  313.                 }
  314.                 printf("0x%02X ",I2c_Buf_Read[i]);
  315.                 if(i%16 == 15)
  316.                 {
  317.                         printf("\r\n");
  318.                 }
  319.         }
  320.         printf("读写测试通过PASSED\r\n");
  321. }


复制代码
这里主要用的东西在这里我给大家贴上(不知道为什么,今天想偷点懒)



IIC的引脚

IIC的引脚

IIC的时钟树

IIC的时钟树

GPIO模式

GPIO模式



BA0P8T5`C`{WOOPK3YYU[}H.png L_I2_1MXWP7C}G%BQB1OFTP.png TG9$ZADE1667{EV3V`BH.png

这个对应上边的写和读的EV5之类的东西

这个对应上边的写和读的EV5之类的东西

先这样吧,确实有点懒了,但是基本上都全了,代码在附件上,大家可以看看,有什么错误之处还请指出,毕竟不是很熟悉。大家将就着看吧。 IIC.rar (5.29 MB, 下载次数: 1341)
1 收藏 3 评论11 发布时间:2017-7-16 22:08

举报

11个回答
zero99 回答时间:2017-7-17 10:35:35
谢谢分享啦
五哥1 回答时间:2017-9-26 12:29:20
谢谢分享啦
ctang 回答时间:2017-9-26 13:45:41
有不有I2C做slave的代码?这个代码相对比较难写。
laigs218 回答时间:2018-4-15 17:21:56
硬件IIC读写AT24C02
谢谢分享啦
栾小建 回答时间:2018-5-24 08:47:32
太给力了,谢谢分享
Habsburg 回答时间:2018-7-4 14:50:29
谢谢分享
大陶 回答时间:2018-8-29 16:41:10
谢谢分享 学习一下
Vincent-396829 回答时间:2018-9-21 11:02:01
谢谢分享
w12358 回答时间:2018-11-19 11:27:51
HAODE
网络孤客 回答时间:2018-11-19 13:32:34
能否再进一步,采用DMA方式?
mingchrb 回答时间:2019-6-19 16:16:45
谢谢分享,学习学习

所属标签

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