历史上的今天
今天是:2025年07月21日(星期一)
2018年07月21日 | STM32之利用I2C协议读写EEPROM
2018-07-21 来源:eefocus
/*
名称:STM32之利用I2C协议读写EEPROM
说明:
1.利用STM32来读写EEPROM和C51最大的不同就是,前者是直接使用I2C控制器(硬件方式)来产生所需要的I2C时序,而后者是通过软件方式来产生I2C时序。相对来说,前者使用硬件电路简化了编程的复杂性,用户只要将数据发送到相应的数据寄存器,然后I2C控制器自动按照I2C协议把数据通过SCL和SDA总线发送出去。而后者,你必须按照I2C协议手动产生SCL和SDA的高低电平。当然对于EEPROM来说,它是感受不到发送来的数据是通过硬件电路还是软件方式产生的。
2.还有,STM32内部集成的I2C控制器不仅可以产生时序,还包括了一些其他的功能。比如说,相关的状态寄存器。当主设备或者从设备的相关状态发生改变的时候,就会自动把相关状态寄存器中相关的位置零或置一,这样我们就能通过检查状态寄存器的值来检查通信正处于什么状态。
相反的,如果使用软件产生的I2C时序方式,必须自己来判断正处于通信的何种状态。比如说,当主设备发送给从设备一个数据后,需要等待从设备的相应。对于STM32来说,若有从机应答,则产生事件“EV6”及“EV8”,这时 SR1 寄存器的“ADDR”位及“TXE”位被置 1, ADDR 为 1 表示地址已经发送, TXE 为 1 表示数据寄存器为空。 我们通过检查寄存器即可得知从设备是否应答。对于C51来说,我们必须手动检测返回的数据是0还是1来判断从设备是否应答。从这个角度来说,有了硬件控制器的帮助,软件编程变得简单不少。
但是,对于I2C来说,STM32封装的固件库网上有很多说有问题的,尤其是无缘故的卡死,还不如直接使用软件方式直接模拟。在编写这个开始程序时,我也有这个问题。一开始,我也以为是这个问题,后来才发现I2C忘了初始化了。嘿嘿。。。
3.还有一点,就是以前在编写C51的I2C驱动AT24C16时,有个不确定的地方:在连续读的时候,会不会产生页回滚的问题?今天又用STM32的方式试了一下,确实是和我当时想的一样。只有页写的时候会产生回滚的问题,页读的时候不会产生这个问题,它会一直读下去,直到到达整个地址边界。
*/
//I2C端口配置
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 打开IIC GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
// 打开IIC 外设的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 将IIC SCL和SDL的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_GPIO_PIN|EEPROM_I2C_SDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
// 配置IIC的工作参数
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;//使能应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit ;//使用7位地址模式
I2C_InitStructure.I2C_ClockSpeed = EEPROM_I2_BAUDRATE; //配置SCL时钟频率
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2 ;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ;
I2C_InitStructure.I2C_OwnAddress1 = STM32_I2C_OWN_ADDR; //这是STM32 IIC自身设备地址,只要是总线上唯一即可
I2C_Init(EEPROM_I2C,&I2C_InitStructure);
// 使能I2C
I2C_Cmd (EEPROM_I2C, ENABLE);
}
//主机向EEPROM写入一个字节
void EEPROM_Byte_Write(uint8_t addr,uint8_t data)
{
//产生起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);
//EV6事件被检测到,发送要操作的存储单元地址
I2C_SendData (EEPROM_I2C,addr);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR);
//EV8事件被检测到,发送要存储的数据
I2C_SendData (EEPROM_I2C,data);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
//数据传输完成
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
//向EEPROM写入多个字节(页写入),每次写入不能超过8个字节
void EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint8_t numByteToWrite)
{
//产生起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);
//EV6事件被检测到,发送要操作的存储单元地址
I2C_SendData (EEPROM_I2C,addr);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR);
while(numByteToWrite)
{
//EV8事件被检测到,发送要存储的数据
I2C_SendData (EEPROM_I2C,*data);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
data++;
numByteToWrite--;
}
//数据传输完成
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
/*等待EEPROM内部时序完成:其基本的原理是重新发送一个起始信号和设备地址,
如果从设备响应了,那么说明写操作完成*/
void EEPROM_WaitForWriteEnd(void)
{
do
{
//产生起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_SB) == RESET);
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
} while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_ADDR) == RESET );
//EEPROM内部时序完成传输完成
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
}
//从EEPROM读取数据
void EEPROM_Read(uint8_t addr,uint8_t *data,uint8_t numByteToRead)
{
//产生起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);
//EV6事件被检测到,发送要操作的存储单元地址
I2C_SendData (EEPROM_I2C,addr);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR);
//第二次起始信号
//产生起始信号
I2C_GenerateSTART(EEPROM_I2C,ENABLE);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
//EV5事件被检测到,发送设备地址
I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Receiver);
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR);
while(numByteToRead)
{
//EV7事件被检测到
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR);
//EV7事件被检测到,即数据寄存器有新的有效数据
*data = I2C_ReceiveData(EEPROM_I2C);
data++;
numByteToRead--;
if(numByteToRead == 0) //如果为最后一个字节
I2C_AcknowledgeConfig(EEPROM_I2C,DISABLE); //发送非响应位
else
I2C_AcknowledgeConfig (EEPROM_I2C,ENABLE); //发送响应位
}
//数据传输完成
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
// //重新配置ACK使能,以便下次通讯
I2C_AcknowledgeConfig (EEPROM_I2C,ENABLE);
}
史海拾趣
|
今 天碰到一个客服的同事问我电源寿命的问题,当时很轻易的把她搪塞过去了。事后仔细一想,有以下几点疑问,想请大侠们探讨下,请不吝赐教: 1;任何物体都是有寿命的!只是长短的区别!对于电源这块,寿命最长的,我认为是磁性材料, ...… 查看全部问答> |
|
先说一下我的平台,硬件是s3c6410,系统wince6.0,OpenGL ES版本1.1,三星提供的dll。 现在说一下问题,我画了几张图,发现远的和近的一样大,没有\"近大远小\"的感觉。查了些资料说是应该要采用\"透视模式\"的投影方式,需要用到这样的一个API ...… 查看全部问答> |
|
RT 小弟最近要把9054的datasheet吃透,但是有些问题不明白,希望各位大侠帮忙回答一下 1.9054的基地址0~1用于内存映射和I/O映射,基地址2~5用作本地地址空间0~3,后面Local寄存器又说明本地空间可以映射到I/O或者内存中,用I/O活内存操作,纳秒这 ...… 查看全部问答> |
|
现阶段节能已经成为一种硬性的要求,不是一种选择,而其中一部分需要采用环保绿色的方式去实现节能。对于照明来说,我们可以很容易的设想全球照明提高10%的效率后所带来的影响,但是提高100%呢?最近高效率发光二极管(LED)可能实现这种效率的改进, ...… 查看全部问答> |
|
TI推出业界首款支持集成型MOSFET 的100V同步降压稳压器LM5017 最新系列高集成引脚兼容型 IC 可缩小 PCB 面积,提高高电压应用的可靠性日前,德州仪器 (TI) 宣布推出业界首款支持集成型 MOSFET 的100 V 同步降压稳压器,进一步壮大其高电压负载点产品阵营。该600 mA LM5017是最新系列降压开关稳压器中 ...… 查看全部问答> |
|
任务由stm32 ADC2采集数据后存入sd卡里面(不用DMA),我修改了下两个程序,第一:3ADCs_DMA删除部分程序只用ADC2,第二:Ex013-SDIO+FatFS删除部分程序。然后合并两程序。。。可是不对。好像ADC转换的数据存入的变量要申明成全局变量,不懂怎么设 ...… 查看全部问答> |
|
ADuC7060的IO引脚确实太少了,想多带个东西就很麻烦 突然想到GND_SW在手册上说是用于和内部模拟地相连的,对于模拟地和数字地相接的电路来说,如果将它作为象电源开关用途的、低速控制,应该没有问题吧?… 查看全部问答> |




