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

硬件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, 下载次数: 1335)
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
太给力了,谢谢分享
kongxiaofuzi 回答时间:2018-7-4 14:50:29
谢谢分享
dataozi 回答时间:2018-8-29 16:41:10
谢谢分享 学习一下
Vincent-396829 回答时间:2018-9-21 11:02:01
谢谢分享
w12358 回答时间:2018-11-19 11:27:51
HAODE
12下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

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