OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3312|回复: 15

外部EEprom存储总是出错怎么办?

[复制链接]

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
发表于 2018-1-11 17:35:33 | 显示全部楼层 |阅读模式
2金钱
应该是存储时被优先级高的中断打断了!!!可是要怎么解决这个问题??

引脚时钟已经开启。存储程序是不是有问题?延时10ms会不会太长?但是没有延时肯定更存不住。。。

*******************************************************************************/
void I2C_InitCfg(void)
{
       
        I2C_SCL_H;
        I2C_SDA_H;
}


/*******************************************************************************
**Function Name:
**Description  :  SDA也可以作发送数据,,
*******************************************************************************/
void I2C_SDA_OUT(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;       
       
        GPIO_InitStructure.GPIO_Pin=I2C_SDA;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
}


/*******************************************************************************
**Function Name:
**Description  :  也可以接收数据
*******************************************************************************/
void I2C_SDA_IN(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;       
       
        GPIO_InitStructure.GPIO_Pin=I2C_SDA;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//配置成上拉,如果板子上没有把这两根线上拉的话。
        GPIO_Init(GPIOB,&GPIO_InitStructure);
}


/*******************************************************************************
**Function Name:
**Description  :  产生起始信号
*******************************************************************************/

void I2C_Start(void)
{
    I2C_SDA_OUT();
       
        I2C_SDA_H;
        I2C_SCL_H;
        delay_us(5);
        I2C_SDA_L;
        delay_us(6);
        I2C_SCL_L;
}


/*******************************************************************************
**Function Name:
**Description  : 产生停止信号
*******************************************************************************/

void I2C_Stop(void)
{
   I2C_SDA_OUT();

   I2C_SCL_L;
   I2C_SDA_L;
   I2C_SCL_H;
   delay_us(6);
   I2C_SDA_H;
   delay_us(6);
}


/*******************************************************************************
**Function Name:
**Description  : 主机产生应答信号ACK
*******************************************************************************/

void I2C_Ack(void)
{
   I2C_SCL_L;
   I2C_SDA_OUT();
   I2C_SDA_L;
   delay_us(2);
   I2C_SCL_H;
   delay_us(5);
   I2C_SCL_L;
}


/*******************************************************************************
**Function Name:
**Description  :  主机不产生应答信号NACK
*******************************************************************************/

void I2C_NAck(void)
{
   I2C_SCL_L;
   I2C_SDA_OUT();
   I2C_SDA_H;
   delay_us(2);
   I2C_SCL_H;
   delay_us(5);
   I2C_SCL_L;
}

/*******************************************************************************
**Function Name:
**Description  :  等待从机应答信号?
*******************************************************************************/
u8 I2C_Wait_Ack(void)
{
        u8 tempTime=0;

        I2C_SDA_IN();

        I2C_SDA_H;
        delay_us(1);
        I2C_SCL_H;
        delay_us(1);

        while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA)) //SDA变成低电平的时候,才会给一个应答,如果读到为0说明给反馈信号了。
        {
                tempTime++; //计数器,如果没有应答不能在这里一直等。
                if(tempTime>250)
                {
                        I2C_Stop();
                        return 1;
                }         
        }

        I2C_SCL_L;
        return 0;
}

/*******************************************************************************
**Function Name:
**Description  : I2C 发送一个字节
*******************************************************************************/
void I2C_Send_Byte(u8 txd)
{
        u8 i=0;

        I2C_SDA_OUT();
        I2C_SCL_L;//拉低时钟开始数据传输

        for(i=0;i<8;i++)
        {
                if((txd&0x80)>0) //0x80  1000 0000 即发送数据时为1就执I2C_SDA_H。否则发个低电平。高位开始先发送
                        I2C_SDA_H;
                else
                        I2C_SDA_L;

                txd<<=1;
                I2C_SCL_H;//为高电平时才能真正的发送。
                delay_us(2); //发送数据
                I2C_SCL_L;  //准备下一次发送
                delay_us(2);
        }
}


void AT24Cxx_WriteTwoByte(u16 addr,u16 dt)
{
        I2C_Start();

        if(EE_TYPE>AT24C16)
        {
                I2C_Send_Byte(0xA0);
                I2C_Wait_Ack();
                I2C_Send_Byte(addr>>8);        //发送数据地址高位
        }
        else
        {
           I2C_Send_Byte(0xA0+((addr/256)<<1));//器件地址+数据地址
        }

        I2C_Wait_Ack();
        I2C_Send_Byte(addr%256);//双字节是数据地址低位               
                                //单字节是数据地址低位
        I2C_Wait_Ack();

        I2C_Send_Byte(dt>>8);
        I2C_Wait_Ack();

        I2C_Send_Byte(dt&0xFF);//发低8位这字节数据,发完后就停止。
        I2C_Wait_Ack();

        I2C_Stop();

        delay_ms(10);
}




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

50

主题

1805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6662
金钱
6662
注册时间
2016-5-29
在线时间
910 小时
发表于 2018-1-11 17:54:34 | 显示全部楼层
外部EEPROM I2C通信根本不怕被中断打断.楼主还是在其它的方面下功夫研究一下吧.
回复

使用道具 举报

2

主题

685

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3448
金钱
3448
注册时间
2017-7-4
在线时间
869 小时
发表于 2018-1-11 18:09:02 | 显示全部楼层
http://blog.csdn.net/qq_20553613/article/details/78878211
400Khz的中断依然正常读写。模拟i2c
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2018-1-12 09:32:09 | 显示全部楼层
1、所有的delay_us全部改为delay_us(5),最后那个delay_ms(10);去掉2、直接逻辑分析仪抓波形进行分析
回复

使用道具 举报

70

主题

6763

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
13129
金钱
13129
注册时间
2012-11-26
在线时间
3814 小时
发表于 2018-1-12 09:40:46 | 显示全部楼层
同八度所言,你的时序应该错了
学无止境
回复

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
 楼主| 发表于 2018-1-12 16:53:16 | 显示全部楼层
八度空间 发表于 2018-1-12 09:32
1、所有的delay_us全部改为delay_us(5),最后那个delay_ms(10);去掉2、直接逻辑分析仪抓波形进行分析

看了原子的例程,里面的延时也是不统一的。要是说时序,其实我倒还真没有仔细研究.....
不过刚才改了改,改成了delay_us(5),去掉了最后的那个delay_ms(10)试了一下,效果不是很明显,还是只能存一两个数,其它的都没存在。
我原程序中是连续存10个2字节数据,但总是不能全部存对,存对的那几个位置也不固定。后来我把存储函数连续执行两遍,目前测试还是100%都能存住的....但这个解决方案让我很无语。。。
回复

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
 楼主| 发表于 2018-1-12 16:58:24 | 显示全部楼层
八度空间 发表于 2018-1-12 09:32
1、所有的delay_us全部改为delay_us(5),最后那个delay_ms(10);去掉2、直接逻辑分析仪抓波形进行分析

还有一点我没有明白:
例程上给出的是PC11 PC12脚,然后输入时配成了上拉输入,输出时配成了复用开漏输出。
然而我若用了复用开漏输出模式,那我不但存不住,连读取都有问题了!

我的硬件是pb6 pb7,只有当配成通用推挽输出时,虽然不保证肯定能写进去,但至少能读写,而且读一般都是没有问题的。

为什么我不能配成复用开漏输出?不都是模拟I2C模式么?
回复

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1769
金钱
1769
注册时间
2015-6-11
在线时间
313 小时
发表于 2018-1-14 10:39:27 | 显示全部楼层
iic接口要加外部上拉电阻,不然读写某些器件会数据丢失
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2018-1-14 19:18:48 | 显示全部楼层
嘴角的上弦月 发表于 2018-1-12 16:58
还有一点我没有明白:
例程上给出的是PC11 PC12脚,然后输入时配成了上拉输入,输出时配成了复用开漏输 ...

复用开漏输出,你确定是这样用的么,你又没使用复用功能
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2018-1-14 19:22:01 | 显示全部楼层
嘴角的上弦月 发表于 2018-1-12 16:53
看了原子的例程,里面的延时也是不统一的。要是说时序,其实我倒还真没有仔细研究.....
不过刚才改了 ...

你所控制的器件一页存储多少个字节,这个要搞清楚,eeprom进行也写的时候,一次性发送的字节数不能超过它一页所能缓存的最大值,否则就出错,记得是覆盖之前的
比如eeprom一页最大8字节缓存,你一次性写入10个字节
00 01 02 03 04 05 06 07 08 09比如你存入这几个字节
08 09 02 03 04 05 06 07实际存入的是这几个字节,约摸记得是这样的,你可以实验以下
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-1-14 21:02:19 | 显示全部楼层
操作系统 发表于 2018-1-11 17:54
外部EEPROM I2C通信根本不怕被中断打断.楼主还是在其它的方面下功夫研究一下吧.

这种没有用外设实现,而是用主程序实现的的I2C通信应该是很容易被中断打断的吧!
回复

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
 楼主| 发表于 2018-1-15 08:27:50 | 显示全部楼层
zc123 发表于 2018-1-14 10:39
iic接口要加外部上拉电阻,不然读写某些器件会数据丢失

实际硬件上是有上拉的,所以程序中配置成了上拉输入、推挽输出模式
回复

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
 楼主| 发表于 2018-1-15 09:23:00 | 显示全部楼层
八度空间 发表于 2018-1-14 19:18
复用开漏输出,你确定是这样用的么,你又没使用复用功能

上周查资料,感觉查的全是开漏输出配置。刚才看你这么一反问,我又回头仔细看了看例程....
(⊙o⊙)… 好吧,是我看错了,
//初始化IIC
void IIC_Init(void)
{                                             
        GPIO_InitTypeDef GPIO_InitStructure;
        //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOC, ENABLE );       
          
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
}

我应该是下面这句,当时分析错了
//IO方向设置
#define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}//上拉输入
#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}//输出模式


这个问题不纠结了,确实是通用推挽输出。
回复

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
 楼主| 发表于 2018-1-15 09:26:27 | 显示全部楼层
八度空间 发表于 2018-1-14 19:22
你所控制的器件一页存储多少个字节,这个要搞清楚,eeprom进行也写的时候,一次性发送的字节数不能超过它 ...

其实,我是连续执行了十几次  AT24Cxx_WriteTwoByte(u16 addr,u16 dt) 写两个字节的操作。
这个应该不存在缓存区超的情况吧?
回复

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
 楼主| 发表于 2018-1-15 09:30:04 | 显示全部楼层
jinfeihan57 发表于 2018-1-14 21:02
这种没有用外设实现,而是用主程序实现的的I2C通信应该是很容易被中断打断的吧!

出错的本质原因,到现在也没确定。
不过,之前有一个2字节数据经常存储错误,所以在执行存这个数据的时候,关闭了最频繁的一个定时器,倒确实能存住这个数据了。但现在要连着存储十几个数据,一直关闭这个定时器也不现实,而且即使关闭了,效果也不是太明显了。
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2018-1-15 12:31:38 | 显示全部楼层
嘴角的上弦月 发表于 2018-1-15 09:30
出错的本质原因,到现在也没确定。
不过,之前有一个2字节数据经常存储错误,所以在执行存这个数据的时 ...

最直接的办法就是逻辑分析仪抓取波形看下,这样比较直观,我调试都会抓波形看下 QQ截图20180115123044.png
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-19 15:49

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表