打印
[其它应用]

SH79F084A 使用IO口做模拟I2C主从机功能

[复制链接]
1373|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lcynothing|  楼主 | 2017-10-17 16:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
由于项目需求,需要用到I2C,但SH79F084A没有I2C功能,只能通过使用IO口去模拟I2C,P3_2为SDA,P3_3为SCL,但是写完之后,测试读写数据没有任何反应,引脚也没有变化。下面贴上作为I2C主机模式的代码,请帮忙检查哪里需要更改的,望大神们指点一二,谢谢


#include <SH79F084A.H>
#include "intrins.h"
#include "datatype.h"
#include "delay.h"


sbit SDA = P3^2;    //IIC总线串行数据线
sbit SCL = P3^3;    //IIC总线串行时钟线
U8 AckFlag;/*应答标志位*/

void I2C_Delay(void)
{
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    _nop_(); // >=4.7uS
}

void I2C_SDA_IO(U8 input)  
{  
    if(input == 1)//SDA输出,p3.2
    {
        SETBIT(P3M0, 2);
        SETBIT(P3M1, 2);
    }
    else//SDA输入,p3.2
    {
        SETBIT(P3M0, 2);
        CLRBIT(P3M1, 2);
    }
}

void I2C_SCL_IO(U8 input)
{
    if(input == 1)//SCL输出,P3.3
    {
        SETBIT(P3M0, 3);
        SETBIT(P3M1, 3);
    }
    else//SCL输入,P3.3
    {
        SETBIT(P3M0, 3);
        CLRBIT(P3M1, 3);
    }
}

void Init_I2C(void)
{
    I2C_SDA_IO(OUT);
    I2C_SCL_IO(OUT);
    SDA = 1;
    _nop_();
    SCL = 1;
    _nop_();
}

//---------------------------------------------------------------
// SW I2C: start signal.
// <comment>
//  SDA _____
//           \____________
//  SCL ________
//              \_________
//
// Return value: None
//---------------------------------------------------------------
void I2C_Start(void)
{
    SDA = 1; /*发送起始条件的数据信号*/
    _nop_();
    SCL = 1;
    I2C_Delay();
    SDA = 0; /*发送起始信号*/
    I2C_Delay();
        SCL = 0; /*钳住I2C总线,准备发送或接收数据 */
    _nop_();
    _nop_();
}

//---------------------------------------------------------------
// SW I2C: stop signal.
// <comment>
//                 _________
//  SDA __________/
//              ____________
//  SCL _______/
//---------------------------------------------------------------
void I2C_Stop(void)
{
    SDA = 0; /*发送结束条件的数据信号*/
    _nop_();
    SCL = 1; /*发送结束条件的时钟信号*/
    I2C_Delay();
    SDA = 1; /*发送I2C总线结束信号*/
    I2C_Delay();
}

void I2C_SendAck(void)
{
    SCL = 0;
    I2C_Delay();
    SDA = 0;
    I2C_Delay();
    SCL = 1;
    I2C_Delay();
}

void I2C_SendNoAck(void)
{
    SCL = 0;
    I2C_Delay();
    SDA = 1;
    I2C_Delay();
    SCL = 1;
    I2C_Delay();
}

bit I2C_CheckAck(void)
{
    bit tempBit;
    SDA = 1;
    I2C_Delay();

    SCL = 0;
    I2C_Delay();

    tempBit = SDA;

    SCL = 1;
    I2C_Delay();

    if(tempBit == 1)
    {
        return 0; //noACK
    }
    else
    {
        return 1; //AckFlag
    }
}

void Ack_I2c(bit a)
{
    if(a == 0)
        SDA = 0; /*在此发出应答或非应答信号 */
    else
        SDA = 1;
    _nop_();
    _nop_();

    SCL = 1;
    I2C_Delay();

    SCL = 0;                /*清时钟线,钳住I2C总线以便继续接收*/
    _nop_();
    _nop_();
}

/*******************************************************************
                 字节数据传送函数               
函数原型: void I2C_SendByte(U8 Data);
功能: 将数据Data发送出去,可以是地址,也可以是数据,发完后等待应答,并对
      此状态位进行操作.(不应答或非应答都使ack=0 假)
      发送数据正常,ack=1; AckFlag=0表示被控器无应答或损坏。
********************************************************************/
void I2C_SendByte(U8 Data)
{
    U8 BitCount;

    for(BitCount = 0; BitCount < 8; BitCount++) /*要传送的数据长度为8位*/
    {
        if((Data<<BitCount) & 0x80)
            SDA = 1; /*判断发送位*/
        else
            SDA = 0;
        _nop_();

        SCL = 1; /*置时钟线为高,通知被控器开始接收数据位*/
        I2C_Delay();

        SCL = 0;
    }

    _nop_();
    _nop_();
    SDA = 1; /*8位发送完后释放数据线,准备接收应答位*/
    _nop_();
    _nop_();
    SCL = 1;
    _nop_();
    _nop_();

    if(SDA == 1)
        AckFlag = 0;
    else
        AckFlag = 1; /*判断是否接收到应答信号*/

    SCL = 0;
    _nop_();
    _nop_();
}

/*******************************************************************
                 字节数据传送函数               
函数原型: U8 I2C_RcvByte(void)
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
      发完后请用应答函数。
********************************************************************/
U8 I2C_RcvByte(void)
{
    U8 RcvByte = 0;
    U8 BitCount;

    SDA = 1; /*置数据线为输入方式*/
    for(BitCount = 0; BitCount < 8; BitCount++)
    {
        _nop_();           
        SCL = 0; /*置时钟线为低,准备接收数据位*/
        I2C_Delay();
        SCL = 1; /*置时钟线为高使数据线上数据有效*/
        _nop_();
        _nop_();

        RcvByte = RcvByte<<1;
        if(SDA == 1)
            RcvByte = RcvByte + 1; /*读数据位,接收的数据位放入retc中 */
        _nop_();
        _nop_();
    }

    SCL = 0;   
    _nop_();
    _nop_();

    return RcvByte;
}

/*******************************************************************
                    向无子地址器件发送字节数据函数               
函数原型: U8 I2C_WriteByte_NoRegister(U8 slaveAddr,U8 Data);
功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址slaveAddr。
      如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_WriteByte_NoRegister(U8 slaveAddr,U8 Data)
{
    I2C_Start(); /*启动总线*/

    I2C_SendByte(slaveAddr); /*发送器件地址*/
    if(AckFlag == 0)
        return 0;

    I2C_SendByte(Data); /*发送数据*/
    if(AckFlag == 0)
        return 0;

    I2C_Stop(); /*结束总线*/

    return 1;
}

/*******************************************************************
                    向有子地址器件发送多字节数据函数               
函数原型: U8 I2C_WriteBytes(U8 slaveAddr, U8 regAddr, U8 *pData, U8 size);
功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,
      从器件地址slaveAddr,子地址regAddr,发送内容是pData指向的内容,发送size个字节。
      如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_WriteBytes(U8 slaveAddr, U8 regAddr, U8 *pData, U8 size)
{
    U8 i;

    I2C_Start(); /*启动总线*/

    I2C_SendByte(slaveAddr); /*发送器件地址*/
    if(AckFlag == 0)
        return 0;

    I2C_SendByte(regAddr); /*发送器件子地址*/
    if(AckFlag == 0)
        return 0;

    for(i = 0; i < size; i++)
    {   
        I2C_SendByte(*pData); /*发送数据*/
        if(AckFlag == 0)
            return 0;
        pData++;
    }

    I2C_Stop(); /*结束总线*/

    return 1;
}

/*******************************************************************
                    向无子地址器件读字节数据函数               
函数原型: U8 I2C_ReadByte_NoRegister(U8 slaveAddr,U8 *pRcvData);
功能: 从启动总线到发送地址,读数据,结束总线的全过程,
      从器件地址slaveAddr,返回值在pRcvData。
      如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_ReadByte_NoRegister(U8 slaveAddr,U8 *pRcvData)
{
    I2C_Start(); /*启动总线*/

    I2C_SendByte(slaveAddr+1); /*发送器件地址*/
    if(AckFlag == 0)
        return 0;

    *pRcvData = I2C_RcvByte(); /*读取数据*/
    Ack_I2c(1); /*发送非就答位*/

    I2C_Stop(); /*结束总线*/

    return 1;
}

/*******************************************************************
                    向有子地址器件读取多字节数据函数               
函数原型: U8 I2C_ReadBytes(U8 slaveAddr, U8 regAddr, U8 *pRcvData, U8 size);
功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,
      从器件地址slaveAddr,子地址regAddr,读出的内容放入pRcvData指向的存储区,读size个字节。
      如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_ReadBytes(U8 slaveAddr, U8 regAddr, U8 *pRcvData, U8 size)
{
    U8 i;

    I2C_Start(); /*启动总线*/

    I2C_SendByte(slaveAddr); /*发送器件地址*/
    if(AckFlag == 0)
        return 0;

    I2C_SendByte(regAddr); /*发送器件子地址*/
    if(AckFlag == 0)
        return 0;

    I2C_Start(); /*启动总线*/

    I2C_SendByte(slaveAddr+1); /*发送器件地址*/
    if(AckFlag == 0)
        return 0;

    for(i = 0; i < size-1; i++)
    {
        *pRcvData = I2C_RcvByte(); /*读取数据*/
        Ack_I2c(0); /*发送就答位*/
        pRcvData++;
    }
    *pRcvData = I2C_RcvByte();
    Ack_I2c(1); /*发送非就答位*/

    I2C_Stop(); /*结束总线*/

    return 1;
}



沙发
langziwuliao| | 2017-10-25 15:41 | 只看该作者
这么长谁有耐心看,找对应的代理支持撒

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

1

帖子

0

粉丝