|
在我们日常开发过程中,常用到EEPROM作为数据存储。今天我以AT24C32为例,给大家接一下EEPROM的使用。1、在我们编写代码前,需要先确定EEPROM的连接STM32的I2C接口。 2、我们需要确定EEPROM的设备地址,在技术手册中找到Device Address,如下图所示。我们介绍使用A2 A1 A0均连接到GND。因此我们使用的Device Address为0xA0。R/W这一位由我们操作I2C读写时再填入。
3、确定EEPROM的内部地址访问规则,如下图所示,AT24C32的访问地址为16位,我们在发送start信号以后,需要连续写入两个字节的地址,再进行后续操作。需要确定2字节的内容存储的格式:AT24C32的页最大容量为32byte,bit0-4用来存写入页内地址,bit5-11填写页地址。比如访问AT24C32的地址为:35,输入页地址为addr=35%32 | ((uint16_t)(35/32)<<5)。换算后的结果为0x0023。
4、EEPROM写时序如下图,通过时序图我们确定写入是,需要先写入硬件地址0xA0,再写入两字节页内地址,后面写入的是数据内容。注意数据内容长度要小于等于32-页内起始地址。2 k; }& }( {. ~5 }* R8 a
5、EEPROM读时序如下图,通过时序图我们发现,读写操作是不一样的。读操作需要先写入设备地址,两字节页地址后,需要重新发送一个读取的start信号,然后就可以读取数据了。读数据时不需要考虑读的长度,但也不能超出EEPROM的范围。* D: G( f% ?* E3 o+ V% [5 `
6、结合上面的介绍,我们来看一下EEPROM的代码操作。首先我们需要对I2C进行初始化,初始化时需要考虑I2C的复用功能,407和103的使用方法不同,需要注意。我们以407为例,代码初始化如下所示: /* Peripheral clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);6 A; i% B2 P/ P( c- o /**I2C2 GPIO Configuration3 n* `& R4 h5 J PB8 ------> I2C1_SCL PB9 ------> I2C1_SDA$ f5 o# @9 Z$ X, b3 m6 o */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);7 T" n. i/ `3 C B' F" w" | GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);8 e' Z" ` F1 x( E J 4 R$ H) D+ h3 D, L /*!< Configure I2C2 pins: SCL,SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;; I7 j# V* o% A7 { GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;% A0 i, G8 H3 M4 `; M GPIO_Init(GPIOB, &GPIO_InitStructure);1 Y) b5 X& j8 e Std_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);: {2 s1 H L5 |: {+ o Std_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);7、读操作代码1 W! D8 u- q1 j" B( g- ?+ U - L1 h0 M& {3 U) `) T* L$ _- v while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE);: T! K) s- T, x* n$ o7 d: K while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5: \! Y5 W ?5 v ' ]; ]* l1 Q, \- l) F8 g5 M I2C_Send7bitAddress(I2C1, addr_dev, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 . m- {+ i% j# T/ J0 U- k I2C_SendData(I2C1,addr>>8]); t+ F; }6 t! o: m5 ^ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));//EV8 I2C_SendData(I2C1, addr); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);//EV8 I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5! g2 F: E; n4 @4 q1 d9 S : \2 K5 V# r1 z% [5 I9 K I2C_Send7bitAddress(I2C1, addr_dev|0x01, I2C_Direction_Receiver);4 z" b# _! m, O9 E" d while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6 while(Num --> 1)8 P$ B1 W, R* j4 R% J {. T7 p/ l _# z, x while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);" J) b; Q2 T7 _6 d% d4 k *pBuffer++ = I2C_ReceiveData(I2C1); }9 \9 K4 @2 `# ^% @3 A I2C_AcknowledgeConfig(I2C1, DISABLE);( d# m0 q" Q2 E. W3 N; M% A I2C_GenerateSTOP(I2C1, ENABLE); while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);- J1 _. O0 m+ {$ {' y9 K *pBuffer++ = I2C_ReceiveData(I2C1);) B5 z( z, e0 h4 I. A2 L; m / G) `) |+ m W( P 8、写操作代码 while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 3 S% V7 L. n& P2 q/ W. h+ p, d I2C_Send7bitAddress(I2C1, addr_dev, I2C_Direction_Transmitter);: ~9 F M; E5 M2 X while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 (void)I2C1->SR1;//EV6- M2 |. @. l9 ^% R( I I2C_SendData(I2C1, addr>>8]); //EV8-1 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 I2C_SendData(I2C1, addr);5 [; W) i: E5 Y& H2 M) M while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV86 p- d6 m2 q+ U R1 p while(Num-->0) { I2C_SendData(I2C1,*pBuffer++); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8# R! b- }' W @' F% G, R } I2C_GenerateSTOP(I2C1,ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //EV8-2 $ `# n! E- Y2 @+ j+ I + z% n3 e n* ~3 c: _ : B/ P# L2 z1 |+ f! A2 \* d % j0 a2 y) T+ u2 G8 t" g. I+ I ; H+ E3 d8 b$ t' d6 r* O1 O' g0 W) B |
【NUCLEO-WBA65RI评测】物联网 LED
【NUCLEO-WB09KE评测】使用I2C点亮一个OLED
【NUCLEO-WB09KE评测】USART的printf和GPIO的使用
【STM32H7S78-DK评测】使用FatFs文件系统读取SD卡文件
【NUCLEO-H533RE评测】+04 串口中断使用心得
【NUCLEO-H533RE评测】+03 printf输出调试
传感器为什么需要智能?
关于STM32的SWD引脚错误配置,“No Target Connected”导致程序不能下载问题解决
【年中粉丝节】+18B20温度传感器
【年中粉丝节】STM32L476开发板-基于rtthread读取加速度传感器KX224数据
微信公众号
手机版