历史上的今天
返回首页

历史上的今天

今天是:2025年05月20日(星期二)

正在发生

2018年05月20日 | STM32F407之模拟I2C(二)之24C128

2018-05-20 来源:eefocus

模拟I2C测试24C128的读写

#define GPIO_PORT_I2C GPIOH/* GPIO端口 */

#define I2C_SCL_PIN GPIO_Pin_4/* 连接到SCL时钟线的GPIO */
#define I2C_SDA_PIN GPIO_Pin_5/* 连接到SDA数据线的GPIO */
/* 定义读写SCL和SDA的宏 */
#define I2C_SCL_1()  GPIO_PORT_I2C->BSRRL = I2C_SCL_PIN/* SCL = 1 */
#define I2C_SCL_0()  GPIO_PORT_I2C->BSRRH = I2C_SCL_PIN/* SCL = 0 */


#define I2C_SDA_1()  GPIO_PORT_I2C->BSRRL = I2C_SDA_PIN/* SDA = 1 */
#define I2C_SDA_0()  GPIO_PORT_I2C->BSRRH = I2C_SDA_PIN/* SDA = 0 */


#define I2C_SDA_READ()   GPIO_ReadInputDataBit(GPIOH,GPIO_Pin_5)/* 读SDA口线状态 */
#define I2C_SCL_READ()    GPIO_ReadInputDataBit(GPIOH,GPIO_Pin_4)/* 读SCL口线状态 */
/****************************************************************************************
*函 数 名:bsp_InitI2c
*函数功能:初始化i2c的io
*形    参:无
*返 回 值:无
*****************************************************************************************/
void bsp_InitI2c(void)
{
GPIO_InitTypeDef GPIO_initStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH,ENABLE);

GPIO_initStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_initStructure.GPIO_OType = GPIO_OType_OD;
GPIO_initStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_initStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_initStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOH,&GPIO_initStructure);
}


/****************************************************************************************
*函 数 名:i2c_Delay
*函数功能:延时
*形    参:无
*返 回 值:无
*****************************************************************************************/
static void i2c_Delay(void)
{
uint8_t i=0;
for(i = 0; i < 30; i++);
}


/****************************************************************************************
*函 数 名:i2c_start
*函数功能:开始信号  
*形    参:无
*返 回 值:无
*****************************************************************************************/
void i2c_start(void)
{
I2C_SCL_0();/*SCL为高电平,SDA由高到低的跳变 就是开始信号*/
i2c_Delay();
I2C_SDA_1();
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/****************************************************************************************
*函 数 名:i2c_stop
*函数功能:结束
*形    参:无
*返 回 值:无
*****************************************************************************************/
void i2c_stop(void)
{
I2C_SCL_0();/*SCL在高电平期间,SDA由低到高的跳变 就是停止信号*/
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_1();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/****************************************************************************************
*函 数 名:i2c_WaitAck
*函数功能:从器件应答
*形    参:无
*返 回 值:1 从器件应答
*****************************************************************************************/
uint8_t i2c_WaitAck(void)
{
uint8_t re;
uint16_t i=0;/*SCL为高电平 从器件把ASD拉低 称为从器件应答*/
I2C_SCL_0();
i2c_Delay();
I2C_SDA_1();
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
while(I2C_SDA_READ() && (i < 65530))/*防止从器件不应答 在这死等*/
{
i++;
}
if(i < 65530)/*小于65530 表示已经应答   具体i的值是多少我也不知道 这里只是大概*/
re = 1;
else
re = 0;
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
return re;
}
/****************************************************************************************
*函 数 名:i2c_Ack
*函数功能:主器件应答
*形    参:无
*返 回 值:无
*****************************************************************************************/
void i2c_Ack(void)
{
I2C_SCL_0();/*SCL为高电平 SDA为低电平表示主器件应答*/
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/****************************************************************************************
*函 数 名:i2c_NAck
*函数功能:主器件不应答
*形    参:无
*返 回 值:无
*****************************************************************************************/
void i2c_NAck(void)
{
I2C_SCL_0();/*SCL为高电平 SDA为低电平表示主器件非应答*/
i2c_Delay();
I2C_SDA_1();
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/****************************************************************************************
*函 数 名:i2c_SendByte
*函数功能:发送一个字节
*形    参:_ucByte 发送的字节
*返 回 值:无
*****************************************************************************************/
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
I2C_SCL_0();
for( i = 0; i < 8; i++)
{
if(_ucByte & 0x80)
I2C_SDA_1();
else
I2C_SDA_0();/*SCL上升沿将数据写入器件*/
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
_ucByte = _ucByte << 1;
}
I2C_SDA_1();/*释放数据线*/
i2c_Delay();

}
/****************************************************************************************
*函 数 名:i2c_ReadByte
*函数功能:读到的值
*形    参:无
*返 回 值:无
*****************************************************************************************/
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t value = 0;
I2C_SDA_1();/*释放数据线*/
for(i = 0; i < 8; i++)
{
value <<=1;
I2C_SCL_1();
i2c_Delay();
if(I2C_SDA_READ())/*读SDA*/
{
value = value + 1;
}
else
{
value = value;
}
i2c_Delay();/*SCL下降沿将数据取出*/
I2C_SCL_0();
i2c_Delay();
}
return value;

}

/*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************                                                                      上面主要是模拟I2C时序                                                                                                                                                                    ************                                                                      下面就是对24C128的读写操作

*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/

#define EE_MODEL_NAME "AT24C128"
#define EE_DEV_ADDR 0xA0/* 设备地址 */
#define EE_PAGE_SIZE 64/* 页面大小(字节) */
#define EE_SIZE (16*1024)/* 总容量(字节) */
#define EE_ADDR_BYTES 2/* 地址字节个数 */


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

uint8_t buf[EE_SIZE];
/****************************************************************************************
*函 数 名:eeprom_ReadBytes
*函数功能:eeprom读字节
*形    参:_pReadBuf 存放读取的数据  _usAddress 开始读取的地址  _usSize读取的大小
*返 回 值:1 表示读取成功  0 表示读取失败
*****************************************************************************************/


uint8_t eeprom_ReadBytes(uint8_t *_pReadBuf,uint16_t _usAddress,uint16_t _usSize)
{
uint16_t i;
/*第一步:发起I2C启动信号*/
i2c_start();
/*第二步:发送控制字节,高7位表示地址,最低位表示读写控制 0表示写 1表示读*/
i2c_SendByte(EE_DEV_ADDR | I2C_WR);
/*第三步:等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
/*第四步:发送读取的地址 24C128 要发送2次地址*/
i2c_SendByte(_usAddress >> 8);
/*等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
/*发送读取的地址 */
i2c_SendByte(_usAddress);
/*等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
/*第五步:重启I2C总线  之后开始读取数据*/
i2c_start();
/*第六步:发送控制字节 */
i2c_SendByte(EE_DEV_ADDR | I2C_RD);
/*等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
/*第七步:循环读取数据*/
for(i = 0; i < _usSize; i++)
{
_pReadBuf[i] = i2c_ReadByte();/*读一个字节*/
if( i != _usSize -1)/*不是最后一个主器件就要应带,是最后一个就主器件非应答*/
{
i2c_Ack();
}
else
{
i2c_NAck();
}
}
/*第八步:发送I2C停止信号*/
i2c_stop();

return 1;

}
/****************************************************************************************
*函 数 名:eeprom_ReadTest
*函数功能:读取整个24C128的数据
*形    参:无
*返 回 值:无
*****************************************************************************************/
void eeprom_ReadTest(void)
{
uint16_t i;
int32_t Time1,Time2;
Time1 = bsp_GetRunTime();/*获取开始时间*/

if(eeprom_ReadBytes(buf,0,EE_SIZE))/*1 读取成功 0读取失败*/
{
Time2 = bsp_GetRunTime();/*获取结束时间*/
printf("读eeprom成功\r\n");
}
else
{
printf("读eeprom出错\r\n");
}

for(i = 0;i < EE_SIZE ;i++)
{

if(i % 16 == 0)/*输出16个字节换行*/
{
printf("\r\n");
}
printf(" %02X",buf[i]);/*输出数据*/

}
printf("读耗时: %dms,读速度: %dB/s\r\n",Time2 - Time1,(EE_SIZE * 1000) / (Time2 - Time1));


}


/****************************************************************************************
*函 数 名:eeprom_WriteBytes
*函数功能:写整个eeprom测试
*形    参:_pWriteBuf 写入的值  _usAddress 写入的地址 _usSize写入的大小
*返 回 值:1 表示写入成功 0 表示写入失败
*****************************************************************************************/
uint8_t eeprom_WriteBytes(uint8_t *_pWriteBuf,uint16_t _usAddress,uint16_t _usSize)
{
uint16_t i,m;
uint16_t usAddr;
uint16_t num = 0;
usAddr = _usAddress;

for( i = 0; i< _usSize; i++)
{
/*写eeprom不可以像读那样连续读取多个字节,写每次只能在一个页page
24C128每也64个字节*/
if (num % 64 == 0)/*写入64个就要重新开始 因为每page为64*/
{
/*第一步:发送停止信号,启动内部写操作*/
i2c_stop();
/*通过循环判断eeprom内部写操作是否完成*/
for(m = 0; m < 100; m++)
{
/*第二步:发起I2C总线启动信号*/
i2c_start();
/*第三步:发起控制字节,高7位是地址,最低位 0表示写 1表示读*/
i2c_SendByte(EE_DEV_ADDR | I2C_WR);
/*第四步:等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() == 1)
{
break;
}
if(m >= 100)/*大于100表示从器件没有应答*/
{
return 0;
}
}
/*第五步:发送写入的地址 24C128 要发送2次地址*/
i2c_SendByte(usAddr >> 8);
/*等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
/*发送写入的地址*/
i2c_SendByte(usAddr);
/*等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
}
/*第六步:写入数据*/
i2c_SendByte(_pWriteBuf[i]);
/*等待从器件应答 1表示应答 0 表示没有应带*/
if(i2c_WaitAck() != 1)
{
return 0;
}
num++;
usAddr++;/*地址增1*/
}
/*发送停止信号*/
i2c_stop();
return 1;
}


/****************************************************************************************
*函 数 名:eeprom_WriteTest
*函数功能:写入数据
*形    参:无
*返 回 值:无
*****************************************************************************************/


void eeprom_WriteTest(void)
{
uint16_t i;
int32_t Time1,Time2;

for(i = 0; i < EE_SIZE; i++)
{
buf[i] = 0x01;/*填充要写入的数据*/
}
Time1 = bsp_GetRunTime();/*获取开始时间*/

if(eeprom_WriteBytes(buf,0,EE_SIZE))/*1 表示写入成功 0表示失败*/
{
Time2 = bsp_GetRunTime();/*获取结束时间*/
printf("写eeprom成功\r\n");
}
else
{
printf("写eeprom错误\r\n");
}

printf("写耗时: %dms,写速度: %dB/s\r\n",Time2-Time1,(EE_SIZE *1000)/(Time2-Time1));
}


/*********************************************************************************************************************************************************************************************************************************************        下面就是Main函数   ********************************************************************************************************/


/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形    参:无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ch;
/*
ST固件库中的启动文件已经执行了 SystemInit() 函数,该函数在 system_stm32f4xx.c 文件,主要功能是
配置CPU系统的时钟,内部Flash访问时序,配置FSMC用于外部SRAM
*/
bsp_Init();/*初始化I2C的IO*/
/* 进入主程序循环体 */
printf("1 - 读EEPROM (%d 字节)\r\n", EE_SIZE);
printf("2 - 写EEPROM (%d 字节,0x00-0xFF)\r\n", EE_SIZE);
while (1)
{
if(comGetChar(COM1,&ch))/*读取串口数据*/
{
switch(ch)
{
case '1':
eeprom_ReadTest();/*测试读数据*/
printf("\r\n");
break;
case '2':
eeprom_WriteTest();/*测试写数据*/
printf("\r\n");
break;
default:
break;
}
}
}
}


推荐阅读

史海拾趣

Britool Expert公司的发展小趣事

撰写5个关于电子行业里Britool Expert公司发展起来的相关故事,每个故事字数至少500字,可能内容过多,我可以为您提供1个故事的示例,如果需要更多故事,您可以在之后输入继续。


Britool Expert公司的发展故事之一:技术创新的突破

在电子行业的激烈竞争中,Britool Expert公司以其独特的技术创新策略脱颖而出。公司创立之初,就明确了以技术研发为核心的发展道路。在一次关键的技术研讨会上,公司的研发团队提出了一个前所未有的想法——开发一种新型的高效能芯片。

这个想法在当时看来极具挑战性,但团队成员们凭借着对技术的热爱和对市场的敏锐洞察,决心将这个想法变为现实。经过数月的艰苦努力,团队终于攻克了技术难关,成功研发出了这款芯片。这款芯片不仅性能卓越,而且成本大大降低,迅速在市场上获得了广泛的认可。

这一技术创新的突破,为Britool Expert公司打开了新的发展空间。公司借此机会,不断扩大生产规模,优化产品结构,逐渐在电子行业中树立了良好的口碑。随着技术的不断进步和市场的不断扩大,Britool Expert公司逐渐成为了电子行业中的佼佼者。

这个故事只是Britool Expert公司发展历程中的一个缩影。在公司的成长过程中,还有许多类似的技术创新故事。正是这些故事,构成了Britool Expert公司不断发展壮大的坚实基石。


若您想要探索更多内容,随时可以继续输入。

Anytek Technology Corporation Ltd公司的发展小趣事

随着技术实力的不断提升和市场份额的稳步增长,Anytek在2009年获得了“中国国际高新技术企业”的认定。这一荣誉不仅是对公司技术实力和创新能力的肯定,也为公司的未来发展提供了更广阔的空间和机遇。同年,Anytek还成功进入了俄罗斯政府采购项目,进一步扩大了公司的国际影响力。

Cortina Systems Inc公司的发展小趣事

为了进一步满足市场需求,Anytek在2005年投建了安尼泰科(中国)生产基地,并成功投产运营。这一举措不仅大幅提升了公司的生产能力,也为后续的产品研发和市场拓展奠定了坚实基础。同年,Anytek的产品还通过了SGS ISO 9001(2000)国际质量体系认证,这标志着公司的产品质量和管理水平达到了国际标准,为公司的国际化发展打开了新局面。

GAIA Converter Inc公司的发展小趣事

随着全球化进程的加速,锋鸣电子(上海总部)于2015年启动了国际化战略。公司首先在东南亚地区设立生产基地,利用当地的成本优势扩大产能。随后,锋鸣电子积极参加国际展会,拓展海外市场,与多家国际知名企业建立了合作关系。通过国际化战略的实施,锋鸣电子不仅提升了品牌知名度,还实现了销售收入的快速增长。

CalAmp公司的发展小趣事

CalAmp公司以其卓越的无线产品、设备和方案供应能力,赢得了业界的广泛认可。某年,CalAmp与全球知名的电子分销商Mouser签署了全球分销协议。这一合作使得Mouser能够备有CalAmp公司的一系列产品,如UHF和VHF收发器模块、遥感勘测模块以及适用于不同频带的无线通信装置。这些产品广泛应用于各种无线通信领域,其方便快速集成的特点大大加快了客户产品的上市时间,同时提供了性价比极高的无线解决方案。这一协议的签署不仅进一步巩固了CalAmp在全球无线产品市场的领导地位,也为Mouser带来了更多的业务机会。

德力康(DLK)公司的发展小趣事

作为一家有社会责任感的企业,DLK公司始终将社会责任和可持续发展作为企业发展的重要内容。公司积极参与公益事业和社会活动,为当地经济发展和社会进步做出了积极贡献。同时,DLK公司注重环保和节能工作,采用环保材料和生产工艺,减少了对环境的污染和破坏。通过履行社会责任和推动可持续发展,DLK公司赢得了社会的广泛认可和尊重。

请注意,以上故事框架仅供参考,具体的故事内容需要根据公司的实际情况和具体事件进行编写。

问答坊 | AI 解惑

『难题』tornado调试难题一个

目前一块板A上没有TCP/IP网络插口(也无串口连到外部),但是A和其他有TCP/IP网络插口的板B有内部网络相连,而板B已经连到了sever,可以用tornado调试,现在想调试A板,咋办?请教各位高招…

查看全部问答>

UFN驱动程序的Init函数是否创建了线程?

今天在看UFN_Init函数,一直找不到创建线程的函数,不知道是否有创建? UFN: USB Function Controller Driver(就是WinCE设备作为Client时的驱动)…

查看全部问答>

关于ARM更改SDRAM问题

我的ARM是2410的,,现在我将原来的两个64M SDRAM改为4个32M的SDRAM。请问软件如何设置呀,,须要怎么改呢…

查看全部问答>

连接C的liB库后Release版本出错 高人请进

  我有个MFC的程序,Release版本需要引用一个C的LIB库加密 InitInstance()初始化时只调用了这个库一个函数(而且这个库就提供了这一个接口),当我注释掉后,能顺利执行 如果不注释掉,程序一启动连WINAPP的构造函数都没进崩溃了&nbs ...…

查看全部问答>

coldfire V1核心与ARM CORTEX M3核心的对比!

这是飞思卡尔工程师的一个文档,通过试验详细对比了飞思卡尔coldfire v1核心的MCU与现在热炒的arm cortex m3。可以看出coldfire v1作为飞思卡尔coldfire系列中最低端的架构,与arm热闹的cortex m3比,丝毫不输于arm。特别有点比较有意思的,arm想来 ...…

查看全部问答>

STM8stvd编译如何生成可编程的bin文件或者hex文件

                                 急,请知者告知。谢谢先…

查看全部问答>

玩转MSP430 LaunchPad

很想玩玩MSP430 LaunchPad,可惜没有人教…

查看全部问答>

求BH1705光照传感器程序 (msp430)

求BH1705光照传感器程序 (msp430)~~~求高手帮忙…

查看全部问答>

warning: parsing restarts here after previous syntax error

warning: parsing restarts here after previous syntax error   遇到这个warning …

查看全部问答>

关于恒压源电源和恒流源电源的一些理解,,

电子产品电路设计,电路中总少不了关于恒压源电源和恒流源电源的话题,搞懂这两个源的问题,应该说很有必要,欢迎大家议论讨论,, 恒流亦可叫稳流,意思相近,一般可以不加区别。与恒压的概念相比,恒流的概念就难于理解一些了,因为日常生活中 ...…

查看全部问答>