求IO模拟的SMBUS通信(类似于IIC)的程序呀

2019-08-14 19:46发布

原子哥  我这程序不够完美呀   连续发送命令  总是有读错和读不到的时候呀   【读电池BQ芯片数据的】  求原子哥给个完美的SMBUS模拟程序呀  ……
下面是我的程序
void Delay(void)   //延时子程序
{
//        unsigned char i;

//        _nop_();
//        i = 25;
//        while (--i);
//       

  _nop_();   //约0.000001秒  1微秒
  _nop_();
  _nop_();
  _nop_();
  _nop_();
        _nop_();   //约0.000001秒  1微秒
  _nop_();

  _nop_();
        _nop_();   //约0.000001秒  1微秒
       
       

}

void SMBUS_Init()
{
        SMBC=1;
        SMBD=1;
}

void Star(void)  //开始子程序      当SMBC为高电平时,SMBD上出现一个下降沿。该条件启动一次传输过程
{
  SMBD=1;
Delay();
  SMBC=1;
Delay();
  SMBD=0;
Delay();
  SMBC=0;
}


void Stop(void)  //停止子程序      当SMBC为高电平时,SMBD上出现一个上升沿。该条件停止一次传输过程
{
  SMBC=0;
Delay();
  SMBD=0;
Delay();
  SMBC=1;
  Delay();
  SMBD=1;
Delay();
}


u8 Ackw(void)  //ACKNOWLEDGE写子程序     SMBC为高时,采样到SMBD为低电平
{
  unsigned char a=0;
  SMBC=0;
Delay();
  SMBD=1;
Delay();
  SMBC=1;
Delay();
  while(SMBD)
  {
    a++;
        ack=0;
          /****
    if(a==250)     //   向串口发送EE,表示发送出错,未收到确认。利用串口助手可以看到
    {
      ADAPTER++;
          if(ADAPTER==20)
          {
        ERROR=0xEE;
                ADAPTER=0;
      }
      else
            ERROR=0;
          ack=1;
      SelectUART_or_485(&SM_Error,1);  //失败,则通过串口向PC发送一个字节0xEE
      break;
    }
          ****/
          if(a==250)     //   向串口发送EE,表示发送出错,未收到确认。利用串口助手可以看到
    {   
                Stop();
               
      SelectUART_or_485(&SM_Error,1);  //失败,则通过串口向PC发送一个字节0xEE
   return 1;
    }
       
  }
    SMBC=0;
        return 0;
}


void Ackr(void) //ACKNOWLEDGE读子程序     SMBC为高时,采样到SMBD为低电平
{
  SMBC=0;
Delay();
  SMBD=0;
Delay();
  SMBC=1;
Delay();
SMBC=0;
}

void Nack(void)  //NOT ACKNOWLEDGE子程序    SMBC为高电平时,采样到SMBD为高电平
{
  SMBC=0;
  Delay();
  SMBD=1;
Delay();
  SMBC=1;
Delay();
SMBC=0;
}

void Send(unsigned char b)  //发送子程序      将b按从最高位到最低位的顺序,逐位的发送给bq2040
{
  unsigned char i,x,y,z;
  z=0x80;
  for(i=1;i<9;i++)
  {
    x=b&z;  //  读最高位数据
    if(x==0)
      y=0;  //为 0就 y=0
    else
      y=1;   //否则 y=1
    SMBC=0;
   Delay();
       
    SMBD=y;  //把一个位数据送入SMBus数据线
    Delay();
       
    SMBC=1;
    Delay();
       
    z>>=1;     //把高位的1右移一位
       
        //SMBC=0;//每次读完或写完都把时钟端拉低
  }
}

unsigned char Receive(void)  //接收子程序     将bq2040中的数据逐位的读出
{
  unsigned char i,g=0x00;
  for(i=1;i<9;i++)
  {
    SMBC=0;
    Delay();
    SMBD=1;
   Delay();
    SMBC=1;
   Delay();
    g<<=1;   //g左移一位   
    if(SMBD)   //如果SMBD==1,g++
        { g++;

        }
  }
  
            Ackr();     //接收确认
     
       
   //SMBC=0;//每次读完或写完都把时钟端拉低
  return g;    //8次循环后g=0xFF
}
/****
u8 Read_Byte(unsigned char Command)   //
{
        u8 TempByte;
   Star();      //开始
   Send(BQ_AddrW);    //发送器件地址0x16    00010110
  Ackw();     //发送确认


  Send(Command);  //发送读剩余电量指令
  Ackw();     //发送确认


  Star();
  Send(BQ_AddrR);
  Ackw();    //发送确认
  

  TempByte=Receive();  //接收剩余电量低8位数据    调用Receive();返回值就是 0xFF
  Ackr();    //接收确认
       
  Nack();    //非确认
  Stop();    //结束
  return TempByte;
}
****/
void Read_Word(unsigned char Command)   //
{
   Star();      //开始
   Send(BQ_AddrW);    //发送器件地址0x16    00010110
  Ackw();     //发送确认


  Send(Command);  //发送读剩余电量指令
  Ackw();     //发送确认

  Star();
  Send(BQ_AddrR);
  Ackw();    //发送确认
  

  ReceiveData_L=Receive();  //接收剩余电量低8位数据    调用Receive();返回值就是 0xFF
  Ackr();    //接收确认
       
  ReceiveData_H=Receive();  //接收剩余电量高8位数据    调用Receive();返回值就是 0xFF
Ackr();
  Nack();    //非确认
  Stop();    //结束
}
/****
void Read_Block(u8 Command,u8 *pBuffer)
{
          u8 tempReadCount=0;
  Star();      //开始
   Send(BQ_AddrW);    //发送器件地址0x16    00010110
  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;

  Send(Command);  //发送要读取的块指令

  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;    //遇到return函数就返回

       
  Star();
  Send(BQ_AddrR);
  Ackw();    //发送确认
  if(ack)    //未确认则重新发送
    return;
       
        SMB_ReadCount=Receive();//首先,接收从机向主机发送的读取字节数量
        Ackr();    //接收确认
     
     tempReadCount=SMB_ReadCount;
        while(tempReadCount)
        {
               
                *pBuffer++=Receive();       
                Ackr();
                tempReadCount--;                               
        }
  Nack();    //非确认
  Stop();    //结束
}
****/
//读块
void Read_Block(u8 Command,u8 *pBuffer)
{

          u8 tempReadCount=0;
       
         u8 tempReceiveByteData=0;
        //u8 xdata ReceiveArray[32];
  Star();      //开始
   Send(BQ_AddrW);    //发送器件地址0x16    00010110
  Ackw();     //发送确认


  Send(Command);  //发送要读取的块指令

  Ackw();     //发送确认
       
  Star();
  Send(BQ_AddrR);
  Ackw();    //发送确认

       



    tempReadCount=Receive();//首先,接收从机向主机发送的读取字节数量   
       
        if(tempReadCount>0x20)  tempReadCount=0; //大于16进制20 即十进制32个 元素     就清为零
               
        SMB_ReadCount=tempReadCount;   //接收确认了,再赋值
        while(tempReadCount)
        {
               
                //*pBuffer++=Read_Byte(Command++);         
               
                tempReceiveByteData=Receive();
                //Ackr();       
           *pBuffer++=tempReceiveByteData;
               
                tempReadCount--;                       
                       
        }

       
//        while(tempReadCount)
//        {
//                                         
//                tempReceiveByteArray[i]=Receive();
//                        Ackr();
//                i++;                       
//                       
//        }
//        pBuffer=(u8 *)&tempReceiveByteArray[0];
    Nack();    //非确认
  Stop();    //结束

}


/****
void Write_Byte(unsigned char Command,unsigned char WriteByte)   
{
         Star();      //开始
   Send(BQ_AddrW);    //发送器件地址0x16    00010110
  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;

  Send(Command);  //发送读剩余电量指令
  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;    //遇到return函数就返回

   Send(WriteByte);  //发送读剩余电量指令
  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;    //遇到return函数就返回

  Stop();    //结束
}
****/

void Write_Word(u8 Command,u16 WriteWord)
{
       
        unsigned char WrLowByte,WrHighByte;
                                 Star();      //开始
                                 Send(BQ_AddrW);    //发送器件地址0x16    00010110
                                Ackw();     //发送确认
                               

                        Send(Command);  //发送要读取的块指令
                        Ackw();     //发送确认       
                       
               
                        WrLowByte=WriteWord&0xff;   //取要写字的低字节
                        WrHighByte=(WriteWord&0xff00)>>8;  //取要写字的高字节

                                 Send(WrLowByte);  
                                Ackw();     //发送确认
                               
                                Send(WrHighByte);  
                                Ackw();     //发送确认
                               
                       
                        Stop();    //结束
                               
       
}









void Write_Block(unsigned char Command,unsigned char WriteNum,unsigned char *p_WrBlock)
{
           unsigned char i=0;
                  Star();      //开始
                         Send(BQ_AddrW);    //发送器件地址0x16    00010110
                        Ackw();     //发送确认
                       

                        Send(Command);  //发送要读取的块指令
                        Ackw();     //发送确认       
                       
                       
                        Send(WriteNum);  //发送要写入的字节数量
                        Ackw();     //发送确认       
                       
                       
                        while(WriteNum--)
                        {
                                Send(p_WrBlock[i]);  //从第4个字节开始发送数据 WriteNum个
                                        Ackw();     //发送确认       
                                       
                                        i++;
                       
                        }
                       
                Stop();    //结束
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。