OpenEdv-开源电子网

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

ATC2402 IIC连续读写的问题

[复制链接]

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2017-8-22
在线时间
29 小时
发表于 2017-9-16 22:15:00 | 显示全部楼层 |阅读模式
3金钱
STM32软件IIC与AT24C02通信
程序运行开始先读取三个时间值
static u8 g_second = 0, g_minute = 0, g_hour = 0;

static void InitData(void)
{       
        g_hour   = IICGet()->ReadByte(100);
        g_minute = IICGet()->ReadByte(101);
        g_second = IICGet()->ReadByte(102);
       
        printf("%d ", g_hour);
        printf("%d ", g_minute);
        printf("%d ", g_second);
        printf("\r\n");
}


定时器每秒钟向AT24C02写三个时间值
void Timer1_Callback(void *p_tmr, void *p_arg)
{
        CPU_SR_ALLOC();
        OS_CRITICAL_ENTER();
       
        g_second++;
        if(g_second >= 60)
        {
                g_second = 0;
                g_minute++;
        }
        if(g_minute >= 60)
        {
                g_second = 0;
                g_hour++;
        }
        if(g_hour >= 24)
        {
                g_hour = 0;
        }       
       
        IICGet()->WriteByte(100, g_hour);       
        IICGet()->WriteByte(101, g_minute);       
        IICGet()->WriteByte(102, g_second);       
       
        OLEDFun()->ShowNumber(48, 0, 2, g_hour);
        OLEDFun()->ShowNumber(72, 0, 2, g_minute);
        OLEDFun()->ShowNumber(96, 0, 2, g_second);
       
        OS_CRITICAL_EXIT();       
}


每次STM32复位后,发现g_hour、g_second读写都是对的,g_minute读写不成功,每次都为0,多次测试发现连续读写都是第一个成功,第二个不成功,第三个成功,第四个不成功,间隔似的。
检查了IIC驱动代码
IIC.c

#include "sys.h"
#include "IIC.h"

static IICFun                m_Instance;
static IICFun                *pthis = NULL;


//static void SDA_Out(Level b_level)
//{
//        if(b_level == High)
//                GPIO_SetBits(IIC_SDA_GPIO_TYPE, IIC_SDA_GPIO_PIN);
//        else
//                GPIO_ResetBits(IIC_SDA_GPIO_TYPE, IIC_SDA_GPIO_PIN);
//}

//static void SCK_Out(Level b_level)
//{
//        if(b_level == High)
//                GPIO_SetBits(IIC_SCK_GPIO_TYPE, IIC_SCK_GPIO_PIN);
//        else
//                GPIO_ResetBits(IIC_SCK_GPIO_TYPE, IIC_SCK_GPIO_PIN);
//}

static void IIC_Start(void)
{
        SDA_OUT();
        IIC_SDA = 1;
        IIC_SCL = 1;
        delay_us(4);
        IIC_SDA = 0;
        delay_us(4);
        IIC_SCL = 0;
}

static void IIC_Stop(void)
{
        SDA_OUT();
        IIC_SCL = 0;
        IIC_SDA = 0;
        delay_us(4);
        IIC_SCL = 1;
        delay_us(4);
        IIC_SDA = 1;
        delay_us(4);
}

static void ACK(void)
{
        IIC_SCL = 0;
        SDA_OUT();
        IIC_SDA = 0;
        delay_us(4);
        IIC_SCL = 1;
        delay_us(4);
        IIC_SCL = 0;
}

static void No_ACK(void)
{
        IIC_SCL = 0;       
        SDA_OUT();
        IIC_SDA = 1;
        delay_us(4);
        IIC_SCL = 1;
        delay_us(4);
        IIC_SCL = 0;
}

static u8 Wait_ACK(void)
{
        u8 ucErrTime=0;
        SDA_IN();
        IIC_SDA = 1;       
        delay_us(4);       
        IIC_SCL = 1;
        delay_us(4);
        while(READ_SDA)
        {
                ucErrTime++;
                if(ucErrTime >250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        IIC_SCL=0;
        return 0;
}
static void WriteByte(u8 data)
{
        u8 i;
       
        SDA_OUT();
        IIC_SCL = 0;
        for(i=0; i<8; i++)
        {
                if(data & 0x80)
                        IIC_SDA = 1;
                else
                        IIC_SDA = 0;
                data <<= 1;
                delay_us(4);
                IIC_SCL = 1;
                delay_us(4);
                IIC_SCL = 0;
                delay_us(4);
        }       
}

static u8 ReadByte(u8 IsAck)
{
        u8 i, receive = 0;
        SDA_IN();
        for(i=0; i<8; i++)
        {
                IIC_SCL = 0;
                delay_us(4);
                IIC_SCL = 1;
                delay_us(4);
                receive <<= 1;
                if(READ_SDA)
                        receive++;
                delay_us(4);
        }
        if(IsAck)
                ACK();
        else
                No_ACK();
       
        return receive;
}       

static void WriteOneByte(u8 ReadAddr, u8 DataToWrite)
{
        IIC_Start();  
        WriteByte(AT24X02_1        | IIC_WRITE_CMD);       
        Wait_ACK();         
        WriteByte(ReadAddr);  //address
        Wait_ACK();
        WriteByte(DataToWrite);     //·¢&#203;í×&#214;&#189;ú                                                          
        Wait_ACK();                                
        IIC_Stop();//2úéúò&#187;&#184;&#246;í£&#214;1ì&#245;&#188;t
        delay_ms(20);       
}
static u8 ReadOneByte(u8 ReadAddr)
{
        u8 i, receive = 0, ack;
        IIC_Start();  
        WriteByte(AT24X02_1        | IIC_WRITE_CMD);
        Wait_ACK();
        WriteByte(ReadAddr);
        Wait_ACK();
       
        IIC_Start();  
        WriteByte(AT24X01 | IIC_READ_CMD);
        Wait_ACK();       
        receive = ReadByte(FALSE);

        IIC_Stop();//2úéúò&#187;&#184;&#246;í£&#214;1ì&#245;&#188;t       
        delay_ms(20);
        return receive;
}


static void Read_Data(u8 addr, u8 size, u8 *buff)
{
        u8 i;
       
        if(NULL != buff)
        {
                for(i=0; i<size; i++)
                {
                        IIC_Start();  
                        WriteByte(AT24X02_1        | IIC_WRITE_CMD);   //·¢&#203;í&#198;÷&#188;tμ&#216;&#214;·0XA0,D′êy&#190;Y          
                        Wait_ACK();
                        WriteByte(addr++);   //·¢&#203;íμíμ&#216;&#214;·
                        Wait_ACK();            
                        IIC_Start();                     
                        WriteByte(AT24X01 | IIC_READ_CMD);           //&#189;&#248;è&#235;&#189;óê&#213;&#196;£ê&#189;                          
                        Wait_ACK();                
                        if(i<size - 1)
                                *(buff+i)=ReadByte(TRUE);       
                        else
                                *(buff+i)=ReadByte(FALSE);       
                        IIC_Stop();//2úéúò&#187;&#184;&#246;í£&#214;1ì&#245;&#188;t       
                        delay_ms(20);
                }
        }
}

static void Write_Data(u8 addr, u8 size, u8 *buff)
{
        u8 i;
       
        if(NULL != buff)
        {
                for(i=0; i<size; i++)
                {
                        IIC_Start();  
                        WriteByte(AT24X02_1        | IIC_WRITE_CMD);       
                        Wait_ACK();         
                        WriteByte(addr++);  //address
                        Wait_ACK();
                        WriteByte(*buff++);     //·¢&#203;í×&#214;&#189;ú                                                          
                        Wait_ACK();                                
                        IIC_Stop();//2úéúò&#187;&#184;&#246;í£&#214;1ì&#245;&#188;t
                        delay_ms(20);
                }
        }
}
static void IIC_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        //RCC->APB2ENR|=1<<4;//&#207;èê1&#196;üíaéèIO PORTCê±&#214;ó
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOB, ENABLE );       
          
        GPIO_InitStructure.GPIO_Pin = IIC_SDA_GPIO_PIN ;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ;   //í&#198;íìê&#228;3&#246;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(IIC_SDA_GPIO_TYPE, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = IIC_SCK_GPIO_PIN ;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ;   //í&#198;íìê&#228;3&#246;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(IIC_SCK_GPIO_TYPE, &GPIO_InitStructure);       
       
        IIC_SDA = 1;
        IIC_SCL = 1;
}

static u8 Check_AT2402(void)
{
        u8 temp;
        static u8 data = 0x55;

        IIC_Start();  
        WriteByte(AT24X02_1        | IIC_WRITE_CMD);       
        Wait_ACK();         
        WriteByte(0xff);  //address
        Wait_ACK();
        WriteByte(data);     //·¢&#203;í×&#214;&#189;ú                                                          
        Wait_ACK();                                
    IIC_Stop();//2úéúò&#187;&#184;&#246;í£&#214;1ì&#245;&#188;t
        delay_ms(10);
       
                                                                                                                                                       
    IIC_Start();  
        WriteByte(AT24X02 | IIC_WRITE_CMD);   //·¢&#203;í&#198;÷&#188;tμ&#216;&#214;·0XA0,D′êy&#190;Y          
        Wait_ACK();
    WriteByte(0xff);   //·¢&#203;íμíμ&#216;&#214;·
        Wait_ACK();            
        IIC_Start();                     
        WriteByte(AT24X02 | IIC_READ_CMD);           //&#189;&#248;è&#235;&#189;óê&#213;&#196;£ê&#189;                          
        Wait_ACK();         
    temp=ReadByte(FALSE);                  
    IIC_Stop();//2úéúò&#187;&#184;&#246;í£&#214;1ì&#245;&#188;t
        if(temp == data)
                printf("AT24C02 Init Succeed\r\n");
        else
                printf("No Fine AT24C02\r\n");
        return temp;
}

static void New(void)
{
        pthis = &m_Instance;
        pthis->Init = IIC_Init;
        pthis->ReadByte = ReadOneByte;
        pthis->WriteByte = WriteOneByte;
        pthis->Check = Check_AT2402;
        pthis->ReadData = Read_Data;
        pthis->WriteData = Write_Data;
}

IICFun        *IICGet(void)
{
        if(pthis == NULL)
        {
                New();
        }
        return pthis;
}


IIC.h
#ifndef        _IIC_H_
#define        _IIC_H_

#define SDA_IN()    {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT()         {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)1<<28;}

#define                IIC_SDA_GPIO_PIN                GPIO_Pin_7
#define                IIC_SDA_GPIO_TYPE                GPIOB
#define                IIC_SCK_GPIO_PIN                GPIO_Pin_6
#define                IIC_SCK_GPIO_TYPE                GPIOB

#define                IIC_WRITE_CMD        0x00
#define                IIC_READ_CMD        0x01

#define                AT24X02_1                0xA0
#define                AT24X02_2                0xA2
//IO2ù×÷oˉêy         
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA         
#define READ_SDA   PBin(7)  //ê&#228;è&#235;SDA

typedef struct
{
        void (*Init)(void);
        u8   (*ReadByte)(u8 ReadAddr);
        void (*WriteByte)(u8 ReadAddr, u8 DataToWrite);
        u8    (*Check)(void);
        void (*ReadData)(u8 addr, u8 size, u8 *buff);
        void (*WriteData)(u8 addr, u8 size, u8 *buff);
}IICFun;

IICFun        *IICGet(void);


#endif

根据网友遇到的情况修改开漏输出或者推挽输出效果无变化
单次读数据和连续读数据也是数据间隔式丢失
读完数据延时增加到100ms也不解决第二个数据读写丢失的问题
从串口输出可以看到复位后g_hour和g_second确实保存了,但是g_minute丢失

不知道是读写时序问题还是其他问题
困扰我很多天了
望各位指教

QQ截图20170916221154.png

最佳答案

查看完整内容[请看2#楼]

1、连续写的时候,不能超过eeprom一页字节,24c02页写大小为8字节(有16字节的?)。 2、页写算法参考 [mw_shl_code=applescript,true]#include "main.h" //eeprom/fram 参数 #define EEPROM_TYPE 0 //0->EEPROM 1->FRAM #define EEPROM_MODEL 16 //EEPROM 类型 24c16 #define EE24CLXX_SLAVE_ADDR 0x50 //注意读写位,实际地址为0x50 #define EE24CLXX_PageSize 16 //AT24C16每页有16 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

685

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3448
金钱
3448
注册时间
2017-7-4
在线时间
869 小时
发表于 2017-9-16 22:15:01 | 显示全部楼层
1、连续写的时候,不能超过eeprom一页字节,24c02页写大小为8字节(有16字节的?)。
2、页写算法参考
[mw_shl_code=applescript,true]#include "main.h"       

//eeprom/fram 参数
#define                EEPROM_TYPE                                                        0                                //0->EEPROM 1->FRAM
#define                EEPROM_MODEL                                                16                        //EEPROM 类型 24c16
#define         EE24CLXX_SLAVE_ADDR           0x50                //注意读写位,实际地址为0x50
#define         EE24CLXX_PageSize       16                        //AT24C16每页有16个字节   24C02->8

static void I2C_24CLXXWaitStandby(u8 slave_addr);

//页写延时,FRAM不用
static void I2C_24CLXXWaitStandby(u8 slave_addr)
{
#if EEPROM_TYPE
       
#else
                u16 i;
                i = 0xFFFF;
                while (i--);
#endif
}

//写多字节,需确保当前写地址+写入数据长度不能超过EEPROM的一页
static void i2c_24clxx_write( u16 WriteAddr, char* pBuffer,u16 NumByteToWrite)
{
                struct st_i2c_msg ee24_msg[2];
                u8        buf[2];
                u8  slave_addr;

                //if(WriteAddr+NumByteToWrite > EE24CLXX_PageSize)
                //                return;
                if(EEPROM_MODEL > 16)
                {//大于2k字节时,地址为16位
                                slave_addr = EE24CLXX_SLAVE_ADDR;
                                buf[0] = (WriteAddr >>8)& 0xff;
                                buf[1] = WriteAddr & 0xff;
                                ee24_msg[0].size  = 2;
                }
                else
                {
                                slave_addr = EE24CLXX_SLAVE_ADDR | (WriteAddr>>8);
                                buf[0] = WriteAddr & 0xff;
                                ee24_msg[0].size  = 1;
                }
                ee24_msg[0].addr = slave_addr;
                ee24_msg[0].flags = ST_I2C_WR;
                ee24_msg[0].buff  = buf;
                ee24_msg[1].addr = slave_addr;
                ee24_msg[1].flags = ST_I2C_WR  | ST_I2C_NO_START;       
                ee24_msg[1].buff  = (u8*)pBuffer;
                ee24_msg[1].size  = NumByteToWrite;
                i2c_bitops_bus_xfer(&i2c1_dev,ee24_msg,2);
}

/*******************************************************
**
**                                                                                         外部函数
**
*******************************************************/

//写一字节
char ee_24clxx_writebyte(u16 addr,u8 data)
{
                struct st_i2c_msg ee24_msg[2];
                u8        buf[3];
                u8  slave_addr;
       
                if(EEPROM_MODEL > 16)
                {//大于2k字节时,地址为16位
                                slave_addr = EE24CLXX_SLAVE_ADDR;
                                buf[0] = (addr >>8)& 0xff;   //高位地址在前
                                buf[1] = addr & 0xff;
                                buf[2] = data;
                                ee24_msg[0].size  = 3;
                }
                else
                {
                                slave_addr = EE24CLXX_SLAVE_ADDR | (addr>>8);
                                buf[0] = addr & 0xff;
                                buf[1] = data;
                                ee24_msg[0].size  = 2;
                }
                ee24_msg[0].addr = slave_addr;
                ee24_msg[0].flags = ST_I2C_WR;
                ee24_msg[0].buff  = buf;
                i2c_bitops_bus_xfer(&i2c1_dev,ee24_msg,1);
               
                return 0;
}

//写多字节,页写算法
char ee_24clxx_writebytes(u16 write_addr, char* pwrite_buff, u16 writebytes)
{
                u8   write_len,page_offset;
                u16  write_remain,write_current_addr;
                char error = 0,*pbuff;
       
                pbuff                                        = pwrite_buff;                       
                write_remain  = writebytes;
                write_current_addr = write_addr;
                while(write_remain > 0)
                {
                                page_offset = write_current_addr & 0x0f;                //write_current_addr%EE24CLXX_PageSize
                                write_len   = write_remain > (EE24CLXX_PageSize - page_offset) ? (EE24CLXX_PageSize - page_offset) : write_remain;
                                i2c_24clxx_write(write_current_addr,pbuff, write_len);
                                write_remain   = write_remain - write_len;
                                if(write_remain > 0)
                                {
                                                pbuff = pbuff + EE24CLXX_PageSize - page_offset;
                                                write_current_addr  =  write_current_addr + EE24CLXX_PageSize - page_offset;
                                                I2C_24CLXXWaitStandby(0);
                                }
                }
                I2C_24CLXXWaitStandby(0);
                {//校验数据
                                int i;
                                char checkdata;
                       
                                for(i = 0;i < writebytes;i++)
                                {
                                                ee_24clxx_readbytes(write_addr+i,&checkdata,1);       
                                                if(checkdata != pwrite_buff)
                                                {
                                                                error = 1;
                                                                break;
                                                }
                                }
                }
                return error;
}

//读多字节,连续读
void ee_24clxx_readbytes(u16 ReadAddr, char* pBuffer, u16 NumByteToRead)
{  
                struct st_i2c_msg ee24_msg[2];
                u8        buf[2];
                u8  slave_addr;
       
                if(EEPROM_MODEL > 16)
                {//大于2k字节时,地址为16位
                                slave_addr = EE24CLXX_SLAVE_ADDR;
                                buf[0] = (ReadAddr >>8)& 0xff;
                                buf[1] = ReadAddr & 0xff;
                                ee24_msg[0].size  = 2;
                }
                else
                {
                                slave_addr = EE24CLXX_SLAVE_ADDR | (ReadAddr>>8);
                                buf[0] = ReadAddr & 0xff;
                                ee24_msg[0].size  = 1;
                }
                ee24_msg[0].buff  = buf;
                ee24_msg[0].addr  = slave_addr;
                ee24_msg[0].flags = ST_I2C_WR;
                ee24_msg[1].addr  = slave_addr;
                ee24_msg[1].flags = ST_I2C_RD;
                ee24_msg[1].buff  = (u8*)pBuffer;
                ee24_msg[1].size  = NumByteToRead;
                i2c_bitops_bus_xfer(&i2c1_dev,ee24_msg,2);
}[/mw_shl_code]
回复

使用道具 举报

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2017-8-22
在线时间
29 小时
 楼主| 发表于 2017-9-16 23:20:19 | 显示全部楼层
调整了延时,增减读写间隔还是不理想
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2017-9-17 01:08:54 | 显示全部楼层
你先检查下你的24c读写是否正常,不用管什么时间。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2017-8-22
在线时间
29 小时
 楼主| 发表于 2017-9-17 01:24:51 | 显示全部楼层
正点原子 发表于 2017-9-17 01:08
你先检查下你的24c读写是否正常,不用管什么时间。

24C读写是正常的,就是用原子的例程,连续读写,第一第三个数据改变了第二个数据不变,但三个数据其实是一起改变的
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-18 21:43

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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