手撸IIC通信协议,ACK信号有问题。

2023-12-163839
AI 快速预览详细 收起
本文介绍了在调试IIC通信协议时遇到的ACK信号问题。通过自定义myWire类,详细展示了如何实现IIC通信并解决了寻址MPU6050寄存器时收不到ACK信号的问题。文章提供了具体的调试步骤和解决方案,帮助读者快速定位并解决问题。
问题是寻IIC地址没问题,也就是调用findDevice() 功能正常,但是寻MPU6050的寄存器时总是收不到ACK。
开始也没想着去寻全部的寄存器地址的,只是想给0x6B寄存器发一个0唤醒MPU6050读取温度数据,
但是发送寄存器地址后收不到ACK

以下是我的 myWire.h文件部分
#pragma once
typedef unsigned char uchar;
class myWire
{
    private:
    uchar SDA;
    uchar SCL;
    //信号部分
    //由主机发出的部分
    void signStart();//开始通信的信号
    void signStop();//停止通信的信号
    void sendAck(bool ack);//发送应答信号
    bool readAck();//接收应答信号

    public:
    myWire(uchar sda,uchar scl);//构造函数,设置SDA,SCL引脚
    void sendByte(uchar data);//发送一个字节数据
    uchar readByte();//接收数据
    void sendAddr(uchar addr,bool WR);//0为写,1为读
    void findDevice();//查找设备
    void findRegister();
    void sendDataToRegister(uchar addr,uchar reg,uchar data);//向IIC设备的寄存器写入数据
};
// void myWire::sendDataToRegister(uchar addr,uchar reg,uchar data)//向IIC设备的寄存器写入数据
// {
//     this->sendAddr(addr,0);
//     this->readAck();
//     this->sendByte(reg);
//     this->readAck();
//     this->sendByte(data);
//     this->readAck();
//     this->signStop();
// }
void myWire::sendDataToRegister(uchar addr,uchar reg,uchar data)//向IIC设备的寄存器写入数据
{
    this->sendAddr(addr,0);
    if(this->readAck()==0)
    {
        Serial.println("写入IIC地址成功!");
        this->sendByte(0x6B);
        if(this->readAck()==0)
        {
            Serial.println("写入数据成功!");
            this->sendByte(0);
            this->readAck();
            this->signStop();
        }
        else this->signStop();
    }
    else this->signStop();
}
void myWire::sendAddr(uchar addr,bool WR)//0为写,1为读
{
    this->signStart();
    this->sendByte((addr<<1)|WR);
}
bool myWire::readAck()//接收应答信号
{
    bool data=0;
    pinMode(this->SDA,INPUT);
    digitalWrite(this->SCL,LOW);//时钟线为低时对方开始准备数据
    delayMicroseconds(5);//等待对方准备好数据
    digitalWrite(this->SCL,HIGH);//准备读数据
    delayMicroseconds(5);//数据稳定了,可以读取了
    data=digitalRead(this->SDA);
    digitalWrite(this->SCL,LOW);
    pinMode(this->SDA,OUTPUT);
    return data;
}
void myWire::sendAck(bool ack)//发送应答信号
{
    digitalWrite(this->SCL,LOW);
    //稳定SDA
    if(ack) digitalWrite(this->SDA,HIGH);
    else digitalWrite(this->SDA,LOW);
    delayMicroseconds(5);//等待准备的数据稳定
    //跳变SCL 发送SDA数据
    digitalWrite(this->SCL,HIGH);
    delayMicroseconds(5);
    digitalWrite(this->SCL,LOW);//拉低SCL,为下次发送做准备
}
uchar myWire::readByte()//接收数据
{
    uchar data=0;
    pinMode(this->SDA,INPUT);
    digitalWrite(this->SCL,LOW);//时钟线为低时对方开始准备数据
    for(int i=0;i<8;i++)
    {
        delayMicroseconds(5);//等待对方准备好数据
        digitalWrite(this->SCL,HIGH);//准备读数据
        delayMicroseconds(5);//数据稳定了,可以读取了
        data<<=1;
        data|=digitalRead(this->SDA);
        digitalWrite(this->SCL,LOW);
    }
    pinMode(this->SDA,OUTPUT);
    return data;
}

void myWire::sendByte(uchar data)//发送从机地址和读写位,0:写 1:读
{
    digitalWrite(this->SCL,LOW);
    for(int i=0;i<8;i++)
    {
        //稳定SDA
        if(data&(1<<(7-i))) digitalWrite(this->SDA,HIGH);
        else digitalWrite(this->SDA,LOW);
        delayMicroseconds(5);//等待准备的数据稳定
        //跳变SCL 发送SDA数据
        digitalWrite(this->SCL,HIGH);
        delayMicroseconds(5);
        digitalWrite(this->SCL,LOW);//拉低SCL,为下次发送做准备
    }
}


void myWire::signStop()//停止通信的信号
{
    digitalWrite(this->SDA,LOW);
    digitalWrite(this->SCL,HIGH);
    delayMicroseconds(5);   
    digitalWrite(this->SDA,HIGH);//SDA上跳,形成停止信号
    delayMicroseconds(5);
    digitalWrite(this->SCL,LOW);//空闲时钟为低
}
void myWire::signStart()//开始通信的信号
{
    digitalWrite(this->SDA,HIGH);
    digitalWrite(this->SCL,HIGH);
    delayMicroseconds(5);
    digitalWrite(this->SDA,LOW);//SDA下跳,形成启动信号
    delayMicroseconds(5);
    digitalWrite(this->SCL,LOW);//准备下次通信
}
myWire::myWire(uchar sda,uchar scl)//构造函数,设置SDA,SCL引脚
{
    this->SDA=sda;
    this->SCL=scl;
    pinMode(this->SCL,OUTPUT);
    pinMode(this->SDA,OUTPUT);
}
void myWire::findDevice()//查找设备
{
    int count=0;
    for(uchar i=0;i<128;i++)
    {
        this->signStart();
        this->sendByte((i<<1)|0);
        bool ask=this->readAck();
        this->signStop();
        if(ask==0)
        {
            Serial.print("0x");
            Serial.println(i,HEX);
            count++;
        }
    }
    if(count==0) Serial.println("未发现设备");
}
void myWire::findRegister()
{
    this->sendAddr(0x68,0);
    if(this->readAck()==0)
    {
        int count=0;
        for(uchar i=1;i<255;i++)
        {
            this->sendByte(i);
            bool ask=this->readAck();
            this->signStop();
            if(ask==0)
            {
                Serial.print("0x");
                Serial.println(i,HEX);
                count++;
            }
        }
        if(count==0) Serial.println("未发现寄存器");
    }
}





创作许可协议

本项目采用 None(不开放任何权利,保留所有权利) 进行许可。

评论(0)
- 没有更多了 -