历史上的今天
返回首页

历史上的今天

今天是:2025年08月14日(星期四)

正在发生

2019年08月14日 | 基于STM32F103的GPIO模拟I2C操作AT24C02S-ST E2prom调试日志

2019-08-14 来源:eefocus

基于STM32F103的GPIO模拟I2C操作E2prom芯片AT24C02S-ST:



1、硬件环境初始化:Stm32管脚配置,管脚操作


typedef  struct _PIN_CFG

{

    GPIO_TypeDef *Port;

    uint16_t  Pin;

 

} PIN_CFG;

 

typedef  struct _E2PROM_CFG

{

    PIN_CFG SCL;

    PIN_CFG SDA;

} E2PROM_CFG;

 

E2PROM_CFG  E2prom_Cfg;

//初始化

void E2prom_Chip_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

 

    /*SCL*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

 

    /*SDA*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

 

    E2prom_Cfg.SCL.Port = GPIOB;

    E2prom_Cfg.SCL.Pin = GPIO_Pin_9;

 

    E2prom_Cfg.SDA.Port = GPIOB;

    E2prom_Cfg.SDA.Pin = GPIO_Pin_8;

 

 

    if(E2prom_Check() != TRUE)

    {

        System_State.bit_st  |= SYS_E2PROM;

        System_State.E2prom_St = FALSE;

    }

}

//SDA管脚控制

void E2prom_SDA_Set(uint8_t st)

{

    if(st == HIGH)

    {

        GPIO_SetBits(E2prom_Cfg.SDA.Port, E2prom_Cfg.SDA.Pin);

    }

    else

    {

        GPIO_ResetBits(E2prom_Cfg.SDA.Port, E2prom_Cfg.SDA.Pin);

    }

}

 

//SCL管脚控制

void E2prom_SCL_Set(uint8_t st)

{

    if(st == HIGH)

    {

        GPIO_SetBits(E2prom_Cfg.SCL.Port, E2prom_Cfg.SCL.Pin);

    }

    else

    {

        GPIO_ResetBits(E2prom_Cfg.SCL.Port, E2prom_Cfg.SCL.Pin);

    }

}

 

uint8_t E2prom_SDA_Get(void)

{

    return GPIO_ReadInputDataBit(E2prom_Cfg.SDA.Port, E2prom_Cfg.SDA.Pin);

}

 

2、模拟I2C接口:


//启动I2C

void E2prom_I2C_Start(void)

{

    E2prom_SDA_Set(HIGH);

    DelayUs(5);

 

    E2prom_SCL_Set(HIGH);

    DelayUs(5);

 

    E2prom_SDA_Set(LOW); /* 根据I2C总线定义: SCL为高时, 数据由高跳变至低表示开始信号 */

    DelayUs(5);

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

}

 

/* 产生I2C停止信号 */

void E2prom_I2C_Stop(void)

{

    E2prom_SDA_Set(LOW);

    DelayUs(5);

 

    E2prom_SCL_Set(HIGH);

    DelayUs(5);

 

    E2prom_SDA_Set(HIGH);

    DelayUs(5);

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

}

//i2c发送一个字节

void E2prom_I2C_Send_Byte(uint8_t dat)

{

    uint8_t  i;

 

    for(i = 0; i < 8; i++)

    {

        E2prom_SCL_Set(LOW);

        DelayUs(5);

 

        if((dat & 0x80) == 0x80)

        {

            E2prom_SDA_Set(HIGH);

        }

        else

        {

            E2prom_SDA_Set(LOW);

        }

        dat <<= 1;

 

        E2prom_SCL_Set(HIGH);

        DelayUs(5);

    }

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

}

 

//i2c接收一个字节

uint8_t E2prom_I2C_Rcv_Byte(void)

{

    uint8_t  i;

    uint8_t  u8Temp = 0;

 

    E2prom_SDA_Set(HIGH);

 

    for(i = 0; i < 8; i++)

    {

        E2prom_SCL_Set(LOW);

        DelayUs(5);

 

        E2prom_SCL_Set(HIGH);

        DelayUs(5);

        u8Temp <<= 1;      //数据从高位开始读取

 

        if(E2prom_SDA_Get() == HIGH)

        {

            u8Temp++;

        }

    }

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

 

    return u8Temp;

}

//I2C主机应答

void E2prom_I2C_Ack(void)

{

    E2prom_SDA_Set(LOW);

    DelayUs(5);

 

    E2prom_SCL_Set(HIGH);

    DelayUs(5);

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

}

//I2C主机无应答

void E2prom_I2C_NoAck(void)

{

    E2prom_SDA_Set(HIGH);

    DelayUs(5);

 

    E2prom_SCL_Set(HIGH);

    DelayUs(5);

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

}

//检测从机应答

uint8_t E2prom_I2C_Check_Ack(void)

{

    uint8_t u8Temp;

 

    E2prom_SDA_Set(HIGH);

    DelayUs(5);

 

    E2prom_SCL_Set(HIGH);

    DelayUs(5);

 

    if(E2prom_SDA_Get() == LOW)

        u8Temp = 1;

    else

        u8Temp = 0;

 

    E2prom_SCL_Set(LOW);

    DelayUs(5);

 

    return u8Temp;

}

3、E2prom读写


// e2prom指定地址写入一个字节

void E2prom_Write_Byte(uint32_t addr, uint8_t dat)

{

    uint8_t  u8Temp = 0;

 

    if(addr > 0xFFFF)

    {

        u8Temp = 0x08;

    }

 

    E2prom_I2C_Start();

    E2prom_I2C_Send_Byte(0xA0 + ((addr / 256) << 1));

    if(E2prom_I2C_Check_Ack() != 1)

    {

        u8Temp = 0;

        return;

    }

    E2prom_I2C_Send_Byte(addr % 256);

    if(E2prom_I2C_Check_Ack() != 1)

    {

        return;

    }

    E2prom_I2C_Send_Byte(dat);

    if(E2prom_I2C_Check_Ack() != 1)

    {

        return;

    }

 

    E2prom_I2C_Stop();

    DelayUs(20000);

}

 

//从e2prom指定地址读出一个字节

uint8_t E2prom_Read_Byte(uint32_t addr)

{

    uint8_t  u8Temp = 0;

 

    if(addr > 0xFFFF)

    {

        u8Temp = 0x08;

    }

 

    E2prom_I2C_Start();

    E2prom_I2C_Send_Byte(0xA0 + ((addr / 256) << 1));

    if(E2prom_I2C_Check_Ack() != 1)

    {

        return 0;

    }

 

    E2prom_I2C_Send_Byte(addr % 256);

    if(E2prom_I2C_Check_Ack() != 1)

    {

        return 0;

    }

 

    E2prom_I2C_Start();

    E2prom_I2C_Send_Byte(CTRL_CODE | u8Temp | 0x01);

    if(E2prom_I2C_Check_Ack() != 1)

    {

        return 0;

    }

 

    u8Temp = E2prom_I2C_Rcv_Byte();

 

    E2prom_I2C_NoAck();

    E2prom_I2C_Stop();

 

    return u8Temp;

}

 

//向e2prom指定地址写入多个字节

void E2prom_Write_Mult_Byte(uint32_t addr, uint8_t *pdat, uint8_t cnt)

{

    uint8_t  i;

 

    for(i = 0; i < cnt; i++)

    {

        E2prom_Write_Byte(addr++, *pdat++);

    }

}

 

// 从e2prom指定地址读出多个字节

void E2prom_Read_Mult_Byte(uint32_t addr, uint8_t *pdat, uint8_t cnt)

{

    uint8_t  i;

    for(i = 0; i < cnt; i++)

    {

        pdat[i] = E2prom_Read_Byte(addr++);

    }

}

 

//读写测试

uint8_t  E2prom_Check(void)

{

    uint8_t  test_buf[E2PROM_CHECK_SIZE], check_buf[E2PROM_CHECK_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0xAA, 0x55 };

    memset(test_buf, 0, sizeof(test_buf));

    E2prom_Write_Mult_Byte(E2PROM_CHECK, check_buf, sizeof(check_buf));

    E2prom_Read_Mult_Byte(E2PROM_CHECK, test_buf, sizeof(test_buf));

    if(!memcmp(test_buf, check_buf, E2PROM_CHECK_SIZE))

        return TRUE;

    return FALSE;

}

调试中的问题;写入多个字节数据时,每写入后一个字节后至少10ms的延时,不能被其他线程打断,否则容易写入错误

推荐阅读

史海拾趣

Honda Tsushin Kogyo Co Ltd公司的发展小趣事

Honda Tsushin Kogyo Co. Ltd.的成立背景虽未详细公开,但考虑到其专注于电子连接器领域,可以推测该公司可能是在日本电子工业兴起的背景下成立的。在成立初期,公司可能面临了激烈的市场竞争和技术挑战。为了站稳脚跟,Honda Tsushin Kogyo致力于研发高质量的电子连接器产品,并逐步赢得了市场的认可。公司可能通过不断提升产品质量、优化生产工艺以及拓展销售渠道等方式,实现了初期的稳步发展。

G-Link Technology公司的发展小趣事

面对日益多样化的市场需求,蜂鸟无线敏锐地意识到定制化服务的重要性。公司开始提供根据客户需求量身定制的无线通信解决方案,这一举措迅速赢得了众多企业和个人的青睐。例如,某大型互联网公司需要为其全球分支机构部署稳定可靠的无线通信网络,蜂鸟无线凭借其在全球范围内的研发和销售网络,迅速响应并提供了个性化的解决方案,不仅满足了客户对通信质量的高要求,还大大缩短了项目周期,赢得了客户的高度赞誉。

Atmel (Microchip)公司的发展小趣事

Atmel(Microchip)一直注重技术创新和产品升级。公司不断投入研发资金,推动新产品的研发和现有产品的改进。通过引入新技术、优化产品设计等方式,Atmel的产品在性能、功耗、可靠性等方面都得到了显著提升。这些创新成果不仅满足了客户日益增长的需求,也为公司赢得了更多的市场份额。

统宇电研(Coilmaster)公司的发展小趣事

统宇电研公司成立于1995年,初创时期面临着重重挑战。当时,电子行业正值技术革新的关键时期,无源组件市场竞争激烈。统宇电研凭借对技术的敏锐洞察力和对市场趋势的准确判断,决定专注于高性能功率电感等无源组件的研发和生产。公司团队夜以继日地攻克技术难题,不断优化产品设计,最终成功推出了一系列具有竞争力的产品,为公司赢得了市场的认可。

Ericsson公司的发展小趣事

Ericsson公司在早期就非常注重市场拓展和全球布局。通过与各国电信运营商建立合作关系,Ericsson成功将其产品和服务推广到了全球各地。特别是在中国市场,Ericsson早在19世纪90年代就与中国签订了供货合同,成为中国通信网络建设的重要参与者。如今,Ericsson已经在中国扎根130余年,成为了唯一一家从1G到5G全程参与中国通信网络建设的企业。

Compound Photonics公司的发展小趣事

在Micro LED领域,Compound Photonics同样展现出了强大的实力。公司曾与Plessey合作开发Micro LED产品,双方的合作一度被业界看好。然而,就在合作即将取得突破时,Meta公司突然出手收购了Plessey的产能,使得Compound Photonics失去了一个重要的合作伙伴。面对这一突如其来的竞争压力,Compound Photonics不得不重新调整战略,寻找新的合作伙伴。

问答坊 | AI 解惑

全国大学生电子设计竞赛获奖作品精选1990~1994

本帖最后由 paulhyde 于 2014-9-15 03:18 编辑 超星图书下载    …

查看全部问答>

kline与TX RX的关系问题

我看到一个电路,发现当RX有信号时且不是也干扰到了TX了吗,怎么也不明白。往各位朋友能帮我解这个惑。…

查看全部问答>

ARM启动代码的比较与实现。

ARM启动代码的比较与实现。…

查看全部问答>

LabVIEW测量信号时间间隔的实现

LabVIEW测量信号时间间隔的实现 摘要 以两路信号为例, 详细阐述了以虚拟仪器方式, 针对不同种类的信号输入硬件板卡, 使用L abV IEW 软件平台实现信 号时间间隔测量的方法。详细解释了各种方法的特点、适用范围及具体实现。另外, 也根据具体的测 ...…

查看全部问答>

SD卡数据的读取

我想用FPGA来读取SD卡内的数据,那位大虾有现成的FPGA程序,共享一下!…

查看全部问答>

支持DirectShow的usb摄像头的接口是什么标准啊(不需要安装驱动)

如题:这种usb设备需要怎样通讯可让windows 自动识别为usb图像设备…

查看全部问答>

由于快递没到所以团购活动的maple开发板延误了

由于快递没到所以团购的maple开发板延误了预计明天会到…

查看全部问答>

请教一个BootLoader的问题

购买的EEWORLDC32SS开发板,CPU地址总线为32位,板载FLASH地址为0x0H-0x3ffffH,而BootLoader的地址为0h-0x0fffH,也就是说上电复位后,系统会从FLASH中读取程序,但现在FLASH的位数为16位,而DSP数据总线是32位,是不是这样就不可能上电自启动了呢 ...…

查看全部问答>

如何让51 记录下很多数据??

具体点是  现在有多个数据过来 比如说 一号灯亮 二号等亮 三号灭 四号灭 这些是不同个信号源发送过来的 这些都是同时发送给51  能不能让51  同时记录下来  记录后打包做好标记 然后不同时刻发送出去 !! ...…

查看全部问答>

DSP-Sitara课程进度一直是50%的请进!!!

进度一直是50%的同学,是不是每次点击的是上图中的片头,看完整个视频进度只有50%呢? 技术告诉我们,虽然说从片头可以直接学习课件。但是对系统来讲片头与课程是整个视频的两部分。所以,需要点一下“课程”。否则,系统会认为 “课程”这个部 ...…

查看全部问答>