2446|3

18

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

MSP430FR5969-LaunchPad模拟I2C [复制链接]

    MSP430FR5969虽然自带I2C,但总感觉用起来挺别扭,可能是习惯用自己写的模拟I2C。用51来模拟I2C实现起来比较方便,但在MSP430上相对复杂一点,不过也不是什么大问题。注意切换IO的输入和输出,在判断IO输入时稍加注意就可以。
以下程序读写FM24V05亲测可用,需要注意的是SDA,SCL引脚需要接上拉电阻。
I2C.C
#include
#define Uint8    unsigned char
#define Uint16    unsigned int

#define SDA_IN            P1DIR &=~BIT6    // P1.6 IN
#define SDA_OUT           P1DIR |=BIT6     // P1.6 OUT
#define SDA_LOW           P1OUT &=~BIT6  // sda=0
#define SDA_HIGH          P1OUT |=BIT6   // sda=1
#define SCL_IN            P1DIR &=~BIT7    // P1.7 IN
#define SCL_OUT           P1DIR |=BIT7    // P1.7 OUT
#define SCL_LOW           P1OUT &=~BIT7
#define SCL_HIGH          P1OUT |=BIT7

#define        TURE                1
#define        FALSE               0
#define        GET_SDA          P1IN&BIT6
#define        SYS_MCLK              8000000                //系统时钟频率
#define        DELAY_US                SYS_MCLK/1000000
#define _Nop() _NOP(),_NOP(),_NOP(),_NOP(),_NOP()
unsigned char ack;                         /*应答标志位*/
//延时5us
void i2c_delay(unsigned char us)
{
        //unsigned char tmp;
        while(us--)
        {
                __delay_cycles(DELAY_US);                // Wait 8 CPU Cycles
        }
}
/*
*************************************************************************************
**函数名称:起动总线函数                                                           **
**函数功能:启动I2C总线,即发送I2C起始条件.                                         **
**入口参数:无                                                                     **
**返回参数:无                                                                     **
*************************************************************************************
*/
void Start_I2c(void)
{
        SDA_OUT;                //引脚为输出模式
        SCL_OUT;
        i2c_delay(4);
        SDA_HIGH;                //发送起始条件的数据信号
        i2c_delay(1);
        SCL_HIGH;
        i2c_delay(1);        //起始条件建立时间大于4.7us,延时
        SDA_LOW;                //发送起始信号
        i2c_delay(1);        // 起始条件锁定时间大于4μs
        SCL_LOW;                //钳住I2C总线,准备发送或接收数据
        i2c_delay(2);
}
/*
*************************************************************************************
**函数名称:结束总线函数                                                           **
**函数功能:结束I2C总线,即发送I2C结束条件.                                         **
**入口参数:无                                                                     **
**返回参数:无                                                                     **
*************************************************************************************
*/
void Stop_I2c(void)
{
    SDA_OUT;        //引脚为输出模式
        SDA_LOW;          //发送结束条件的数据信号
    i2c_delay(1);           //发送结束条件的时钟信号
    SCL_HIGH;          //结束条件建立时间大于4μs
    i2c_delay(1);
    SDA_HIGH;          //发送I2C总线结束信号
    i2c_delay(1);
}
/*
*************************************************************************************
**函数名称:应答子函数                                                             **
**函数功能:主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)              **
**入口参数:无                                                                     **
**返回参数:无                                                                     **
*************************************************************************************
*/
void Ack_I2c(Uint8 a)
{  
    SDA_OUT;        //引脚为输出模式
        if(a==0)SDA_LOW;                  //在此发出应答或非应答信号
        else SDA_HIGH;
    i2c_delay(1);   
    SCL_HIGH;
    i2c_delay(1);                    //时钟低电平周期大于4μs
    SCL_LOW;                    //清时钟线,钳住I2C总线以便继续接收
    i2c_delay(1);   
}
/*
*************************************************************************************
**函数名称:发送单字节函数                                                         **
**函数功能:将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对            **
**          此状态位进行操作.(不应答或非应答都使ack=0)                             **
**入口参数:Uint8 c发送数据                                                        **
**返回参数:无                                                                     **
*************************************************************************************
*/
void SendByte(Uint8 c)
{
    Uint8 BitCnt = 0;
        SDA_OUT;        //引脚为输出模式
    for(BitCnt=0;BitCnt<8;BitCnt++){  //要传送的数据长度为8位
        if((c<         else  SDA_LOW;               
        i2c_delay(1);
        SCL_HIGH;               //置时钟线为高,通知被控器开始接收数据位
        i2c_delay(1);             //保证时钟高电平周期大于0.6μs   
        SCL_LOW;
    }
    i2c_delay(1);
    SDA_HIGH;                //8位发送完后释放数据线,准备接收应答位
    i2c_delay(1);  
    SDA_IN;
        SCL_HIGH;
    i2c_delay(1);
    if(GET_SDA)ack=0;     
       else ack=1;        //判断是否接收到应答信号
    SCL_LOW;
    i2c_delay(1);
}

/*
*************************************************************************************
**函数名称:接收单字节函数                                                         **
**函数功能:用来接收从器件传来的数据,并判断总线错误(不发应答信号),                                   **
**          发完后请用应答函数应答从机。                                           **
**入口参数:无                                                                     **
**返回参数:无                                                                     **
*************************************************************************************
*/       
Uint8 RcvByte(void)
{
    Uint8 retc = 0;
    Uint8 BitCnt = 0;

    //retc=0;
    SDA_HIGH;                             //置数据线为输入方式
        SDA_IN;
    for(BitCnt=0;BitCnt<8;BitCnt++){
        _Nop();           
        SCL_LOW;                  //置时钟线为低,准备接收数据位
        i2c_delay(1);              //时钟低电平周期大于4.7μs
        SCL_HIGH;                  //置时钟线为高使数据线上数据有效
        _Nop();
        _Nop();
        retc=retc<<1;
        if(GET_SDA)retc=retc+1;  //读数据位,接收的数据位放入retc中
        _Nop();
        _Nop();
    }
    SCL_LOW;   
        _Nop();
    _Nop();
    return(retc);
}
/*
*************************************************************************************
**函数名称:向有子地址器件发送多字节数据函数                                       **
**函数功能:从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件             **
**          地址sla,子地址suba,发送内容是s指向的内容,p发送子地址                                   **
**          8位或16位选择,发送no个字节。                                          **
**          如果返回1表示操作成功,否则操作有误。                                  **
**注意:    使用前必须已结束总线。                                                 **
**入口参数:...                                                                    **
**返回参数:成功/失败                                                              **
*************************************************************************************
*/
Uint8 ISendStr(Uint8 sla,Uint16 suba,Uint8 * s,Uint16 no,Uint8 p)
{
    Uint16 i;
    Start_I2c();                //启动总线
    SendByte(sla);              //发送器件地址
    if(ack==0)return(FALSE);
    if(p){                       //发送子地址
        SendByte(suba/256);        
        if(ack==0)return(FALSE);
        SendByte(suba%256);
        if(ack==0)return(FALSE);   
    }
    else{
        SendByte((Uint8) suba);
        if(ack==0)return(FALSE);
    }
    for(i=0;i       SendByte(*s);            //发送数据
      if(ack==0)return(FALSE);
      s++;
    }
    Stop_I2c();                //结束总线
    return(TRUER);
}

/*
*************************************************************************************
**函数名称:向有子地址器件读取多字节数据函数                                       **
**函数功能:从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件           **
**          地址sla,子地址suba,读出的内容放入s指向的存储区,p发送子地址          **
**          8位或16位选择,读no个字节。                                            **
**          如果返回1表示操作成功,否则操作有误。                                                                   **
**注意:    使用前必须已结束总线。                                                 **
**入口参数:...                                                                    **
**返回参数:成功/失败                                                              **
*************************************************************************************
*/
Uint8 IRcvStr(Uint8 sla,Uint16 suba,Uint8 * s,Uint16 no,Uint8 p)
{
    Uint16 i = 0;
    Start_I2c();                    //启动总线
    SendByte(sla);                  //发送器件地址
    if(ack==0)return(FALSE);
    if(p){                           //发送子地址
        SendByte(suba/256);        
        if(ack==0)return(FALSE);
        SendByte(suba%256);
        if(ack==0)return(FALSE);   
    }
    else{
        SendByte((Uint8) suba);
        if(ack==0)return(FALSE);
    }
    Start_I2c();                    //重新启动总线
    SendByte(sla+1);
    if(ack==0)return(0);
    for(i=0;i         *s=RcvByte();               //发送数据
        Ack_I2c(0);                 //发送应答位
        s++;
    }
    *s=RcvByte();
    Ack_I2c(1);                     //发送非应位
    Stop_I2c();                     //结束总线
    return(TRUER);
}

------------------------------------------------------------------------------------
下面是操作FM24V05的函数
#define MaxAddr (65536)
/***********************************************************************************/
/*函数名称:Uint8 DISK_Read(Uint16 Addr,Uint8 * Buf,Uint16 Count)                   */
/*函数功能:从存储器中读取数据                                                     */
/*入口参数:Addr Buf Count                                                         */
/*返回参数:TRUER/FALSE                                                            */
/***********************************************************************************/
Uint8 DISK_Read(Uint16 Addr,Uint8 * Buf,Uint16 Count)//reentrant
{
        Uint8 i=0;
        //Uint16 j = Addr+Count;
        if((Addr+Count) > MaxAddr)       //超出存储范围
        {
                return FALSE;
        }
        while(!(IRcvStr(ADDR_FM24V05,Addr,Buf,Count,1)))
        {
                i ++;
                if(i > 3)
                {
                        return FALSE;
                }
        }
        return TRUER;
}

/***********************************************************************************/
/*函数名称:Uint8 DISK_Write(Uint16 Addr,Uint8 * Buf,Uint16 Count)                  */
/*函数功能:向存储器中写入数据                                                     */
/*入口参数:Addr Buf Count                                                         */
/*返回参数:TRUER/FALSE                                                            */
/***********************************************************************************/
Uint8 DISK_Write(Uint16 Addr,Uint8 * Buf,Uint16 Count)
{
        Uint8 i=0;
        //i = 0;
        if((Addr+Count) > MaxAddr)      //超出存储范围
        {
                return FALSE;
        }
        while(!(ISendStr(ADDR_FM24V05,Addr,Buf,Count,1)))
        {
                i ++;
                if(i > 3)
                {
                        return FALSE;
                }
        }       
        return TRUER;
}

最新回复

你确定可用?你的 IRcvStr和ISendStr函数的最后的返回值都写错了,连编译都根本不会通过  详情 回复 发表于 2017-10-27 10:47
 
点赞 关注

回复
举报

6066

帖子

92

TA的资源

裸片初长成(初级)

沙发
 
MSP430FR5969玩起来
 
 

回复

16

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
MSP430经典的片子
 
个人签名创龙DSP开发培训,时间为2016年7月18日,http://51dsp.net/forum.php?mod=viewthread&tid=939
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

4
 
你确定可用?你的 IRcvStr和ISendStr函数的最后的返回值都写错了,连编译都根本不会通过
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表