关于LPC1758平台上I2C EEPROM 调试总结

发布者:sjjawx831最新更新时间:2016-04-20 来源: eefocus关键字:LPC1758  I2C  EEPROM  调试总结 手机看文章 扫描二维码
随时随地手机看文章
硬件平台:PLC1758

软件平台 uCOS-II

开发环境: IAR EWARM

源码如下

#define BSP_I2C2_PINS           (DEF_BIT_10|DEF_BIT_11)

static void  BSP_I2C2_Init(CPU_INT32U fi2c)
{
    //获取外设时钟
    CPU_INT32U Fpclk  = BSP_PM_PerClkFreqGet(BSP_PM_PER_NBR_I2C2);
    //使能该功率模块
    BSP_PM_PerClkEn(BSP_PM_PER_NBR_I2C2);                     
    //配置脉冲捕捉管脚                                                           
    BSP_GPIO_Cfg(BSP_GPIO_PORT0_FAST,//P0.10引脚
                 BSP_I2C2_PINS,//设置成脉冲捕捉
                 BSP_GPIO_OPT_FNCT_3);//引脚输入使能
    
    //设置占空比
    if(fi2c>400000)
      fi2c = 400000;
    I2C2SCLH = (Fpclk+1/fi2c ) / 2; //高电平占空比寄存器
    I2C2SCLL = (Fpclk/fi2c) / 2;      //低电平占空比寄存器
    //配置成I2C主模式 
    I2C2CONCLR = 0x2C;      //STA|SI|AA|STO;
    I2C2CONSET = 0x40;      //I2EN=1,使能主I2C   
  
    //设置中断源
    BSP_IntVectSet((CPU_INT08U)BSP_INT_SRC_NBR_I2C2,(CPU_FNCT_VOID)I2C2_IRQ_ISR_handler ); 
    BSP_IntPrioSet((CPU_INT08U)BSP_INT_SRC_NBR_I2C2,0x01);
    //使能中断
    BSP_IntEn(BSP_INT_SRC_NBR_I2C2);
    //I2C2中断通道号为28
   
}

 

问题 :一个字节的变量写入与读出的的结果不一致,源码如下

 
INT8U I2C_WriteNByte(INT8U sla, INT8U suba_type, INT32U suba, INT8U *s, INT32U num)
{
    if (num > 0)                                         //  如果读取的个数为0,则返回错误                                                                    
                                                      // 设置参数                    
        if (suba_type == 1)
                                                      // 子地址为单字节              
            I2C_sla         = sla;                       // 读器件的从地址              
            I2C_suba        = suba;                      // 器件子地址                  
            I2C_suba_num    = 1;                         // 器件子地址为1字节           
        }
        else if (suba_type == 2)
                                                      // 子地址为2字节               
            I2C_sla         = sla;                       // 读器件的从地址              
            I2C_suba        = suba;                      // 器件子地址                  
            I2C_suba_num    = 2;                         // 器件子地址为2字节           
        }
        else if (suba_type == 3)
                                                      // 子地址结构为8+X             
            I2C_sla         = sla + ((suba >> 7 )& 0x0e);// 读器件的从地址              
            I2C_suba        = suba & 0x0ff;              // 器件子地址                  
            I2C_suba_num    = 1;                         // 器件子地址为8+X             
        }

        I2C_buf     = s;                                 // 数据                        
        I2C_num     = num;                               // 数据个数                    
        I2C_suba_en = 2;                                 // 有子地址,写操作            
        I2C_end     = 0;

                                                         // 清除STA,SI,AA标志位         
        I2C2CONCLR = (1 << 2)|                           // AA                          
                     (1 << 3)|                           // SI                          
                     (1 << 5);                           // STA                         

                                                        // 置位STA,启动I2C总线         
        I2C2CONSET = (1 << 5)|                          // STA                         
                     (1 << 6);                          // I2CEN                       

                                                        // 等待I2C操作完成             
        return( Wait_I2c_End(1000));

    }
    return (FALSE);
}


INT8U I2C_ReadNByte (INT8U sla, INT32U suba_type, INT32U suba, INT8U *s, INT32U num)
{
   
    if (num > 0)                                         // 判断num个数的合法性         
                                                      // 参数设置                    
        if (suba_type == 1)
                                                     // 子地址为单字节              
            I2C_sla         = sla + 1;                  // 读器件的从地址,R=1         
            I2C_suba        = suba;                     // 器件子地址                  
            I2C_suba_num    = 1;                        // 器件子地址为1字节           
        }
        else if (suba_type == 2)
                                                     // 子地址为2字节               
            I2C_sla         = sla + 1;                  // 读器件的从地址,R=1         
            I2C_suba        = suba;                     // 器件子地址                  
            I2C_suba_num    = 2;                        // 器件子地址为2字节           
        }
        else if (suba_type == 3)
                                                     // 子地址结构为8+X             
            I2C_sla         = sla + ((suba >> 7 )& 0x0e) + 1; // 读器件的从地址,R=1         
            I2C_suba        = suba & 0x0ff;             // 器件子地址                  
            I2C_suba_num    = 1;                        // 器件子地址为8+x             
        }
        I2C_buf     = s;                                // 数据接收缓冲区指针          
        I2C_num     = num;                              // 要读取的个数                
        I2C_suba_en = 1;                                // 有子地址读                  
        I2C_end     = 0;

                                                        // 清除STA,SI,AA标志位         
        I2C2CONCLR = (1 << 2)|                          // AA                          
                     (1 << 3)|                          // SI                          
                     (1 << 5);                          // STA                         

                                                       // 置位STA,启动I2C总线         
        I2C2CONSET = (1 << 5)|                         // STA                         
                     (1 << 6);                         // I2CEN                       
                                                             
        return( Wait_I2c_End(1000));                    // 等待I2C操作完成    


    }
    return (FALSE);
 
}



void I2C2_IRQ_ISR_handler(void)

  
   
   
    switch (I2C2STAT & 0xF8)//0~6位是状态位
     // 根据状态码进行相应的处理    
        case 0x08:    // 已发送起始条件,主发送和主接收都有,装入SLA+W或者SLA+R
            if(I2C_suba_en == 1)// SLA+R         // 指定子地址读               
            {
                I2C2DAT = I2C_sla & 0xFE;        // 先写入地址                  
            }
            else                                 // SLA+W                      
            {
                I2C2DAT = I2C_sla;               // 否则直接发送从机地址       
            }
                                                 // 清零SI位                    
            I2C2CONCLR = (1 << 3)|               // SI                         
                         (1 << 5);               // STA                       
            break;

        case 0x10:    // 已发送重复起始条件      // 主发送和主接收都有          
                                                 // 装入SLA+W或者SLA+R         
            I2C2DAT = I2C_sla;                   // 重起总线后,重发从地址      
            I2C2CONCLR = 0x28;                   // 清零SI,STA                 
            break;

        case 0x18:
        case 0x28:                              // 已发送I2DAT中的数据,已接收ACK
            if (I2C_suba_en == 0)
            {
                if (I2C_num > 0)
                {
                    I2C2DAT = *I2C_buf++;
                    I2C2CONCLR = 0x28;          // 清零SI,STA                  
                    I2C_num--;
                }
                else                            // 没有数据发送了              
                                             // 停止总线                    
                    I2C2CONSET = (1 << 4);      // STO                         
                    I2C2CONCLR = 0x28;          // 清零SI,STA                  
                    I2C_end = 1;                // 总线已经停止                
                }
            }
   
            else if(I2C_suba_en == 1)         // 若是指定地址读,则重新启动总线
            {
                if (I2C_suba_num == 2)
                {
                    I2C2DAT = ((I2C_suba >> 8) & 0xff);
                    I2C2CONCLR = 0x28;        // 清零SI,STA                  
                    I2C_suba_num--;
                    break;
                }
   
                else if(I2C_suba_num == 1) //器件子地址为1字节
                {
                    I2C2DAT = (I2C_suba & 0xff);
                    I2C2CONCLR = 0x28;       // 清零SI,STA                  
                    I2C_suba_num--;
                    break;
                }
   
                else if (I2C_suba_num == 0)
                {
                    I2C2CONCLR = 0x08;
                    I2C2CONSET = 0x20;
                    I2C_suba_en = 0;        // 子地址己处理                
                    break;
                }
              
            else if (I2C_suba_en == 2)  //  指定子地址写,子地址尚未指定                                                                         
                                     // 则发送子地址                
                if (I2C_suba_num > 0)
                {
                   
                   
                    if (I2C_suba_num == 2)
                     
                        I2C2DAT     = ((I2C_suba >> 8) & 0xff);
                        I2C2CONCLR  = 0x28;
                        I2C_suba_num--;
                        break;
                                    
                    else if (I2C_suba_num == 1)  //器件子地址为1字节
                    {
                        I2C2DAT    = (I2C_suba & 0xff);
                        I2C2CONCLR = 0x28;
                        I2C_suba_num--;
                        I2C_suba_en  = 0;
                        break;
                    }
                }
            }
            break;

        case 0x40:                       // 已发送SLA+R,已接收ACK       
            if (I2C_num <= 1)            // 如果是最后一个字节         
            
                  I2C2CONCLR = 1 << 2;  // 下次发送非应答信号          
            }
            else
             
                  I2C2CONSET = 1 << 2; // 下次发送应答信号            
            }
            I2C2CONCLR = 0x28;         // 清零SI,STA                  
            break;

        case 0x20:                    // 已发送SLA+W,已接收非应答   
        case 0x30:                    // 已发送I2DAT中的数据,已接收非应答                                                                                               
        case 0x38:                    // 在SLA+R/W或数据字节中丢失仲裁
                                                                       
        case 0x48:                    // 已发送SLA+R,已接收非应答    
            I2C2CONCLR = 0x28;
            I2C_end = 0xFF;
            break;

        case 0x50:                   // 已接收数据字节,已返回ACK   
            *I2C_buf++ = I2C2DAT;
            I2C_num--;
            if (I2C_num == 1)        // 接收最后一个字节           
            {
                I2C2CONCLR = 0x2C;   // STA,SI,AA = 0              
            }
            else
            {
                I2C2CONSET = 0x04;  // AA=1                        
                I2C2CONCLR = 0x28;
            }
            break;

        case 0x58:                  // 已接收数据字节,已返回非应答
            *I2C_buf++ = I2C2DAT;   // 读取最后一字节数据          
            I2C2CONSET = 0x10;      // 结束总线                    
            I2C2CONCLR = 0x28;
            I2C_end = 1;
            break;

        default:
            break;
    }
}

原因:指定suba_type参数不正确,如果器件的地址位宽是一字节,那么指定为1,如果地址位宽是两字节,那么指定为2。另外在读写操作时指定Wait_I2c_End(INT32 Dly)函数中的Dly值太小也不能操作成功,可以适当放大些。

关键字:LPC1758  I2C  EEPROM  调试总结 引用地址:关于LPC1758平台上I2C EEPROM 调试总结

上一篇:arm启动代码详细分析
下一篇:在IAR环境下LPC2129平台上脉冲捕捉导致死机问题

推荐阅读最新更新时间:2024-03-16 14:51

STM32L系列单片机内部EEPROM的读写
STM32L系列单片机内部提供了EEPROM存储区域,但实质上,其FLASH也是EEPROM类型,只不过有一块区域被开放出来专门用作EEPROM操作而已。STM32L的EEPROM使用寿命设计为100000次擦写以上,容量为2K-4K,这对于一般设备的参数存储来说是非常理想的。但从EEPROM使用方式看,其不适用于被反复修改的数据存储使用,一般作为配置参数,其修改次数往往是比较少量的。 STM32L的EEPROM和FLASH是统一编址,操作共用同一个读写电路,所以在EEPROM读写的时候STM32L核对于FLASH的一切访问和操作都将暂停,只有当EEPROM的操作完成后,才继续执行后续代码,在这期间只有EEPROM的读写电路工
[单片机]
KST-STM学习之I2C+SPI
只能说跟51的差不了多少,在这里仅仅记录下主要注意事项吧。 1、I 2 C 通信分为标准模式 100kbit/s、快速模式 400kbit/s 和高速模式 3.4Mbit/s。因为所有的I 2 C 器件都支持标准模式,但却未必支持另外两种速度。 所以作为通用的 I 2 C 程序我们选择100k 这个速率来实现,也就是说实际程序产生的时序必须小于等于 100k 的时序参数,有特殊速度需求的器件再针对性写高速通信程序。 2、I 2 C 引脚属于开漏并联结构,并且 STM32 的 GPIO 端口引脚设置为开漏输出时,可以直接从输入数据寄存器获取 I/O 电平状态,因此将 I 2 C 引脚配置为开漏输出模式。 3、由于 I
[单片机]
KST-STM学习之I2C+SPI
STM32的I2C的原理与使用(24C02附代码)
一、IIC的定义 I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS开发用于连接微控制器及其外围设备。IIC是一种多向控制总线,就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。这种方式简化信号传输总线。 它由数据线SDA和时钟SCL构成的串行总线,接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上,可发送接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。 IIC是半双工通信方式。 二、多主机I2C总线系统结构 2)多设备的使用举例
[单片机]
STM32的<font color='red'>I2C</font>的原理与使用(24C02附代码)
AVR操作EEPROM应注意的问题
简介:本文介绍了AVR单片机在实际使用时电源检测的问题。 作为一个正式的系统或产品,当系统基本功能调试完成后,一旦进行现场测试阶段,请注意马上改写熔丝位的配置,启用AVR的电源检测(BOD)功能。 对于5V系统,设置BOD电平为4.0V;对于3V系统,设置BOD电平为2.7V。然后允许BOD检测。 这样,一旦AVR的供电电压低于BOD电平,AVR进入RESET(不执行程序了)。而当电源恢复到BOD电平以上,AVR才正式开始从头执行程序。保证了系统的可靠性! 原因分析如下: AVR是宽电压工作的芯片,当电压跌至2.5V,系统程序还能工作。这是有2个可怕的现象可能出现, 1、外围芯片工作已经混乱,AVR读到的东
[单片机]
I2C配置及调试流程
一、I2C配置 1.根据原理图,查找相关的i2c引脚对应的GPIO值,以GPIO10作为I2C_SDA,GPIO11作为I2C_SCL为例。 2.根据MSM8937 DEVICE SPECIFICATION文档,查找GPIO10与GPIO11对应的BLSP,以及检查GPIO10与GPIO11是否可以作为I2C来使用。根据文档,GPIO10对应BLSP3_1,GPIO11对应BLSP3_0。 3.根据80-nu767-1_h_linux_bam_low-speed_peripherals_configuration_and_debug_guide文件,查找I2C部分BLSP3_0与BLSP3_1对应内容,包括其物理地址、re
[单片机]
STM8 AT24CXX使用I2C接口读写
软件设计 /********************************************************************* 目 的: 建立AT24CXX操作库 目标系统: 基于STM8单片机 应用软件: Cosmic CxSTM8 *********************************************************************/ #define WD_DADR 0xa0 #define RD_DADR 0xa1 #include ws_i2c.h void AT24CXX_Init(void) { I2C_Init(); } void
[单片机]
具有I2C总线接口的A/D芯片PCF8591及其应用
1 引言 I2C总线是Philips公司推出的串行总线,整个系统仅靠数据线(SDA)和时钟线(SCL)实现完善的全双工数据传输,即CPU与各个外围器件仅靠这两条线实现信息交换。I2C总线系统与传统的并行总线系统相比具有结构简单、可维护性好、易实现系统扩展、易实现模块化标准化设计、可靠性高等优点。 在一个完整的单片机系统中,A/D转换芯片往往是必不可少的。PCF8591是一种具有I2C总线接口的A/D转换芯片。在与CPU的信息传输过程中仅靠时钟线SCL和数据线SDA就可以实现。 2 芯片介绍 PCF8591是具有I2C总线接口的8位A/D及D/A转换器。有4路A/D转换输入,1路D/A模拟输出。这就是说,它既可以作
[单片机]
具有<font color='red'>I2C</font>总线接口的A/D芯片PCF8591及其应用
基于I2C总线的新型可编程增益放大电路的设计
在各类遥感遥测系统中,模拟信号的动态范围通常都很大,一般在几mV至几十V范围内(动态范围可达80_90db),有的甚至是几pV_几百V(动态范围可达160db以上)。而且信号的干扰源多,有时甚至掩盖掉有用信号,很难辨识是有用信号还是干扰信号。此外,不同的材料、形状、尺寸,不同的类型,不同的测量速度,得到的信号频谱不同,受干扰信号的特点也不同。对这样的信号进行采集处理,为保证精度,检测系统首先需要对大动态模拟信号的动态范围进行压缩,即对mV甚至pV级的信号进行放大,对几十V甚至几百V的信号进行衰减,将信号的变化幅度调整到A/电路所需要的范围。针对这一问题,本文提出了一种基于I2C总线的新型可编程增益放大器的设计方法,可根据输入的模拟信
[模拟电子]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved